password_input.tsx (2003B)
1 import { useComputed, useSignal } from "@preact/signals"; 2 3 const MIN_LENGTH = 8; 4 5 export default function PasswordInput( 6 props: { error: boolean; confirm: boolean }, 7 ) { 8 const visible = useSignal(false); 9 const error = useSignal(props.error); 10 const passwordValue = useSignal(""); 11 const confirmValue = useSignal(""); 12 const type = useComputed(() => visible.value ? "text" : "password"); 13 14 const passwordInvalid = useComputed(() => { 15 if (error.value) return "true"; 16 if (passwordValue.value === "" || !props.confirm) return undefined; 17 return passwordValue.value.length < MIN_LENGTH ? "true" : "false"; 18 }); 19 20 const confirmInvalid = useComputed(() => { 21 if (error.value) return "true"; 22 if (confirmValue.value === "") return undefined; 23 return confirmValue.value !== passwordValue.value ? "true" : "false"; 24 }); 25 26 return ( 27 <fieldset> 28 <label> 29 Password: 30 <input 31 type={type} 32 name="password" 33 value={passwordValue} 34 aria-invalid={passwordInvalid} 35 onInput={(e) => { 36 error.value = false; 37 passwordValue.value = e.currentTarget.value; 38 }} 39 /> 40 {props.confirm && ( 41 <small>Enter password with {MIN_LENGTH} characters minimum</small> 42 )} 43 </label> 44 {props.confirm && ( 45 <label> 46 Confirm password: 47 <input 48 type={type} 49 name="passwordConfirmation" 50 value={confirmValue} 51 aria-invalid={confirmInvalid} 52 onInput={(e) => { 53 error.value = false; 54 confirmValue.value = e.currentTarget.value; 55 }} 56 /> 57 <small>Re-enter your password to check for errors</small> 58 </label> 59 )} 60 <label> 61 <input 62 type="checkbox" 63 checked={visible} 64 onInput={(e) => visible.value = e.currentTarget.checked} 65 /> 66 Show password 67 </label> 68 </fieldset> 69 ); 70 }