From 590f6546ee393f7a628c09d49bfe5963e0001fcb Mon Sep 17 00:00:00 2001 From: LUCAS DINIZ DE MELO Date: Fri, 12 Jan 2024 12:07:22 -0300 Subject: [PATCH] Adicionado novo estilo do input (#169) * added new input style * fix defaultValue input mask --- src/components/TextInput/index.tsx | 140 ++++++++++++++++++++-------- src/components/TextInput/styles.tsx | 94 +++++++++++-------- 2 files changed, 155 insertions(+), 79 deletions(-) diff --git a/src/components/TextInput/index.tsx b/src/components/TextInput/index.tsx index fb21bcd..95bd0c3 100644 --- a/src/components/TextInput/index.tsx +++ b/src/components/TextInput/index.tsx @@ -3,24 +3,44 @@ import { FC, FocusEvent, InputHTMLAttributes, + MouseEvent, Ref, RefObject, useRef, } from 'react'; import { IMaskMixin, ReactElementProps } from 'react-imask'; +import Icons from '../Icons'; +import { + IconWrapperLeft, + IconWrapperRight, + Input, + Message, + PlaceholderLabel, + Wrapper, +} from './styles'; -import { Input, Label, Message, PlaceholderLabel, Wrapper } from './styles'; +type IconsType = keyof typeof Icons; type InputMaskProps = ReactElementProps & { inputRef: Ref; hasError?: boolean; + hasIconLeft?: boolean; + hasIconRight?: boolean; }; const InputMask = IMaskMixin( - ({ inputRef, hasError, ...props }: InputMaskProps) => ( + ({ + inputRef, + hasError, + hasIconRight, + hasIconLeft, + ...props + }: InputMaskProps) => ( | undefined} /> ), @@ -30,7 +50,7 @@ export type TextInputType = InputHTMLAttributes & { style?: any; textInputStyle?: any; maskOptions?: any; - label: string; + label?: string; message?: string; error?: string; name: string; @@ -38,6 +58,10 @@ export type TextInputType = InputHTMLAttributes & { maxLength?: number; value: string; autoFocus?: boolean; + iconRight?: IconsType; + iconLeft?: IconsType; + onClickIconRight?: (event: MouseEvent) => void; + onClickIconLeft?: (event: MouseEvent) => void; onChange: (e: Partial>) => void; onBlur?: ( e: @@ -59,6 +83,8 @@ const TextInput: FC = ({ onChange, onBlur, onFocus, + onClickIconLeft, + onClickIconRight, style, label, textInputStyle, @@ -68,11 +94,16 @@ const TextInput: FC = ({ maxLength, autoFocus, maskOptions, + iconRight, + iconLeft, ...rest }) => { const hasValue = value?.length > 0; const hasError = error ? error.length > 0 : false; + const RightIconComponent: any = iconRight && Icons[iconRight]; + const LeftIconComponent: any = iconLeft && Icons[iconLeft]; + const onAccept = (_, __, event?: InputEvent | undefined) => { onChange(event as Partial>); }; @@ -82,44 +113,71 @@ const TextInput: FC = ({ return ( - + {iconLeft && ( + + + + )} + {maskOptions ? ( + + ) : ( + + )} + {iconRight && ( + + + + )} + + {label} + + {error || message ? ( + + {error || message} + + ) : null} ); }; diff --git a/src/components/TextInput/styles.tsx b/src/components/TextInput/styles.tsx index 9efdf3a..7da83c9 100644 --- a/src/components/TextInput/styles.tsx +++ b/src/components/TextInput/styles.tsx @@ -1,10 +1,15 @@ import styled from 'styled-components'; -import { getTheme, ifStyle } from '@platformbuilders/theme-toolkit'; +import { getTheme, ifStyle, pxToRem } from '@platformbuilders/theme-toolkit'; + +type HasIcon = { + hasIconLeft?: boolean; + hasIconRight?: boolean; +}; type PlaceholderLabelProps = { $hasValue: boolean; $hasError: boolean; -}; +} & HasIcon; type MessageProps = { $hasError: boolean; @@ -12,72 +17,85 @@ type MessageProps = { type InputProps = { $hasError: boolean; -}; +} & HasIcon; const primaryMain = getTheme('brand.primary.main'); const dangerMain = getTheme('danger.main'); -const textMain = getTheme('danger.main'); +const fontSizeSm = getTheme('fontSizes.sm'); +const fontSizeMd = getTheme('fontSizes.md'); +const spacingXs = getTheme('spacing.xs'); +const spacingSm = getTheme('spacing.sm'); +const spacingMd = getTheme('spacing.md'); +const spacingLg = getTheme('spacing.lg'); +const textMain = getTheme('text.main'); +const borderRadiusMd = getTheme('borderRadius.md'); + const hasError = ifStyle('$hasError'); export const PlaceholderLabel = styled.span` position: absolute; - top: 0.9375rem; - left: 0.875rem; + top: ${pxToRem(16)}; + left: ${pxToRem(14)}; line-height: 147.6%; - color: rgba(19, 19, 21, 0.6); transition: top 0.2s; - + ${({ hasIconLeft }) => !!hasIconLeft && `left: ${pxToRem(36)};`} ${(props) => - props.$hasValue && - `top: 0; font-size: 0.9375rem; margin-bottom: 40px; color: ${primaryMain( - props, - )};`} + props.$hasValue && `top: 0; font-size: ${fontSizeMd}; margin-bottom: 40px;`} color: ${(props) => hasError(dangerMain(props), primaryMain(props))(props)}; `; export const Input = styled.input` - border: none; - border-bottom: 0.125rem solid rgba(19, 19, 21, 0.6); width: 100%; - height: 3.5rem; - font-size: 1.0625rem; - padding-left: 0.875rem; + font-size: ${fontSizeMd}px; line-height: 147.6%; - padding-top: 0.825rem; - padding-bottom: 0.5rem; border-color: ${(props) => hasError(dangerMain(props), '#121212')(props)}; - - &:hover { - background: rgba(73, 133, 224, 0.12); - } - + display: flex; + height: ${pxToRem(44)}; + padding: ${spacingXs}px ${spacingSm}px ${spacingXs}px ${spacingMd}px; + ${({ hasIconRight }) => !!hasIconRight && `padding-right: ${pxToRem(36)};`} + ${({ hasIconLeft }) => !!hasIconLeft && `padding-left: ${pxToRem(36)};`} + align-items: center; + gap: ${pxToRem(12)}; + background: ${(props) => + !!props.$hasError ? `${dangerMain(props)}10` : `${textMain(props)}10`}; + border-radius: ${borderRadiusMd}px; + border: none; + font-size: ${fontSizeSm}px; + font-style: normal; + font-weight: 400; + line-height: 150%; &:focus { border-color: ${(props) => hasError(dangerMain(props), primaryMain(props))(props)}; outline: none; } - - &:focus + ${PlaceholderLabel} { - top: 0; - font-size: 0.9375rem; - margin-bottom: 40px; - color: ${(props) => hasError(dangerMain(props), primaryMain(props))(props)}; - } - - background: #eff1f2; `; export const Message = styled.span` - font-size: 0.9375rem; + font-size: ${fontSizeMd}px; color: ${(props) => hasError(dangerMain(props), textMain(props))(props)}; letter-spacing: 0.0275rem; - margin: 0.125rem 0.875rem; + margin: ${spacingXs}px ${spacingMd}px; `; -export const Label = styled.label``; - export const Wrapper = styled.div` - margin-bottom: 1.5rem; + margin-bottom: ${spacingLg}px; position: relative; `; + +export const IconWrapperLeft = styled.div<{ clickable?: boolean }>` + position: absolute; + left: ${pxToRem(14)}; + top: ${pxToRem(22)}; + transform: translateY(-50%); + cursor: ${({ clickable }) => (!!clickable ? 'pointer' : 'default')}; +`; + +export const IconWrapperRight = styled.div<{ clickable?: boolean }>` + position: absolute; + right: ${pxToRem(14)}; + top: ${pxToRem(22)}; + transform: translateY(-50%); + cursor: ${({ clickable }) => (!!clickable ? 'pointer' : 'default')}; +`;