MaskedInput.tsx 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. import type { ChangeEvent } from 'react';
  2. import { type JSX, useState } from 'react';
  3. import type { UseFormRegister } from 'react-hook-form';
  4. import styles from './MaskedInput.module.scss';
  5. type Props = {
  6. name?: string;
  7. readOnly: boolean;
  8. value?: string;
  9. onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
  10. tabIndex?: number | undefined;
  11. register?: UseFormRegister<any>;
  12. fieldName?: string;
  13. };
  14. export default function MaskedInput(props: Props): JSX.Element {
  15. const [passwordShown, setPasswordShown] = useState(false);
  16. const togglePassword = () => {
  17. setPasswordShown(!passwordShown);
  18. };
  19. const { name, readOnly, value, onChange, tabIndex, register, fieldName } =
  20. props;
  21. // Use register if provided, otherwise use value/onChange
  22. const inputProps =
  23. register && fieldName
  24. ? register(fieldName)
  25. : {
  26. name,
  27. value,
  28. onChange,
  29. };
  30. return (
  31. <div className={styles.MaskedInput}>
  32. <input
  33. className="form-control"
  34. type={passwordShown ? 'text' : 'password'}
  35. readOnly={readOnly}
  36. tabIndex={tabIndex}
  37. {...inputProps}
  38. />
  39. <button
  40. type="button"
  41. onClick={togglePassword}
  42. className={`${styles.PasswordReveal} border-0 bg-transparent p-0`}
  43. aria-pressed={passwordShown}
  44. aria-label="Toggle password visibility"
  45. >
  46. {passwordShown ? (
  47. <span className="material-symbols-outlined">visibility</span>
  48. ) : (
  49. <span className="material-symbols-outlined">visibility_off</span>
  50. )}
  51. </button>
  52. </div>
  53. );
  54. }