Skip to content

Commit

Permalink
feat: add button component (#47)
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas J Han <[email protected]>
Signed-off-by: Lukas.J Han <[email protected]>
  • Loading branch information
lukasjhan authored Aug 8, 2024
1 parent f1f6b1b commit 1cbcda8
Show file tree
Hide file tree
Showing 3 changed files with 269 additions and 0 deletions.
115 changes: 115 additions & 0 deletions packages/core/lib/components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react';
import { Label } from './Label';
import { Color } from '../colors/color.type';

export type ButtonProps<E extends React.ElementType> = {
variant?: 'primary' | 'secondary' | 'tertiary' | 'text';
size?: 'x-small' | 'small' | 'medium' | 'large' | 'x-large';
children: React.ReactNode;
className?: string;
disabled?: boolean;
} & React.ComponentPropsWithoutRef<E>;

export const Button = <E extends React.ElementType = 'button'>({
variant = 'primary',
size = 'large',
children,
className = '',
disabled = false,
...props
}: ButtonProps<E>) => {
const baseStyles =
'inline-flex items-center justify-center rounded-4 font-medium focus:outline-none focus:ring-2 focus:ring-offset-2 transition-colors duration-200';

const variantStyles: {
style: string;
color: Color;
disabledStyle: string;
disabledColor: Color;
} = {
primary: {
style: 'bg-primary hover:bg-primary-60',
color: 'gray-0' as Color,
disabledStyle: 'bg-primary-20',
disabledColor: 'gray-0' as Color,
},
secondary: {
style: 'bg-gray-0 hover:bg-primary-5 border border-primary',
color: 'primary' as Color,
disabledStyle: 'bg-gray-0 border border-primary-30',
disabledColor: 'primary-30' as Color,
},
tertiary: {
style: 'bg-gray-0 hover:bg-gray-5 border border-gray-90',
color: 'gray-90' as Color,
disabledStyle: 'bg-gray-0 border border-gray-40',
disabledColor: 'gray-40' as Color,
},
text: {
style: 'bg-transparent',
color: 'gray-90' as Color,
disabledStyle: 'bg-transparent',
disabledColor: 'gray-40' as Color,
},
}[variant];

const sizeStyles: { style: string; fontSize: 'l' | 'm' | 's' | 'xs' } = {
'x-small': {
style: 'px-3 min-w-[32px] min-h-[32px]',
fontSize: 's' as const,
},
small: {
style: 'px-3 min-w-[40px] min-h-[40px]',
fontSize: 'm' as const,
},
medium: {
style: 'px-4 min-w-[48px] min-h-[48px]',
fontSize: 'm' as const,
},
large: {
style: 'px-6 min-w-[56px] min-h-[56px]',
fontSize: 'l' as const,
},
'x-large': {
style: 'px-8 min-w-[64px] min-h-[64px]',
fontSize: 'l' as const,
},
}[size];

const buttonStyles = `
${baseStyles}
${disabled ? variantStyles.disabledStyle : variantStyles.style}
${sizeStyles.style}
${disabled ? 'cursor-not-allowed' : ''}
${className}
`;

const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
if (!disabled) {
(event.currentTarget as HTMLButtonElement).click();
}
}
};

const labelStyles = `${disabled ? 'cursor-not-allowed' : 'cursor-pointer'} ${variant === 'text' ? 'underline' : ''}`;

return (
<button
className={buttonStyles}
onKeyDown={handleKeyDown}
role="button"
disabled={disabled}
{...props}
>
<Label
color={disabled ? variantStyles.disabledColor : variantStyles.color}
size={sizeStyles.fontSize}
className={labelStyles}
>
{children}
</Label>
</button>
);
};
3 changes: 3 additions & 0 deletions packages/core/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ import { Label } from './components/Label';
import { Link } from './components/Link';
import { colors } from './colors/color';

import { Button } from './components/Button';

export { Display, Heading, Title, Body, Detail, Label, Link, colors };
export { Button };
151 changes: 151 additions & 0 deletions stories/core/Button.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { Button } from '../../packages/core/lib';

const meta = {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: {
type: 'select',
options: ['primary', 'secondary', 'tertiary'],
},
},
size: {
control: {
type: 'select',
options: ['x-small', 'small', 'medium', 'large', 'x-large'],
},
},
disabled: {
control: 'boolean',
},
onClick: { action: 'clicked' },
},
} satisfies Meta<typeof Button>;

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

export const Primary: Story = {
args: {
variant: 'primary',
children: '버튼: Primary',
onClick: fn(),
},
};

export const Secondary: Story = {
args: {
variant: 'secondary',
children: '버튼: Secondary',
onClick: fn(),
},
};

export const Tertiary: Story = {
args: {
variant: 'tertiary',
children: '버튼: Tertiary',
onClick: fn(),
},
};

export const Text: Story = {
args: {
variant: 'text',
children: '버튼: Text',
size: 'small',
onClick: fn(),
},
};

export const XSmall: Story = {
args: {
variant: 'primary',
children: 'X-Small 버튼',
size: 'x-small',
onClick: fn(),
},
};

export const Small: Story = {
args: {
variant: 'primary',
children: 'Small 버튼',
size: 'small',
onClick: fn(),
},
};

export const Medium: Story = {
args: {
variant: 'primary',
children: 'Medium 버튼',
size: 'medium',
onClick: fn(),
},
};

export const Large: Story = {
args: {
variant: 'primary',
children: 'Large 버튼',
size: 'large',
onClick: fn(),
},
};

export const XLarge: Story = {
args: {
variant: 'primary',
children: 'X-Large 버튼',
size: 'x-large',
onClick: fn(),
},
};

export const Disabled: Story = {
args: {
variant: 'primary',
children: 'Disabled Button',
size: 'medium',
disabled: true,
onClick: fn(),
},
};

export const DisabledSecondary: Story = {
args: {
variant: 'secondary',
children: 'Disabled Button',
size: 'medium',
disabled: true,
onClick: fn(),
},
};

export const DisabledTertiary: Story = {
args: {
variant: 'tertiary',
children: 'Disabled Button',
size: 'medium',
disabled: true,
onClick: fn(),
},
};

export const DisabledText: Story = {
args: {
variant: 'text',
children: 'Disabled Button',
size: 'small',
disabled: true,
onClick: fn(),
},
};

0 comments on commit 1cbcda8

Please sign in to comment.