Skip to content

Commit

Permalink
feat: Tab 컴포넌트 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
steven-yn committed Mar 2, 2024
1 parent 6c9b88c commit 069dd4a
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 2 deletions.
50 changes: 50 additions & 0 deletions src/composable/Tab/Tab.css.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { style, styleVariants } from '@vanilla-extract/css';
import { backgroundColorVariants } from '@/styles/common/color.css';
import { flexCenter } from '@/styles/common/flex.css';

export const wrapStyle = style({
display: 'flex',
gap: '0.25rem',
});

const buttonAnchorCommonStyle = style([
flexCenter,
backgroundColorVariants['secondary-variant'],
{
position: 'relative',
height: '0.125rem',
borderRadius: '0.25rem',
transition: 'all 0.3s ease-in-out',
},
]);

export const buttonAnchorStyleVariant = styleVariants({
SELECTED: [
buttonAnchorCommonStyle,
{
width: '2rem',
opacity: 1,
':hover': {
opacity: 0.8,
},
},
],
DEFAULT: [
buttonAnchorCommonStyle,
{
width: '1.5rem',
opacity: 0.4,
':hover': {
opacity: 0.2,
},
},
],
});

export const buttonStyle = style({
position: 'absolute',
boxSizing: 'content-box',
width: '100%',
height: '100%',
padding: '0.25rem 0.1rem',
});
44 changes: 42 additions & 2 deletions src/composable/Tab/Tab.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,47 @@
import React from 'react';
import Button from '../Button/Button';
import { buttonAnchorStyleVariant, buttonStyle, wrapStyle } from './Tab.css';

const Tab = () => {
return <div></div>;
export interface TabProps {
selectedIdx: number;
onClick: (currentIdx: number) => void;
length: number;
}

const Tab = ({ length, selectedIdx, onClick }: TabProps) => {
return (
<div className={wrapStyle}>
{Array.from({ length: length > 5 ? 5 : length }).map((_, idx) => (
<Tab.Item
key={idx}
idx={idx}
isSelected={idx === selectedIdx}
onClick={onClick}
/>
))}
</div>
);
};

interface ItemProps {
idx: number;
isSelected: boolean;
onClick: (currentIdx: number) => void;
}

const Item = ({ idx, isSelected, onClick }: ItemProps) => {
const handleClick = () => {
onClick(idx);
};
return (
<span
className={buttonAnchorStyleVariant[isSelected ? 'SELECTED' : 'DEFAULT']}
>
<Button as="button" className={buttonStyle} onClick={handleClick} />
</span>
);
};

Tab.Item = Item;

export default Tab;
16 changes: 16 additions & 0 deletions src/hook/useOceanTab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { useState } from 'react';

const useOceanTab = (initIdx?: number) => {
const [selectedIdx, setSelectedIdx] = useState(initIdx || 0);

const handleClick = (idx: number) => {
setSelectedIdx(idx);
};

return {
selectedIdx,
handleClick,
};
};

export default useOceanTab;
32 changes: 32 additions & 0 deletions src/stories/Common/Tab/Tab.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Meta, StoryObj } from '@storybook/react';
import Tab from '@/composable/Tab/Tab';

const meta: Meta<typeof Tab> = {
title: 'Common/Tab',
component: Tab,
tags: ['autodocs'],
parameters: { layout: 'fullscreen' },
decorators: [
(Story) => (
<div
style={{
display: 'flex',
alignItems: 'center',
height: '10rem',
backgroundColor: 'lightgray',
}}
>
<Story />
</div>
),
],
};

type Story = StoryObj<typeof Tab>;
export const Static: Story = {
args: {
length: 5,
selectedIdx: 0,
},
};
export default meta;
39 changes: 39 additions & 0 deletions src/stories/Common/Tab/Usage.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Meta, StoryObj } from '@storybook/react';
import Tab, { TabProps } from '@/composable/Tab/Tab';
import useOceanTab from '@/hook/useOceanTab';

const Template = (args: TabProps) => {
const { selectedIdx, handleClick } = useOceanTab(args.selectedIdx);
return (
<div
style={{
display: 'flex',
alignItems: 'center',
height: '10rem',
backgroundColor: 'lightgray',
}}
>
<Tab
length={args.length}
selectedIdx={selectedIdx}
onClick={handleClick}
/>
</div>
);
};

const meta: Meta<typeof Tab> = {
title: 'Common/Tab',
component: Template,
parameters: { layout: 'fullscreen' },
};

type Story = StoryObj<typeof Tab>;
export const Usage: Story = {
args: {
length: 5,
selectedIdx: 0,
},
};

export default meta;

0 comments on commit 069dd4a

Please sign in to comment.