Skip to content
This repository has been archived by the owner on Jul 29, 2024. It is now read-only.

Commit

Permalink
[FE] feat: Input 컴포넌트 구현 (#174)
Browse files Browse the repository at this point in the history
* feat: theme 컬러 추가

* feat: `Input` 컴포넌트 구현

* test: `Input` 스토리 작성

* refactor: red 색상 팔레트 추가

* refactor: htmlFor 속성 추가 및 outline css 수정
  • Loading branch information
nangkyeonglim authored Aug 3, 2023
1 parent 4234cf1 commit 98217b9
Show file tree
Hide file tree
Showing 3 changed files with 230 additions and 0 deletions.
56 changes: 56 additions & 0 deletions frontend/src/components/@common/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { Meta, StoryObj } from '@storybook/react';
import Input, { InputVariant } from './Input';
import { StoryContainer, StoryItemContainer, StoryItemTitle } from 'styles/storybook';
import { Size } from 'constants/components/common';

const meta: Meta<typeof Input> = {
title: 'common/Input',
component: Input,
args: {
variant: 'outline',
size: 'medium',
labelText: '라벨',
supportingText: '안내 문구는 여기에 나타납니다',
isError: false,
required: true,
placeholder: 'placeholder',
},
argTypes: {
variant: {
description: '미리 정의해놓은 인풋의 스타일입니다.',
options: Object.values(InputVariant),
control: { type: 'radio' },
},
size: {
description: '크기에 따라 padding과 font-size가 바뀝니다.',
options: Object.values(Size),
control: { type: 'radio' },
},
labelText: {
description: '라벨 텍스트입니다.',
control: { type: 'text' },
},
supportingText: {
description: '인풋 아래에 나타나는 안내 문구 텍스트입니다.',
control: { type: 'text' },
},
placeholder: {
description: '인풋 안에 나타나는 placeholder 텍스트입니다.',
control: { type: 'text' },
},
isError: {
description: 'Error 상태를 나타냅니다.',
control: { type: 'boolean' },
},
required: {
description: 'input의 필수 입력 여부를 나타냅니다.',
control: { type: 'boolean' },
},
},
};

export default meta;

type Story = StoryObj<typeof meta>;

export const Playground: Story = {};
163 changes: 163 additions & 0 deletions frontend/src/components/@common/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import type { ComponentPropsWithRef, ForwardedRef, ReactElement } from 'react';
import { forwardRef, useId } from 'react';
import { RuleSet, css, styled } from 'styled-components';
import { Size } from 'types/components/common';

export const InputVariant = ['outline', 'filled', 'unstyled', 'underlined'] as const;
export type InputVariant = (typeof InputVariant)[number];

type Props = {
size: Size;
labelText: string;
supportingText: string;
variant: InputVariant;
isError: boolean;
} & Omit<ComponentPropsWithRef<'input'>, 'size'>;

const Input = (
{
size = 'large',
labelText,
supportingText,
variant = 'outline',
isError = false,
...rest
}: Partial<Props>,
ref: ForwardedRef<HTMLInputElement>,
) => {
const inputId = useId();
return (
<S.InputContainer>
{labelText && (
<S.Label htmlFor={inputId} $required={rest.required} $variant={variant}>
{labelText}
</S.Label>
)}
<S.Input
id={inputId}
ref={ref}
$size={size}
$variant={variant}
$isError={isError}
{...rest}
/>
{supportingText && <S.SupportingText $isError={isError}>{supportingText}</S.SupportingText>}
</S.InputContainer>
);
};

export default forwardRef(Input);

const genVariantStyle = (
variant: Required<Props>['variant'],
isError: Required<Props>['isError'],
): RuleSet<object> => {
const styles: Record<typeof variant, ReturnType<typeof genVariantStyle>> = {
outline: css`
${({ theme }) => css`
border: 1px solid ${isError ? theme.color.red6 : theme.color.gray6};
outline: 1px solid ${theme.color.gray1};
&:focus {
border: 1px solid ${isError ? theme.color.red6 : theme.color.gray6};
outline: 1px solid ${isError ? theme.color.red6 : theme.color.gray8};
}
`}
`,
filled: css`
${({ theme }) => css`
background-color: ${isError ? theme.color.red1 : theme.color.gray4};
border: 1px solid ${theme.color.gray1};
outline: 1px solid ${theme.color.gray1};
&:focus {
background-color: ${theme.color.gray1};
outline: 1px solid ${isError ? theme.color.red6 : theme.color.gray8};
}
`}
`,
unstyled: css`
${({ theme }) => css`
border: 1px solid ${theme.color.gray1};
outline: 1px solid ${isError ? theme.color.red6 : theme.color.gray1};
&:focus {
outline: 1px solid ${isError ? theme.color.red6 : theme.color.gray8};
}
`}
`,
underlined: css`
${({ theme }) => css`
border: 1px solid ${theme.color.gray1};
border-bottom: 1px solid ${isError ? theme.color.red6 : theme.color.gray6};
border-radius: 0;
outline: 1px solid ${theme.color.gray1};
`}
`,
};
return styles[variant];
};

const genSizeStyle = (size: Required<Props>['size']): RuleSet<object> => {
const styles: Record<typeof size, ReturnType<typeof genSizeStyle>> = {
small: css`
padding: 0.6rem 0.6rem;
font-size: 1.3rem;
`,
medium: css`
padding: 0.8rem 1rem;
font-size: 1.4rem;
`,
large: css`
padding: 1rem 1.2rem;
font-size: 1.5rem;
`,
};
return styles[size];
};

const S = {
InputContainer: styled.div`
display: flex;
flex-direction: column;
gap: 0.6rem;
font-size: 1.3rem;
`,

Label: styled.label<{ $required: boolean | undefined; $variant: InputVariant }>`
font-weight: 500;
${({ $required, theme }) =>
$required &&
css`
&::after {
content: '*';
margin-left: 0.2rem;
color: ${theme.color.red6};
}
`};
`,
Input: styled.input<{
$size: Size;
$variant: InputVariant;
$isError: boolean;
}>`
border: none;
border-radius: 4px;
${({ $size }) => genSizeStyle($size)};
${({ $variant, $isError }) => genVariantStyle($variant, $isError)};
`,
SupportingText: styled.p<{ $isError: boolean | undefined }>`
color: ${({ $isError, theme }) => ($isError ? theme.color.red6 : theme.color.gray7)};
`,
Underline: styled.div`
position: absolute;
bottom: 0;
left: 0;
height: 2px;
width: 100%;
background-color: ${({ theme }) => theme.color.primary};
transform: scaleX(0);
transition: all 0.3s ease;
`,
};
11 changes: 11 additions & 0 deletions frontend/src/styles/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ const color = {
tistory: '#FF5A4A',
medium: '#000000',

red1: '#fff1f0',
red2: '#ffccc7',
red3: '#ffa39e',
red4: '#ff7875',
red5: '#ff4d4f',
red6: '#f5222d',
red7: '#cf1322',
red8: '#a8071a',
red9: '#820014',
red10: '#5c0011',

gray1: '#ffffff',
gray2: '#fafafa',
gray3: '#f5f5f5',
Expand Down

0 comments on commit 98217b9

Please sign in to comment.