Skip to content

Commit

Permalink
feat(tabs): introduce new tabs component
Browse files Browse the repository at this point in the history
refs #347
  • Loading branch information
steveoh committed Nov 4, 2024
1 parent 77226f4 commit f05231a
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 0 deletions.
50 changes: 50 additions & 0 deletions packages/utah-design-system/src/components/Tabs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import type { Meta } from '@storybook/react';
import { Tab, TabList, TabPanel, Tabs } from './Tabs';

const meta: Meta<typeof Tabs> = {
component: Tabs,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
};

export default meta;

export const Example = (args: any) => (
<div className="min-w-[800px]">
<Tabs {...args}>
<TabList aria-label="History of Ancient Rome">
<Tab id="FoR">Founding of Rome</Tab>
<Tab id="MaR">Monarchy and Republic</Tab>
<Tab id="Emp" isDisabled>
Empire
</Tab>
</TabList>
<TabPanel id="FoR">
Arma virumque cano, Troiae qui primus ab oris.
</TabPanel>
<TabPanel id="MaR">Senatus Populusque Romanus.</TabPanel>
<TabPanel id="Emp">Alea jacta est.</TabPanel>
</Tabs>
</div>
);

export const Vertical = (args: any) => (
<div className="min-w-[800px]">
<Tabs {...args} orientation="vertical">
<TabList aria-label="History of Ancient Rome">
<Tab id="FoR">Founding of Rome</Tab>
<Tab id="MaR">Monarchy and Republic</Tab>
<Tab id="Emp" isDisabled>
Empire
</Tab>
</TabList>
<TabPanel id="FoR">
Arma virumque cano, Troiae qui primus ab oris.
</TabPanel>
<TabPanel id="MaR">Senatus Populusque Romanus.</TabPanel>
<TabPanel id="Emp">Alea jacta est.</TabPanel>
</Tabs>
</div>
);
97 changes: 97 additions & 0 deletions packages/utah-design-system/src/components/Tabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
Tab as RACTab,
TabList as RACTabList,
TabPanel as RACTabPanel,
Tabs as RACTabs,
TabListProps,
TabPanelProps,
TabProps,
TabsProps,
composeRenderProps,
} from 'react-aria-components';
import { tv } from 'tailwind-variants';
import { focusRing } from './utils';

const tabsStyles = tv({
base: 'group flex gap-4',
variants: {
orientation: {
horizontal: 'flex-col',
vertical: 'flex-1 flex-row',
},
},
});

export function Tabs(props: TabsProps) {
return (
<RACTabs
{...props}
className={composeRenderProps(props.className, (className, renderProps) =>
tabsStyles({ ...renderProps, className }),
)}
/>
);
}

const tabListStyles = tv({
base: 'flex gap-1',
variants: {
orientation: {
horizontal: 'flex-row border-b pb-2',
vertical: 'flex-col items-start border-l pl-2',
},
},
});

export function TabList<T extends object>(props: TabListProps<T>) {
return (
<RACTabList
{...props}
className={composeRenderProps(props.className, (className, renderProps) =>
tabListStyles({ ...renderProps, className }),
)}
/>
);
}

const tabProps = tv({
extend: focusRing,
base: 'relative flex cursor-default items-center rounded-full px-4 py-1.5 font-bold transition forced-color-adjust-none hover:bg-zinc-200 hover:text-zinc-700',
variants: {
isSelected: {
false:
'text-zinc-500 after:bottom-1 after:h-px after:bg-slate-400 pressed:bg-zinc-200 pressed:text-zinc-700 dark:text-secondary-400 dark:text-slate-200 dark:text-zinc-300 after:dark:bg-secondary-400 after:dark:bg-slate-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-200 dark:pressed:bg-zinc-800 dark:pressed:text-zinc-200',
true: 'text-secondary-500 after:absolute after:block after:rounded-full after:bg-secondary-400 group-data-[orientation="horizontal"]:after:bottom-[-0.8em] group-data-[orientation="horizontal"]:after:left-0 group-data-[orientation=vertical]:after:left-[-0.78em] group-data-[orientation="horizontal"]:after:h-2 group-data-[orientation=vertical]:after:h-full group-data-[orientation="horizontal"]:after:w-full group-data-[orientation=vertical]:after:w-2 forced-colors:bg-[Highlight] forced-colors:text-[HighlightText]',
},
isDisabled: {
true: 'text-zinc-200 selected:bg-zinc-200 selected:text-zinc-300 dark:text-zinc-600 dark:selected:bg-zinc-600 dark:selected:text-zinc-500 forced-colors:text-[GrayText] forced-colors:selected:bg-[GrayText] forced-colors:selected:text-[HighlightText]',
},
},
});

export function Tab(props: TabProps) {
return (
<RACTab
{...props}
className={composeRenderProps(props.className, (className, renderProps) =>
tabProps({ ...renderProps, className }),
)}
/>
);
}

const tabPanelStyles = tv({
extend: focusRing,
base: 'flex-1 p-4 text-sm text-zinc-900 dark:text-zinc-100',
});

export function TabPanel(props: TabPanelProps) {
return (
<RACTabPanel
{...props}
className={composeRenderProps(props.className, (className, renderProps) =>
tabPanelStyles({ ...renderProps, className }),
)}
/>
);
}

0 comments on commit f05231a

Please sign in to comment.