Как сделать отображение валидации раздельной react hook form?
Суть: хочу сделать так, что бы валидация поля выглядила так как на скрине, тоесть есть форма, которая сделана с помощью хука useForm
из react hook form, при вводе текса в строку, снизу строки должны отображатьcя 3 строки (как на скрине) и эти строки должны менять цвет текса и галочку в зависимости от результата валидации. Как можно сделать такое отображение валидации используя react hook form? Или всё же нужно написать функцию, которая принимает строку и проверяет для каждого вида валидации условия и возвращает true или false?
useView.ts
import { useForm, UseFormReturn } from 'react-hook-form'
import { emailFormScheme, EmailFormScheme } from '../constants/emailFormScheme'
import { useState } from 'react'
import { passwordFormScheme, PasswordFormScheme } from '../constants/passwordFormScheme'
import { zodResolver } from '@hookform/resolvers/zod';
import { useNavigate } from 'react-router-dom';
export type stages = 'email' | 'password' | 'about'
export const useView = () => {
const navigate = useNavigate()
const [stage, setStage] = useState<stages>('email')
const signUpForm = useForm<EmailFormScheme | PasswordFormScheme>({
mode: 'onBlur',
defaultValues: {
email: '',
password: ''
},
resolver: zodResolver(stage === 'email' ? emailFormScheme : stage === 'password' ? passwordFormScheme : emailFormScheme)
})
const onSubmit = signUpForm.handleSubmit(value => {
if(stage === 'email' && 'email' in value) {
navigate('step=1')
setStage('password')
return
}
})
const back = () => {
switch(stage) {
case 'password': {
setStage('email')
navigate(-1)
break
}
}
}
return {
form: signUpForm,
stage,
functions: { onSubmit, back }
}
}
passwordFormScheme.ts
import { z } from "zod";
export const passwordFormScheme = z.object({
password: z
.string()
.min(10)
})
export type PasswordFormScheme = z.infer<typeof passwordFormScheme>
import { Box, Button, Fade, IconButton, InputAdornment, List, ListItem, ListItemAvatar, ListItemButton, ListItemIcon, ListItemText, MenuItem, MenuList, OutlinedInput, Stack, TextField, Typography } from '@mui/material'
import React from 'react'
import { TextFieldWithLabel } from '../../components/input/textFieldWithLabel'
import Visibility from '@mui/icons-material/Visibility';
import VisibilityOff from '@mui/icons-material/VisibilityOff';
import { Controller } from 'react-hook-form'
import { ContextType } from '../../signUp'
import { useOutletContext } from 'react-router-dom'
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
import PanoramaFishEyeIcon from '@mui/icons-material/PanoramaFishEye';
import styles from './passwordStage.module.scss'
export const PasswordStage = () => {
const { form, functions, stage } = useOutletContext<ContextType>()
const [showPassword, setShowPassword] = React.useState(false);
const handleClickShowPassword = () => setShowPassword((show) => !show);
const handleMouseDownPassword = (event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
};
return (
<Box
width='324px'
mt={5}
>
<Fade in timeout={400} >
<Box>
<Controller
name='password'
control={form.control}
render={({ field, fieldState }) => (
<Box>
<TextFieldWithLabel
size='small'
inputLabel='Password'
type={showPassword ? 'text' : 'password'}
value={field.value}
onChange={(e) => field.onChange(e.target.value)}
error={!!fieldState.error}
endAdornment={
<InputAdornment position="end">
<IconButton
sx={{ color: '#a0a0a0' }}
aria-label="toggle password visibility"
onClick={handleClickShowPassword}
onMouseDown={handleMouseDownPassword}
edge="end"
>
{showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
}
/>
<Box mt={1}>
<Typography variant='body2' color='white' fontWeight='600'>
The password must contain at least:
</Typography>
<Stack spacing={1} mt={1} fontWeight='700' color='white'>
<Stack direction='row' spacing={0.7} alignItems='baseline'>
<PanoramaFishEyeIcon sx={{ color: '#a0a0a0', fontSize: '13px' }} />
<Typography sx={{ fontSize: '0.8125rem' }}>1 letter</Typography>
</Stack>
<Stack direction='row' spacing={0.7} alignItems='baseline'>
<PanoramaFishEyeIcon sx={{ color: '#a0a0a0', fontSize: '13px' }} />
<Typography sx={{ fontSize: '0.8125rem' }}>1 number or 1 special character (for example: # ? ! &)</Typography>
</Stack>
<Stack direction='row' spacing={0.7} alignItems='baseline'>
<PanoramaFishEyeIcon sx={{ color: '#a0a0a0', fontSize: '13px' }} />
<Typography sx={{ fontSize: '0.8125rem' }}>10 symbols</Typography>
</Stack>
</Stack>
</Box>
</Box>
)}
/>
</Box>
</Fade>
<Button fullWidth className={styles.submitButton}>
Further
</Button>
</Box>
)
}