Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

input 옮기기 & 리드미 작성 #77

Merged
merged 5 commits into from
Nov 5, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .storybook/preview-body.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<div id="custom-root"></div>
<div id="dialog-container"></div>
185 changes: 117 additions & 68 deletions README.md

Large diffs are not rendered by default.

49 changes: 49 additions & 0 deletions src/Input/Input.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { Meta, StoryObj } from '@storybook/react';

import Input from './Input';

const meta: Meta<typeof Input> = {
title: 'Input',
component: Input,
argTypes: {
rightIcon: {
control: { type: 'boolean' },
mapping: { false: '', true: '🔎' },
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋ 이렇게 대체하셨군여

},
},
args: {
customWidth: '300px',
isError: false,
rightIcon: false,
errorMessage: '',
},
};

export default meta;
type Story = StoryObj<typeof Input>;

export const Default: Story = {};

export const WithPlaceholder: Story = {
args: {
placeholder: '상품 이름을 검색하세요.',
},
};

export const WithIcon: Story = {
args: {
placeholder: '상품 이름을 검색하세요.',
rightIcon: true,
},
};

export const Error: Story = {
args: {
isError: true,
errorMessage: '10글자 이내로 입력해주세요.',
},
};

export const Disabled: Story = {
render: () => <Input disabled />,
};
98 changes: 98 additions & 0 deletions src/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import type { ComponentPropsWithRef, ForwardedRef, ReactNode } from 'react';
import { forwardRef } from 'react';
import styled from 'styled-components';

import Text from '../Text';

export interface InputProps extends ComponentPropsWithRef<'input'> {
/**
* Input 컴포넌트의 너비값입니다.
*/
customWidth?: string;
/**
* Input 컴포넌트의 최소 너비값입니다.
*/
minWidth?: string;
/**
* Input value에 에러가 있는지 여부입니다.
*/
isError?: boolean;
/**
* Input 컴포넌트 오른쪽에 위치할 아이콘입니다.
*/
rightIcon?: ReactNode;
/**
* isError가 true일 때 보여줄 에러 메시지입니다.
*/
errorMessage?: string;
}

const Input = forwardRef(
(
{ customWidth = '300px', minWidth, isError = false, rightIcon, errorMessage, ...props }: InputProps,
ref: ForwardedRef<HTMLInputElement>
) => {
return (
<>
<InputContainer customWidth={customWidth} minWidth={minWidth}>
<CustomInput ref={ref} isError={isError} {...props} />
{rightIcon && <IconWrapper>{rightIcon}</IconWrapper>}
</InputContainer>
{isError && <ErrorMessage>{errorMessage}</ErrorMessage>}
</>
);
}
);

Input.displayName = 'Input';

export default Input;

type InputContainerStyleProps = Pick<InputProps, 'customWidth' | 'minWidth'>;
type CustomInputStyleProps = Pick<InputProps, 'isError'>;

const InputContainer = styled.div<InputContainerStyleProps>`
position: relative;
min-width: ${({ minWidth }) => minWidth ?? 0};
max-width: ${({ customWidth }) => customWidth};
text-align: center;
`;

const CustomInput = styled.input<CustomInputStyleProps>`
width: 100%;
height: 40px;
padding: 10px 0 10px 12px;
color: ${({ isError, theme }) => (isError ? theme.colors.error : theme.textColors.default)};
border: 1px solid ${({ isError, theme }) => (isError ? theme.colors.error : theme.borderColors.default)};
border-radius: 5px;

&:focus {
border: 2px solid ${({ isError, theme }) => (isError ? theme.colors.error : theme.borderColors.strong)};
outline: none;
}

&:disabled {
border: 1px solid ${({ theme }) => theme.borderColors.disabled};
background: ${({ theme }) => theme.colors.gray1};
}

&::placeholder {
color: ${({ theme }) => theme.textColors.disabled};
font-size: ${({ theme }) => theme.fontSizes.sm};
}
`;

const IconWrapper = styled.div`
position: absolute;
top: 0;
right: 0;
display: flex;
align-items: center;
height: 100%;
margin-right: 8px;
`;

const ErrorMessage = styled(Text)`
color: ${({ theme }) => theme.colors.error};
font-size: ${({ theme }) => theme.fontSizes.xs};
`;
5 changes: 5 additions & 0 deletions src/Input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Input from './Input';

export type { InputProps } from './Input';

export default Input;
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ export { default as Link } from './Link';
export { default as Spacing } from './Spacing';
export { default as Text } from './Text';
export { default as Textarea } from './Textarea';
export { default as Input } from './Input';