Skip to content

Commit b317ec1

Browse files
committed
client(NewBadge.tsx, Input.tsx): add refs and reportValidity()
1 parent f16cf99 commit b317ec1

File tree

4 files changed

+68
-68
lines changed

4 files changed

+68
-68
lines changed

client/src/components/form/PageOne.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const PageOne = () => {
1010
>
1111
<img
1212
width="420px"
13-
src="https://github-readme-tech-stack.vercel.app/api/cards?title=Tech%20Stack&align=center&titleAlign=center&lineCount=2&theme=0l1v3rr&line2=react,react,2d79c7;tailwindcss,tailwind,38bdf8;typescript,typescript,2d79c7;&line1=laravel,laravel,ff2d20;go,golang,00add8;node.js,node.js,23b45d;&width=420&fontSize=20"
13+
src="https://github-readme-tech-stack.vercel.app/api/cards?title=Tech%20Stack&align=center&titleAlign=center&fontSize=20&lineCount=2&theme=0l1v3rr&line1=laravel,laravel,auto;go,golang,00add8;docker,docker,auto;&line2=react,react,2d79c7;tailwindcss,tailwind,38bdf8;typescript,typescript,2d79c7;&width=420"
1414
alt="Tech Stack"
1515
/>
1616

client/src/components/form/PageTwo.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const PageTwo = () => {
1515
const { card, setCard } = useMultistepContext();
1616

1717
return (
18-
<FormWrapper title="Customizing the theme">
18+
<FormWrapper title="Theme">
1919
<P>
2020
First, please select the theme you would like to use. We have tons of
2121
ready-made themes you can use. The themes are available{" "}

client/src/components/lines/NewBadge.tsx

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Flex from "../layout/Flex";
22
import InputWrapper from "../ui/InputWrapper";
33
import Input from "../ui/Input";
4-
import { useState } from "react";
4+
import { useRef } from "react";
55
import { Badge } from "../../types";
66
import Button from "../ui/Button";
77
import { GoPlus } from "react-icons/go";
@@ -11,36 +11,22 @@ type Props = {
1111
};
1212

1313
const NewBadge = ({ addBadge }: Props) => {
14-
const [icon, setIcon] = useState<string>("");
15-
const [label, setLabel] = useState<string>("");
16-
const [color, setColor] = useState<string>("");
14+
const iconRef = useRef<HTMLInputElement | null>(null);
15+
const labelRef = useRef<HTMLInputElement | null>(null);
16+
const colorRef = useRef<HTMLInputElement | null>(null);
1717

1818
return (
1919
<Flex className="items-start">
2020
<InputWrapper description="The name of the icon">
21-
<Input
22-
placeholder="react"
23-
pattern="^[a-zA-Z]{3,32}$"
24-
value={icon}
25-
onChange={(e) => setIcon(e.target.value)}
26-
/>
21+
<Input ref={iconRef} placeholder="react" pattern="^[a-zA-Z]{3,32}$" />
2722
</InputWrapper>
2823

2924
<InputWrapper description="The label shown on the badge">
30-
<Input
31-
placeholder="react"
32-
pattern="^[a-zA-Z]{3,32}$"
33-
value={label}
34-
onChange={(e) => setLabel(e.target.value)}
35-
/>
25+
<Input ref={labelRef} placeholder="react" pattern="^[a-zA-Z]{3,32}$" />
3626
</InputWrapper>
3727

3828
<InputWrapper description="The color of the icon">
39-
<Input
40-
placeholder="#5ed3f3"
41-
value={color}
42-
onChange={(e) => setColor(e.target.value)}
43-
/>
29+
<Input ref={colorRef} placeholder="#5ed3f3" />
4430
</InputWrapper>
4531

4632
<Button
@@ -50,10 +36,28 @@ const NewBadge = ({ addBadge }: Props) => {
5036
size="small"
5137
className="h-[30.67px]"
5238
onClick={() => {
53-
addBadge({ color, icon, label });
54-
setIcon("");
55-
setLabel("");
56-
setColor("");
39+
if (!colorRef.current || !iconRef.current || !labelRef.current) {
40+
return;
41+
}
42+
43+
// if the refs are invalid
44+
if (
45+
colorRef.current.reportValidity() ||
46+
iconRef.current.reportValidity() ||
47+
labelRef.current.reportValidity()
48+
) {
49+
return;
50+
}
51+
52+
addBadge({
53+
color: colorRef.current.value,
54+
icon: iconRef.current.value,
55+
label: labelRef.current.value,
56+
});
57+
58+
colorRef.current.value = "";
59+
iconRef.current.value = "";
60+
labelRef.current.value = "";
5761
}}
5862
/>
5963
</Flex>

client/src/components/ui/Input.tsx

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { FC, InputHTMLAttributes, useCallback, useState } from "react";
1+
import { InputHTMLAttributes, forwardRef, useCallback, useState } from "react";
22
import { VariantProps, cva } from "class-variance-authority";
33
import { cn } from "./utils";
44

@@ -24,49 +24,45 @@ interface InputProps
2424
label?: string;
2525
}
2626

27-
const Input: FC<InputProps> = ({
28-
className,
29-
variant,
30-
label,
31-
type = "text",
32-
onChange,
33-
...props
34-
}) => {
35-
const [actualVariant, setActualVariant] =
36-
useState<InputProps["variant"]>(variant);
27+
const Input = forwardRef<HTMLInputElement, InputProps>(
28+
({ className, variant, label, type = "text", onChange, ...props }, ref) => {
29+
const [actualVariant, setActualVariant] =
30+
useState<InputProps["variant"]>(variant);
3731

38-
const checkValidity = useCallback(
39-
(e: React.ChangeEvent<HTMLInputElement>) => {
40-
// if the input is empty, don't indicate error
41-
if (e.target.value.trim() === "") {
42-
setActualVariant(variant);
43-
return;
44-
}
32+
const checkValidity = useCallback(
33+
(e: React.ChangeEvent<HTMLInputElement>) => {
34+
// if the input is empty, don't indicate error
35+
if (e.target.value.trim() === "") {
36+
setActualVariant(variant);
37+
return;
38+
}
4539

46-
// if the input passes the validity
47-
if (e.target.checkValidity()) {
48-
setActualVariant(variant);
49-
return;
50-
}
40+
// if the input passes the validity
41+
if (e.target.checkValidity()) {
42+
setActualVariant(variant);
43+
return;
44+
}
5145

52-
setActualVariant("danger");
53-
},
54-
[]
55-
);
46+
setActualVariant("danger");
47+
},
48+
[]
49+
);
5650

57-
return (
58-
<input
59-
aria-label={label}
60-
type={type}
61-
autoComplete="off"
62-
onChange={(e) => {
63-
onChange?.(e);
64-
checkValidity(e);
65-
}}
66-
className={cn(inputVariants({ variant: actualVariant }), className)}
67-
{...props}
68-
/>
69-
);
70-
};
51+
return (
52+
<input
53+
aria-label={label}
54+
ref={ref}
55+
type={type}
56+
autoComplete="off"
57+
onChange={(e) => {
58+
onChange?.(e);
59+
checkValidity(e);
60+
}}
61+
className={cn(inputVariants({ variant: actualVariant }), className)}
62+
{...props}
63+
/>
64+
);
65+
}
66+
);
7167

7268
export default Input;

0 commit comments

Comments
 (0)