Skip to content

Commit

Permalink
refactor: 기존 Button 컴포넌트를 LinkedButton 컴포넌트로 리팩터링후 공용 버튼 컴포넌트를 새로 만듬
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-yn committed Mar 2, 2024
1 parent 08c0c49 commit 13f74ca
Show file tree
Hide file tree
Showing 12 changed files with 171 additions and 123 deletions.
6 changes: 3 additions & 3 deletions src/components/Contact/Contact.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { PropsWithChildren } from 'react';
import Button from '@/composable/Button/Button';
import Clipboard from '@/composable/Clipboard/Clipboard';
import LinkedButton from '@/composable/LinkedButton/LinkedButton';
import SectionTitle from '@/composable/SectionTitle/SectionTitle';
import { getStaticContext } from '@/utils/context/StaticContext';
import { ContactSectionProps, StaticContextContact } from './Contact.context';
Expand Down Expand Up @@ -55,9 +55,9 @@ const Description = () => {
const Send = () => {
const { data } = getStaticContext(StaticContextContact);
return (
<Button as="a" className={sendStyle} size="L" href={`mailto:${data.email}`}>
<LinkedButton className={sendStyle} size="L" href={`mailto:${data.email}`}>
메일 보내기
</Button>
</LinkedButton>
);
};

Expand Down
6 changes: 3 additions & 3 deletions src/components/MainProject/MainProject.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import classNames from 'classnames';
import React from 'react';
import Button from '@/composable/Button/Button';
import LinkedButton from '@/composable/LinkedButton/LinkedButton';
import Mock from '@/composable/Mock/Mock';
import {
backgroundGradientVariants,
Expand Down Expand Up @@ -44,9 +44,9 @@ const MainProject = ({ src, device, title, period, description }: Props) => {
<p className={titleStyle}>{title}</p>
<p className={periodStyle}>{period}</p>
<p className={descriptionStyle}>{description}</p>
<Button className={buttonStyle} as="button" size="M">
<LinkedButton className={buttonStyle} size="M">
더보기
</Button>
</LinkedButton>
</div>
</article>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import classNames from 'classnames';
import React from 'react';
import Button from '@/composable/Button/Button';
import Grid from '@/composable/Grid/Grid';
import LinkedButton from '@/composable/LinkedButton/LinkedButton';
import Text from '@/composable/Text/Text';
import {
backgroundColorVariants,
Expand All @@ -23,7 +23,7 @@ const buttonStates: {
{ size: 'L', status: 'PRESS', text: '메일 보내기' },
];

const ButtonBoard = () => {
const LinkedButtonBoard = () => {
// 각 버튼 상태에 대한 버튼 렌더링
return (
<Grid
Expand Down Expand Up @@ -79,18 +79,17 @@ const ButtonBoard = () => {
Press
</Text>
{buttonStates.map(({ size, status, text }) => (
<Button
as="button"
<LinkedButton
key={`${size}-${status}`}
size={size}
status={status}
width={size === 'M' ? '6.875rem' : '20rem'}
>
{text}
</Button>
</LinkedButton>
))}
</Grid>
);
};

export default ButtonBoard;
export default LinkedButtonBoard;
75 changes: 5 additions & 70 deletions src/composable/Button/Button.css.ts
Original file line number Diff line number Diff line change
@@ -1,73 +1,8 @@
import { style, styleVariants } from '@vanilla-extract/css';
import { flexCenter } from '@/styles/common/flex.css';
import {
commonColorThemeVars,
userColorThemeVars,
} from '@/styles/theme/index.css';
import { style } from '@vanilla-extract/css';

export const buttonStyle = style([
flexCenter,
{
gap: '0.625rem',
export const buttonStyle = style({
transition: 'opacity 0.2s ease-in-out',
':hover': {
opacity: 0.8,
},
]);

const MHOVER = {
backgroundColor: 'rgba(255, 255, 255, 0.8)',
};

const MPRESS = {
transition: 'none',
backgroundColor: commonColorThemeVars.token['gray-scale-00'],
boxShadow: '0px 3px 2px 0px rgba(0, 0, 0, 0.12) inset',
};

const LHOVER = {
border: '1.5px solid',
borderColor: commonColorThemeVars.token['gray-scale-01'],
color: commonColorThemeVars.token['gray-scale-01'],
opacity: 0.8,
};

const LPRESS = {
transition: 'none',
borderColor: commonColorThemeVars.token['gray-scale-00'],
color: commonColorThemeVars.token['gray-scale-00'],
opacity: 1,
backgroundColor: 'rgba(255, 255, 255, 0.08)',
};

export const buttonVariants = styleVariants({
M: [
buttonStyle,
{
display: 'inline-flex',
padding: '0.625rem 0.75rem',
borderRadius: '0.5rem',
backgroundColor: commonColorThemeVars.token['gray-scale-00'],
color: userColorThemeVars.token['tertiary'],
':hover': MHOVER,
':active': MPRESS,
},
],
L: [
buttonStyle,
{
padding: '0.625rem',
backgroundColor: 'transparent',
border: '1px solid',
borderColor: commonColorThemeVars.token['gray-scale-00'],
borderRadius: '0.25rem',
color: commonColorThemeVars.token['gray-scale-00'],
':hover': LHOVER,
':active': LPRESS,
},
],
});

export const buttonStatusVariants = styleVariants({
MHOVER,
MPRESS,
LHOVER,
LPRESS,
});
28 changes: 10 additions & 18 deletions src/composable/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,39 @@
import classNames from 'classnames';
import React, { PropsWithChildren } from 'react';
import { fontVariants } from '@/styles/common/font.css';
import Tag from '../Tag/Tag';
import { buttonVariants } from './Button.css';
import { getSpecificButtonStatus } from './helper/getSepcificButtonStatus';
import { buttonStyle } from './Button.css';

interface Props {
className?: string;
size: 'M' | 'L';
as: 'button' | 'a';
type?: 'button' | 'submit';
href?: string;
status?: 'DEFAULT' | 'HOVER' | 'PRESS';
width?: string;
style?: React.CSSProperties;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
onSubmit?: React.FormEventHandler<HTMLButtonElement>;
}

const Button = ({
className,
children,
as,
as = 'button',
type = 'button',
href,
size,
status = 'DEFAULT',
width,
style,
onClick,
onSubmit,
}: PropsWithChildren<Props>) => {
return (
<Tag
type="button"
className={classNames(className, buttonStyle)}
style={{ ...style, width }}
as={as}
href={href}
className={classNames(
className,
buttonVariants[size],
fontVariants[
size === 'M' ? 'paragraph-m-medium' : 'paragraph-s-regular'
],
getSpecificButtonStatus?.(size, status),
)}
type={type}
onClick={onClick}
style={{ ...style, width }}
onSubmit={onSubmit}
>
{children}
</Tag>
Expand Down
2 changes: 1 addition & 1 deletion src/composable/Button/helper/getSepcificButtonStatus.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { buttonStatusVariants } from '../Button.css';
import { buttonStatusVariants } from '@/composable/LinkedButton/LinkedButton.css';

export const getSpecificButtonStatus =
process.env.STORYBOOK || process.env.NODE_ENV === 'test'
Expand Down
73 changes: 73 additions & 0 deletions src/composable/LinkedButton/LinkedButton.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { style, styleVariants } from '@vanilla-extract/css';
import { flexCenter } from '@/styles/common/flex.css';
import {
commonColorThemeVars,
userColorThemeVars,
} from '@/styles/theme/index.css';

export const buttonStyle = style([
flexCenter,
{
gap: '0.625rem',
},
]);

const MHOVER = {
backgroundColor: 'rgba(255, 255, 255, 0.8)',
};

const MPRESS = {
transition: 'none',
backgroundColor: commonColorThemeVars.token['gray-scale-00'],
boxShadow: '0px 3px 2px 0px rgba(0, 0, 0, 0.12) inset',
};

const LHOVER = {
border: '1.5px solid',
borderColor: commonColorThemeVars.token['gray-scale-01'],
color: commonColorThemeVars.token['gray-scale-01'],
opacity: 0.8,
};

const LPRESS = {
transition: 'none',
borderColor: commonColorThemeVars.token['gray-scale-00'],
color: commonColorThemeVars.token['gray-scale-00'],
opacity: 1,
backgroundColor: 'rgba(255, 255, 255, 0.08)',
};

export const buttonVariants = styleVariants({
M: [
buttonStyle,
{
display: 'inline-flex',
padding: '0.625rem 0.75rem',
borderRadius: '0.5rem',
backgroundColor: commonColorThemeVars.token['gray-scale-00'],
color: userColorThemeVars.token['tertiary'],
':hover': MHOVER,
':active': MPRESS,
},
],
L: [
buttonStyle,
{
padding: '0.625rem',
backgroundColor: 'transparent',
border: '1px solid',
borderColor: commonColorThemeVars.token['gray-scale-00'],
borderRadius: '0.25rem',
color: commonColorThemeVars.token['gray-scale-00'],
':hover': LHOVER,
':active': LPRESS,
},
],
});

export const buttonStatusVariants = styleVariants({
MHOVER,
MPRESS,
LHOVER,
LPRESS,
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { render, fireEvent } from '@testing-library/react';
import Button from './Button';
import { buttonStatusVariants, buttonVariants } from './Button.css';
import LinkedButton from './LinkedButton';
import { buttonStatusVariants, buttonVariants } from './LinkedButton.css';

describe('Button 컴포넌트', () => {
describe('LinkedButton 컴포넌트', () => {
it('클래스 이름이 올바르게 적용되어야 한다', () => {
const className = 'test-class';
const { getByRole } = render(
<Button as="button" className={className} size="M">
<LinkedButton className={className} size="M">
테스트 버튼
</Button>,
</LinkedButton>,
);

const button = getByRole('button');
Expand All @@ -18,9 +18,9 @@ describe('Button 컴포넌트', () => {

it('상태에 따라 적절한 클래스가 적용되어야 한다', () => {
const { getByRole } = render(
<Button as="button" size="M" status="HOVER">
<LinkedButton size="M" status="HOVER">
테스트 버튼
</Button>,
</LinkedButton>,
);

const button = getByRole('button');
Expand All @@ -30,9 +30,9 @@ describe('Button 컴포넌트', () => {
it('onClick 핸들러가 호출되어야 한다', () => {
const handleClick = jest.fn();
const { getByRole } = render(
<Button as="button" size="M" onClick={handleClick}>
<LinkedButton size="M" onClick={handleClick}>
테스트 버튼
</Button>,
</LinkedButton>,
);

const button = getByRole('button');
Expand Down
49 changes: 49 additions & 0 deletions src/composable/LinkedButton/LinkedButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import classNames from 'classnames';
import { PropsWithChildren } from 'react';
import { fontVariants } from '@/styles/common/font.css';
import Button from '../Button/Button';
import { getSpecificButtonStatus } from '../Button/helper/getSepcificButtonStatus';
import { buttonVariants } from './LinkedButton.css';

interface Props {
className?: string;
size: 'M' | 'L';
href?: string;
status?: 'DEFAULT' | 'HOVER' | 'PRESS';
width?: string;
style?: React.CSSProperties;
onClick?: React.MouseEventHandler<HTMLButtonElement>;
}

const LinkedButton = ({
className,
children,
href,
size,
status = 'DEFAULT',
width,
style,
onClick,
}: PropsWithChildren<Props>) => {
return (
<Button
as="a"
type="button"
href={href || ''}
className={classNames(
className,
buttonVariants[size],
fontVariants[
size === 'M' ? 'paragraph-m-medium' : 'paragraph-s-regular'
],
getSpecificButtonStatus?.(size, status),
)}
onClick={onClick}
style={{ ...style, width }}
>
{children}
</Button>
);
};

export default LinkedButton;
8 changes: 0 additions & 8 deletions src/stories/Common/ButtonBoard.mdx

This file was deleted.

Loading

0 comments on commit 13f74ca

Please sign in to comment.