Skip to content

Commit

Permalink
refactor: add variant outlined to TextInput component
Browse files Browse the repository at this point in the history
  • Loading branch information
diegogasparbuilders committed Jul 24, 2024
1 parent cd63302 commit 7149ddb
Show file tree
Hide file tree
Showing 3 changed files with 426 additions and 143 deletions.
298 changes: 178 additions & 120 deletions src/components/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,78 +4,57 @@ import {
FocusEvent,
InputHTMLAttributes,
MouseEvent,
Ref,
RefObject,
useRef,
useState,
} from 'react';
import { IMaskMixin, ReactElementProps } from 'react-imask';
import Icons from '../Icons';
import {
Fieldset,
IconWrapperLeft,
IconWrapperRight,
Input,
InputWrapper,
Label,
Message,
PlaceholderLabel,
StyledIMaskInput,
Wrapper,
} from './styles';

type IconsType = keyof typeof Icons;
type VariantProps = { variant?: 'default' | 'outlined' };

type InputMaskProps = ReactElementProps<any> & {
inputRef: Ref<any>;
hasError?: boolean;
$hasIconLeft?: boolean;
$hasIconRight?: boolean;
};

const InputMask = IMaskMixin(
({
inputRef,
hasError,
$hasIconRight,
$hasIconLeft,
...props
}: InputMaskProps) => (
<Input
{...props}
$hasError={!!hasError}
$hasIconLeft={!!$hasIconLeft}
$hasIconRight={!!$hasIconRight}
ref={inputRef as RefObject<HTMLInputElement> | undefined}
/>
),
);

export type TextInputType = InputHTMLAttributes<HTMLInputElement> & {
style?: any;
textInputStyle?: any;
maskOptions?: any;
label?: string;
message?: string;
error?: string;
name: string;
id: string;
maxLength?: number;
value: string;
autoFocus?: boolean;
iconRight?: IconsType;
iconLeft?: IconsType;
onClickIconRight?: (event: MouseEvent<HTMLElement>) => void;
onClickIconLeft?: (event: MouseEvent<HTMLElement>) => void;
onChange: (e: Partial<ChangeEvent<any>>) => void;
onBlur?: (
e:
| FocusEvent<HTMLInputElement | HTMLTextAreaElement>
| ChangeEvent<HTMLDivElement>,
) => void;
onFocus?:
| ((
e:
| FocusEvent<HTMLInputElement | HTMLTextAreaElement>
| ChangeEvent<HTMLDivElement>,
) => void)
| undefined;
};
export type TextInputType = InputHTMLAttributes<HTMLInputElement> &
VariantProps & {
style?: any;
textInputStyle?: any;
maskOptions?: any;
label?: string;
message?: string;
error?: string;
name: string;
id: string;
maxLength?: number;
value: string;
autoFocus?: boolean;
iconRight?: IconsType;
iconLeft?: IconsType;
onClickIconRight?: (event: MouseEvent<HTMLElement>) => void;
onClickIconLeft?: (event: MouseEvent<HTMLElement>) => void;
onChange: (e: Partial<ChangeEvent<any>>) => void;
onBlur?: (
e:
| FocusEvent<HTMLInputElement | HTMLTextAreaElement>
| ChangeEvent<HTMLDivElement>,
) => void;
onFocus?:
| ((
e:
| FocusEvent<HTMLInputElement | HTMLTextAreaElement>
| ChangeEvent<HTMLDivElement>,
) => void)
| undefined;
};

const TextInput: FC<TextInputType> = ({
message,
Expand All @@ -96,91 +75,170 @@ const TextInput: FC<TextInputType> = ({
maskOptions,
iconRight,
iconLeft,
variant = 'default',
...rest
}) => {
const [isFocused, setIsFocused] = useState(false);

const hasValue = value?.length > 0;
const hasError = error ? error.length > 0 : false;
const hasFocus = isFocused || hasValue;

const RightIconComponent: any = iconRight && Icons[iconRight];
const LeftIconComponent: any = iconLeft && Icons[iconLeft];
const ErrorIconComponent: any = Icons['ExclamationTriangleIcon'];

const onAccept = (value: any) => {
if (onChange) {
onChange({
target: {
name,
value,
},
} as any);
}
};

const handleFocus = () => {
setIsFocused(true);
};

const onAccept = (_, __, event?: InputEvent | undefined) => {
onChange(event as Partial<ChangeEvent<any>>);
const handleBlur = (event: FocusEvent<HTMLInputElement>) => {
if (event.target.value === '') {
setIsFocused(false);
}
};

const ref = useRef(null);
const inputRef = useRef(null);

return (
<Wrapper style={style}>
{iconLeft && (
<IconWrapperLeft
clickable={!!onClickIconLeft}
onClick={onClickIconLeft}
>
<LeftIconComponent
id={`${id}-left-icon`}
accessibility="ícone do botão"
/>
</IconWrapperLeft>
)}
{maskOptions ? (
<InputMask
{...maskOptions}
id={id}
name={name}
data-testid={id}
style={textInputStyle}
ref={ref}
inputRef={inputRef}
onAccept={onAccept}
autoFocus={autoFocus}
hasError={hasError}
$hasIconLeft={!!iconLeft}
$hasIconRight={!!iconRight}
defaultValue={value}
{...rest}
/>
) : (
<Input
id={id}
data-testid={id}
name={name}
value={value}
style={textInputStyle}
onBlur={onBlur}
onFocus={onFocus}
onChange={onChange}
maxLength={maxLength}
autoFocus={autoFocus}
{variant === 'outlined' && (
<Label
htmlFor={id}
$hasFocus={hasFocus}
$hasError={hasError}
$hasIconLeft={!!iconLeft}
$hasIconRight={!!iconRight}
{...rest}
/>
)}
{iconRight && (
<IconWrapperRight
clickable={!!onClickIconRight}
onClick={onClickIconRight}
>
<RightIconComponent
id={`${id}-right-icon`}
accessibility="ícone do botão"
/>
</IconWrapperRight>
{label}
</Label>
)}
<PlaceholderLabel
className="text-input-label"
$hasIconLeft={!!iconLeft}
$hasIconRight={!!iconRight}

<InputWrapper
$hasFocus={hasFocus}
$hasError={hasError}
$hasValue={hasValue}
$variant={variant}
>
{label}
</PlaceholderLabel>
{iconLeft && (
<IconWrapperLeft
$clickable={!!onClickIconLeft}
$hasError={hasError}
onClick={onClickIconLeft}
>
<LeftIconComponent
id={`${id}-left-icon`}
accessibility="ícone do botão"
/>
</IconWrapperLeft>
)}

{maskOptions ? (
<StyledIMaskInput
{...maskOptions}
id={id}
name={name}
data-testid={id}
style={textInputStyle}
ref={ref}
inputRef={inputRef}
onAccept={onAccept}
autoFocus={autoFocus}
hasError={hasError}
onFocus={(event) => {
handleFocus();
onFocus?.(event);
}}
onBlur={(event) => {
handleBlur(event);
onBlur?.(event);
}}
mask={hasFocus ? maskOptions?.mask : ''}
defaultValue={value}
$hasIconLeft={!!iconLeft}
$hasIconRight={!!iconRight}
$hasError={hasError}
$variant={variant}
{...rest}
/>
) : (
<Input
id={id}
data-testid={id}
name={name}
value={value}
style={textInputStyle}
onFocus={(event) => {
handleFocus();
onFocus?.(event);
}}
onBlur={(event) => {
handleBlur(event);
onBlur?.(event);
}}
onChange={onChange}
maxLength={maxLength}
autoFocus={autoFocus}
$hasError={hasError}
$hasIconLeft={!!iconLeft}
$hasIconRight={!!iconRight}
$variant={variant}
{...rest}
/>
)}

{iconRight && (
<IconWrapperRight
$clickable={!!onClickIconRight}
$hasError={hasError}
onClick={onClickIconRight}
>
<RightIconComponent
id={`${id}-right-icon`}
accessibility="ícone do botão"
/>
</IconWrapperRight>
)}

{variant === 'outlined' && (
<Fieldset $hasFocus={hasFocus} $hasError={hasError}>
<legend>
<span>{label}</span>
</legend>
</Fieldset>
)}
</InputWrapper>

{variant !== 'outlined' && (
<PlaceholderLabel
className="text-input-label"
$hasIconLeft={!!iconLeft}
$hasIconRight={!!iconRight}
$hasError={hasError}
$hasValue={hasValue}
>
{label}
</PlaceholderLabel>
)}

{error || message ? (
<Message className="error-text-input" $hasError={hasError}>
<Message
className="error-text-input"
$hasError={hasError}
$variant={variant}
>
{variant === 'outlined' && <ErrorIconComponent />}
{error || message}
</Message>
) : null}
Expand Down
Loading

0 comments on commit 7149ddb

Please sign in to comment.