-
Notifications
You must be signed in to change notification settings - Fork 0
/
PasswordStrengthField.tsx
75 lines (64 loc) · 1.84 KB
/
PasswordStrengthField.tsx
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
import clsx from 'clsx'
import { useEffect, useState } from 'react'
import type { ComponentPropsWithoutRef as ComponentProps } from 'react'
import { PasswordField, useWatch } from '@redwoodjs/forms'
import type { RegisterOptions } from '@redwoodjs/forms'
import { zxcvbn } from '@zxcvbn-ts/core'
import type { ZxcvbnResult } from '@zxcvbn-ts/core'
import { loadZxcvbn } from 'src/lib/zxcvbn'
import './PasswordStrengthField.css'
interface ValidationOptions extends RegisterOptions {
strength: {
message: string
value: number
}
}
interface PasswordStrengthFieldProps
extends ComponentProps<typeof PasswordField> {
validation: ValidationOptions
}
export default ({
name,
validation: { strength: validateStrength, ...validation },
...props
}: PasswordStrengthFieldProps) => {
const password = useWatch({ name })
const [strength, setStrength] = useState<ZxcvbnResult>()
useEffect(() => {
const _ = async () => {
await loadZxcvbn()
}
_()
}, [])
useEffect(() => {
const getStrength = async () => {
const res = await zxcvbn(password)
setStrength(res)
}
if (typeof password === 'string') {
getStrength()
}
}, [password, setStrength])
return (
<>
<PasswordField
name={name}
validation={{
validate: () =>
strength?.score >= validateStrength.value ||
validateStrength.message,
...validation,
}}
{...props}
/>
<div
className={clsx('strength-meter', `strength-score-${strength?.score}`)}
>
<span className={clsx(strength?.score > 0 && 'active')} />
<span className={clsx(strength?.score > 1 && 'active')} />
<span className={clsx(strength?.score > 2 && 'active')} />
<span className={clsx(strength?.score > 3 && 'active')} />
</div>
</>
)
}