-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(tabs): introduce new tabs component
refs #347
- Loading branch information
Showing
2 changed files
with
147 additions
and
0 deletions.
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
packages/utah-design-system/src/components/Tabs.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }), | ||
)} | ||
/> | ||
); | ||
} |