diff --git a/striker-ui/components/OutlinedInput/OutlinedInput.tsx b/striker-ui/components/OutlinedInput/OutlinedInput.tsx index cff4a3cb..301bdb4a 100644 --- a/striker-ui/components/OutlinedInput/OutlinedInput.tsx +++ b/striker-ui/components/OutlinedInput/OutlinedInput.tsx @@ -1,48 +1,124 @@ -import { FC } from 'react'; import { + Visibility as MUIVisibilityIcon, + VisibilityOff as MUIVisibilityOffIcon, +} from '@mui/icons-material'; +import { + IconButton as MUIIconButton, OutlinedInput as MUIOutlinedInput, outlinedInputClasses as muiOutlinedInputClasses, OutlinedInputProps as MUIOutlinedInputProps, } from '@mui/material'; +import { cloneElement, FC, ReactElement, useMemo, useState } from 'react'; import { GREY, TEXT, UNSELECTED } from '../../lib/consts/DEFAULT_THEME'; type OutlinedInputProps = MUIOutlinedInputProps; +const INPUT_TYPES: Record< + Exclude, + string +> = { + password: 'password', + text: 'text', +}; + const OutlinedInput: FC = (outlinedInputProps) => { - const { label, sx, ...outlinedInputRestProps } = outlinedInputProps; - const combinedSx = { - color: GREY, + const { + endAdornment, + label, + sx, + inputProps: { type: baseType, ...inputRestProps } = {}, + ...outlinedInputRestProps + } = outlinedInputProps; - [`& .${muiOutlinedInputClasses.notchedOutline}`]: { - borderColor: UNSELECTED, - }, + const [type, setType] = useState(baseType); + + const additionalEndAdornment = useMemo( + () => ( + <> + {baseType === INPUT_TYPES.password && ( + { + setType((previous) => + previous === INPUT_TYPES.password + ? INPUT_TYPES.text + : INPUT_TYPES.password, + ); + }} + > + {type === INPUT_TYPES.password ? ( + + ) : ( + + )} + + )} + + ), + [baseType, type], + ); + const combinedSx = useMemo( + () => ({ + color: GREY, - '&:hover': { [`& .${muiOutlinedInputClasses.notchedOutline}`]: { - borderColor: GREY, + borderColor: UNSELECTED, + }, + + '&:hover': { + [`& .${muiOutlinedInputClasses.notchedOutline}`]: { + borderColor: GREY, + }, }, - }, - [`&.${muiOutlinedInputClasses.focused}`]: { - color: TEXT, + [`&.${muiOutlinedInputClasses.focused}`]: { + color: TEXT, - [`& .${muiOutlinedInputClasses.notchedOutline}`]: { - borderColor: GREY, + [`& .${muiOutlinedInputClasses.notchedOutline}`]: { + borderColor: GREY, - '& legend': { - paddingRight: label ? '1.2em' : 0, + '& legend': { + paddingRight: label ? '1.2em' : 0, + }, }, }, - }, - ...sx, - }; + ...sx, + }), + [label, sx], + ); + const combinedEndAdornment = useMemo(() => { + let result; + + if (typeof endAdornment === 'object') { + const casted = endAdornment as ReactElement; + const { + props: { children: castedChildren = [], ...castedRestProps }, + } = casted; + + return cloneElement(casted, { + ...castedRestProps, + children: ( + <> + {additionalEndAdornment} + {castedChildren} + + ), + }); + } + + return result; + }, [additionalEndAdornment, endAdornment]); return ( = ({ display: 'flex', flexDirection: 'row', - '& > :not(:first-child)': { + [`& > .${muiIconButtonClasses.root}`]: { + color: GREY, + }, + + [`& > :not(:first-child, .${muiIconButtonClasses.root})`]: { marginLeft: '.3em', }, }} > {endAdornment} {isShowHelpButton && ( - + )}