Skip to content
This repository has been archived by the owner on Jul 6, 2024. It is now read-only.

Commit

Permalink
WIP: refactor TextField with HOC component
Browse files Browse the repository at this point in the history
  • Loading branch information
peterleiva committed Mar 23, 2022
1 parent 1a93aa0 commit 676d06a
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 69 deletions.
13 changes: 13 additions & 0 deletions src/components/forms/PasswordField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Field, { type BaseFieldProps } from "./Field";
import PasswordInput from "./PasswordInput";
import { useFormContext } from "react-hook-form";

type PasswordFieldProps = BaseFieldProps<ElementProps<typeof PasswordInput>>;

// export default function PasswordField({ name }: PasswordFieldProps) {
// const {
// formState: { errors },
// } = useFormContext();

// return <div>PasswordField</div>;
// }
18 changes: 12 additions & 6 deletions src/components/forms/PasswordInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import {
} from "react-icons/ri";
import { IconButton } from "components/Button";

type PasswordInputProps = Omit<
React.ComponentProps<typeof TextInput>,
"startDecoration" | "endDecoration"
> & {
type PasswordInputProps = ElementProps<typeof TextInput> & {
position?: "right" | "left";
show?: boolean;
hideAdornment?: boolean;
Expand All @@ -28,8 +25,17 @@ export default function PasswordInput({
);

const decorationProps = {
startDecoration: position === "left" ? adornment : null,
endDecoration: position === "right" ? adornment : null,
startDecoration: (
<>
{props?.startDecoration}
{position === "left" ? adornment : null}
</>
),
endDecoration: (
<>
{props?.endDecoration} {position === "right" ? adornment : null}
</>
),
};

return (
Expand Down
183 changes: 125 additions & 58 deletions src/components/forms/TextField.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { ComponentProps } from "react";
import React, { ComponentProps } from "react";
import { type RegisterOptions, useFormContext } from "react-hook-form";
import TextInput from "./TextInput";
import LengthAdornment from "./LengthAdornment";
import BaseField, { type BaseFieldProps } from "./Field";
import clsx from "clsx";
import PasswordInput from "./PasswordInput";

type TextFieldProps = BaseFieldProps<
Omit<ComponentProps<typeof TextInput>, "register"> & {
Expand All @@ -12,66 +13,132 @@ type TextFieldProps = BaseFieldProps<
}
>;

export default function TextField({
name,
label,
registerOptions = {},
required,
max,
min,
maxLength,
minLength,
showLength,
value,
...inputProps
}: TextFieldProps) {
const { disabled, onBlur, onChange } = inputProps;
function WithTextField<
T extends React.ComponentType<ElementProps<typeof TextInput>>
>(Input: T = TextInput) {
return function TextField({
name,
label,
required,
max,
maxLength,
min,
minLength,
value,
registerOptions,
showLength,
...inputProps
}: TextFieldProps) {
const { disabled, onBlur, onChange } = inputProps;
const {
formState: { errors },
register,
watch,
} = useFormContext();

const {
formState: { errors },
register,
watch,
} = useFormContext();

return (
<BaseField
label={label}
required={required}
name={name}
errors={errors}
renderInput={
<TextInput
id={name}
error={errors[name]}
register={register(name, {
required,
max,
maxLength,
min,
minLength,
disabled,
onBlur,
onChange,
value,
...registerOptions,
})}
endDecoration={
<>
<LengthField
show={showLength}
maxLength={maxLength}
value={watch(name)}
/>
{inputProps?.endDecoration}
</>
}
{...inputProps}
/>
}
/>
);
return (
<BaseField
label={label}
required={required}
name={name}
errors={errors}
renderInput={
<Input
id={name}
error={errors[name]}
register={register(name, {
required,
max,
maxLength,
min,
minLength,
disabled,
onBlur,
onChange,
value,
...registerOptions,
})}
endDecoration={
<>
<LengthField
show={showLength}
maxLength={maxLength}
value={watch(name)}
/>
{inputProps?.endDecoration}
</>
}
{...inputProps}
/>
}
/>
);
};
}

export const TextField = WithTextField();
export const PasswordField = WithTextField(PasswordInput);

// export default function TextField({
// name,
// label,
// registerOptions = {},
// required,
// max,
// min,
// maxLength,
// minLength,
// showLength,
// value,
// ...inputProps
// }: TextFieldProps) {
// const { disabled, onBlur, onChange } = inputProps;

// const {
// formState: { errors },
// register,
// watch,
// } = useFormContext();

// return (
// <BaseField
// label={label}
// required={required}
// name={name}
// errors={errors}
// renderInput={
// <TextInput
// id={name}
// error={errors[name]}
// register={register(name, {
// required,
// max,
// maxLength,
// min,
// minLength,
// disabled,
// onBlur,
// onChange,
// value,
// ...registerOptions,
// })}
// endDecoration={
// <>
// <LengthField
// show={showLength}
// maxLength={maxLength}
// value={watch(name)}
// />
// {inputProps?.endDecoration}
// </>
// }
// {...inputProps}
// />
// }
// />
// );
// }

type LengthFieldProps = {
value?: string;
maxLength?: number;
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/__stories__/FormField.stories.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Meta } from "@storybook/addon-docs";
import Form from "../Form";
import TextField from "../TextField";
import { TextField } from "../TextField";
import Button from "components/Button";

<Meta title="docs/forms/FormField" />
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/__stories__/TextField.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ComponentStory, type ComponentMeta } from "@storybook/react";
import { screen, userEvent } from "@storybook/testing-library";
import TextField from "../TextField";
import { TextField } from "../TextField";
import Form from "../Form";

export default {
Expand Down
2 changes: 1 addition & 1 deletion src/components/forms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export { default as TextInput } from "./TextInput";
export { default as PasswordInput, PasswordAdornment } from "./PasswordInput";
export { default as LengthAdornment } from "./LengthAdornment";
export { default as Label } from "./Label";
export { default as TextField } from "./TextField";
export { TextField, PasswordField } from "./TextField";
4 changes: 2 additions & 2 deletions src/pages/signup.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type NextPage } from "next";
import { Form, TextField } from "components/forms";
import { Form, TextField, PasswordField } from "components/forms";
import Button from "components/Button";
import { useToast } from "components/toast";
import { BsArrowRight as RightIcon } from "react-icons/bs";
Expand Down Expand Up @@ -27,7 +27,7 @@ const SignUp: NextPage = () => {
<h1>Sign Up</h1>
<Form<FormData> onSubmit={submission} className="flex flex-col gap-4">
<TextField name="email" label="Email" required />
<TextField
<PasswordField
name="password"
label="Password"
autoComplete="current-password"
Expand Down

0 comments on commit 676d06a

Please sign in to comment.