Skip to content

Commit

Permalink
feat: add tab component (#81)
Browse files Browse the repository at this point in the history
Signed-off-by: Lukas.J.Han <[email protected]>
  • Loading branch information
lukasjhan authored Aug 20, 2024
1 parent dba7454 commit eb2ccda
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 0 deletions.
108 changes: 108 additions & 0 deletions packages/core/lib/components/Tab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import React, { useState } from 'react';
import { Label } from './Label';

interface TabProps {
label: string;
content: React.ReactNode;
disabled?: boolean;
}

interface TabsProps {
tabs: TabProps[];
}

const Tab: React.FC<{
label: string;
isSelected: boolean;
onClick: () => void;
id: string;
panelId: string;
disabled?: boolean;
}> = ({ label, isSelected, onClick, id, panelId, disabled }) => {
return (
<button
role="tab"
aria-selected={isSelected}
aria-controls={panelId}
id={id}
onClick={onClick}
disabled={disabled}
className={`px-6 py-3 focus:outline-none focus:ring-2 focus:ring-primary-50 transition-all duration-400 ease-in-out'
${
isSelected
? 'border-b-4 border-primary rounded-t-2'
: 'border-b-4 border-transparent rounded-t-2'
} ${disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-secondary-5'}`}
>
<Label
color={isSelected ? 'primary' : 'gray-50'}
className={
disabled
? 'cursor-not-allowed'
: isSelected
? 'cursor-pointer'
: 'cursor-pointer hover:text-gray-70'
}
size="l"
weight="bold"
>
{label}
</Label>
{isSelected && <span className="sr-only">선택됨</span>}
</button>
);
};

const TabPanel: React.FC<{
children: React.ReactNode;
id: string;
tabId: string;
isSelected: boolean;
}> = ({ children, id, tabId, isSelected }) => {
return (
<div
role="tabpanel"
id={id}
aria-labelledby={tabId}
className={`${isSelected ? '' : 'hidden'}`}
>
{children}
</div>
);
};

export const Tabs: React.FC<TabsProps> = ({ tabs }) => {
const [selectedTab, setSelectedTab] = useState(0);

return (
<div className="w-full">
<div
role="tablist"
aria-label="Tab Navigation"
className="flex border-b border-gray-20"
>
{tabs.map((tab, index) => (
<Tab
key={index}
label={tab.label}
isSelected={index === selectedTab}
onClick={() => setSelectedTab(index)}
id={`tab-${index}`}
panelId={`panel-${index}`}
disabled={tab.disabled}
/>
))}
</div>
{tabs.map((tab, index) => (
<TabPanel
key={index}
id={`panel-${index}`}
tabId={`tab-${index}`}
isSelected={index === selectedTab}
>
{tab.content}
</TabPanel>
))}
</div>
);
};
2 changes: 2 additions & 0 deletions packages/core/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { Switch } from './components/Switch';
import { Chip } from './components/Chip';
import { Checkbox } from './components/Checkbox';
import { RadioButtonGroup } from './components/RadioButton';
import { Tabs } from './components/Tab';

export { Display, Heading, Title, Body, Detail, Label, Link, colors };
export {
Expand All @@ -35,4 +36,5 @@ export {
TextInput,
TextArea,
Breadcrumb,
Tabs,
};
96 changes: 96 additions & 0 deletions stories/core/Tab.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { Tabs } from '../../packages/core/lib';

const meta = {
title: 'Components/Tabs',
component: Tabs,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
tabs: {
control: {
type: 'object',
},
},
},
} satisfies Meta<typeof Tabs>;

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

export const Default: Story = {
args: {
tabs: [
{
label: 'Tab 1',
content:
'Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 Content',
},
{
label: 'Tab 2',
content:
'Tab 2 Content Tab 2 Content Tab 2 Content Tab 2 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 Content',
},
{
label: 'Tab 3',
content:
'Tab 3 Content ab 2 Content Tab 2 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentT ',
},
],
},
};

export const oneTab: Story = {
args: {
tabs: [
{
label: 'Tab 1',
content:
'Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 Content Tab 1 Content',
},
],
},
};

export const LongTitle: Story = {
args: {
tabs: [
{
label: 'Tab 1 Long Title',
content:
'Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 Content',
},
{
label: 'Tab 2 Long Title',
content:
'Tab 2 Content Tab 2 Content Tab 2 Content Tab 2 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 Content',
},
{
label: 'Tab 3 Long Title',
content:
'Tab 3 Content ab 2 Content Tab 2 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentT ',
},
],
},
};

export const Disabled: Story = {
args: {
tabs: [
{
label: 'Tab 1 Long Title',
content:
'Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 Content',
},
{
label: 'Tab 2 Long Title',
content:
'Tab 2 Content Tab 2 Content Tab 2 Content Tab 2 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 Content Tab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 ContentTab 1 Content',
disabled: true,
},
],
},
};

0 comments on commit eb2ccda

Please sign in to comment.