-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Expand file tree
/
Copy pathpassword-requirements.tsx
More file actions
85 lines (81 loc) · 2.31 KB
/
Copy pathpassword-requirements.tsx
File metadata and controls
85 lines (81 loc) · 2.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import { CircleCheck } from "@dub/ui";
import { cn } from "@dub/utils";
import { memo } from "react";
import { useFormContext, useWatch } from "react-hook-form";
const REQUIREMENTS: {
name: string;
mobileName?: string;
check: (password: string) => boolean;
}[] = [
{
name: "Number",
check: (p) => /\d/.test(p),
},
{
name: "Uppercase letter",
mobileName: "Uppercase",
check: (p) => /[A-Z]/.test(p),
},
{
name: "Lowercase letter",
mobileName: "Lowercase",
check: (p) => /[a-z]/.test(p),
},
{
name: "8 chars",
check: (p) => p.length >= 8,
},
];
/**
* Component to display the password requirements and whether they are each met for a password field.
*
* Note: This component must be used within a FormProvider context.
*/
export const PasswordRequirements = memo(function PasswordRequirements({
field = "password",
className,
}: {
field?: string;
className?: string;
}) {
const {
formState: { errors },
} = useFormContext();
const password = useWatch({ name: field });
return (
<ul className={cn("mt-2 flex flex-wrap items-center gap-3", className)}>
{REQUIREMENTS.map(({ name, mobileName, check }) => {
const checked = password?.length && check(password);
return (
<li
key={name}
className={cn(
"flex items-center gap-1 text-xs text-neutral-400 transition-colors",
checked ? "text-green-600" : errors[field] && "text-red-600",
)}
>
<CircleCheck
variant="fill"
className={cn(
"size-2.5 transition-opacity",
checked
? "animate-scale-in [--from-scale:1] [--to-scale:1.2] [animation-direction:alternate] [animation-duration:150ms] [animation-iteration-count:2] [animation-timing-function:ease-in-out]"
: errors[field]
? "text-red-600"
: "text-neutral-200",
)}
/>
{mobileName ? (
<>
<span className="max-[420px]:hidden">{name}</span>
<span className="hidden max-[420px]:inline">{mobileName}</span>
</>
) : (
<span>{name}</span>
)}
</li>
);
})}
</ul>
);
});