Skip to content

Commit

Permalink
Merge pull request #41 from Team-Tiki/feature/tiki/#32-input-supporti…
Browse files Browse the repository at this point in the history
…ngText

[Feat] input supportingText 구현
  • Loading branch information
wuzoo authored Jul 8, 2024
2 parents b517b78 + c0cbac3 commit 7bc7c29
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 22 deletions.
37 changes: 27 additions & 10 deletions src/common/component/Input/Input.style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,27 @@ import { css } from '@emotion/react';
import { InputProps } from '@/common/component/Input/Input';
import { theme } from '@/common/style/theme/theme';

export const inputContainerStyle = css({
export const containerStyle = css({
display: 'flex',
flexDirection: 'column',

gap: '1.2rem',
gap: '0.8rem',

width: '100%',

'& > div': {
marginTop: '0.4rem',
},
});

export const inputSupportStyle = css({
display: 'flex',
flexDirection: 'column',

gap: '0.8rem',
});

export const inputWarpperStyle = css({
export const warpperStyle = css({
display: 'flex',
alignItems: 'center',

Expand All @@ -23,22 +36,26 @@ export const inputStyle = css({
border: 'none',
backgroundColor: 'transparent',
fontWeight: 400,
...theme.text.body03,

outline: 'none',

'::placeholder': {
color: theme.colors.gray_500,
...theme.text.body03,
},
});

export const variantStyle = (variant: Required<InputProps>['variant']) => {
export const variantStyle = ({ variant, isError }: { variant: Required<InputProps>['variant']; isError: boolean }) => {
const borderColor = isError ? `${theme.colors.red}` : `${theme.colors.gray_400}`;

const style = {
outline: {
boxShadow: ` 0px 0px 0px 1px ${theme.colors.gray_400}`,
default: {
boxShadow: `inset 0px 0px 0px 1px ${borderColor}`,
borderRadius: '8px',
},
underline: {
boxShadow: ` 0px 1px 0px ${theme.colors.gray_400}`,
boxShadow: `0px 1px 0px ${borderColor}`,
},
colored: {
borderRadius: '100px',
Expand All @@ -51,9 +68,9 @@ export const variantStyle = (variant: Required<InputProps>['variant']) => {

export const sizeStyle = (size: Required<InputProps>['size']) => {
const style = {
small: { padding: '0.8rem 1.2rem', ...theme.text.body04 },
medium: { padding: '1.2rem 1.2rem', ...theme.text.body02 },
large: { padding: '1.2rem 1.6rem', ...theme.text.body02 },
small: { padding: '0.8rem 1.2rem' },
medium: { padding: '1.2rem 1.2rem' },
large: { padding: '1.2rem 1.6rem' },
};

return style[size];
Expand Down
41 changes: 31 additions & 10 deletions src/common/component/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,56 @@
import React, { InputHTMLAttributes } from 'react';
import React, { ForwardedRef, InputHTMLAttributes, forwardRef } from 'react';

import {
inputContainerStyle,
containerStyle,
inputStyle,
inputWarpperStyle,
inputSupportStyle,
sizeStyle,
variantStyle,
warpperStyle,
} from '@/common/component/Input/Input.style';
import Label from '@/common/component/Label/Label';
import SupportingText from '@/common/component/SupportingText/SupportingText';

type InputSize = 'small' | 'medium' | 'large';
type InputVariant = 'outline' | 'underline' | 'colored';
type InputVariant = 'default' | 'underline' | 'colored';

export interface InputProps extends Omit<InputHTMLAttributes<HTMLInputElement>, 'size'> {
variant: InputVariant;
variant?: InputVariant;
size?: InputSize; //default: medium(p: 1.2rem)
label?: string;
LeftIcon?: React.FunctionComponent<React.SVGProps<SVGSVGElement>>; //svg 컴포넌트
isError?: boolean;
isNotice?: boolean;
supportingText?: string;
}

const Input = ({ variant, size = 'medium', label, LeftIcon, ...props }: InputProps) => {
const Input = (
{
variant = 'default',
size = 'medium',
label,
LeftIcon,
isError = false,
isNotice = false,
supportingText,
...props
}: InputProps,
ref: ForwardedRef<HTMLInputElement>
) => {
return (
<article css={inputContainerStyle}>
<article css={containerStyle}>
{label && <Label id={label}>{label}</Label>}
<div css={[inputWarpperStyle, variantStyle(variant), sizeStyle(size)]}>
<div css={[warpperStyle, variantStyle({ variant, isError }), sizeStyle(size)]}>
{LeftIcon && <LeftIcon />}
<input css={[inputStyle]} {...props} />
<input ref={ref} css={inputStyle} {...props} />
</div>
{supportingText && (
<SupportingText isError={isError} isNotice={isNotice}>
{supportingText}
</SupportingText>
)}
</article>
);
};

export default Input;
export default forwardRef(Input);
9 changes: 9 additions & 0 deletions src/common/component/SupportingText/SupportingText.style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { css } from '@emotion/react';

import { theme } from '@/common/style/theme/theme';

export const textStyle = (isError: boolean, isNotice: boolean) => {
const textColor = isError ? theme.colors.red : isNotice ? theme.colors.blue_900 : theme.colors.gray_400;

return css({ color: textColor, wordBreak: 'break-word', ...theme.text.body04 });
};
14 changes: 14 additions & 0 deletions src/common/component/SupportingText/SupportingText.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ComponentPropsWithoutRef } from 'react';

import { textStyle } from '@/common/component/SupportingText/SupportingText.style';

interface SupportingTextProps extends ComponentPropsWithoutRef<'p'> {
isError?: boolean;
isNotice?: boolean;
}

const SupportingText = ({ isError = false, isNotice = false, children }: SupportingTextProps) => {
return <p css={textStyle(isError, isNotice)}>{children}</p>;
};

export default SupportingText;
20 changes: 18 additions & 2 deletions src/story/common/Input.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';

import { useEffect, useRef } from 'react';

import Input from '@/common/component/Input/Input';

const meta = {
Expand All @@ -11,14 +13,28 @@ const meta = {
args: {
type: 'text',
placeholder: 'placeholder',
width: 20,
label: 'label',
variant: 'underline',
size: 'medium',
isError: false,
isNotice: false,
supportingText: '',
},
argTypes: {},
} satisfies Meta<typeof Input>;

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

export const Default: Story = {};
export const Default: Story = {
render: (args) => {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);

return <Input ref={inputRef} {...args} />;
},
};

0 comments on commit 7bc7c29

Please sign in to comment.