🎨 style: adjust vertical tab theme

This commit is contained in:
Wahyu Kurniawan 2024-02-21 14:24:35 +07:00
parent 1ab155c638
commit e57591187c
No known key found for this signature in database
GPG Key ID: 040A1549143A8E33
4 changed files with 60 additions and 10 deletions

View File

@ -4,8 +4,9 @@ export type TabsVariants = VariantProps<typeof tabsTheme>;
export const tabsTheme = tv({ export const tabsTheme = tv({
slots: { slots: {
root: ['flex', 'flex-col', 'w-full'], root: ['flex', 'data-[orientation=horizontal]:w-full'],
triggerWrapper: [ triggerWrapper: [
// Horizontal default
'px-1', 'px-1',
'pb-5', 'pb-5',
'text-elements-low-em', 'text-elements-low-em',
@ -17,6 +18,24 @@ export const tabsTheme = tv({
'data-[state=active]:font-medium', 'data-[state=active]:font-medium',
'data-[state=active]:text-elements-high-em', 'data-[state=active]:text-elements-high-em',
'data-[state=active]:border-elements-high-em', 'data-[state=active]:border-elements-high-em',
// Vertical
'data-[orientation=vertical]:px-3',
'data-[orientation=vertical]:py-3',
'data-[orientation=vertical]:min-w-[240px]',
'data-[orientation=vertical]:focus-ring',
'data-[orientation=vertical]:rounded-xl',
'data-[orientation=vertical]:border-transparent',
'data-[orientation=vertical]:hover:bg-base-bg-emphasized',
'data-[orientation=vertical]:hover:text-elements-mid-em',
'data-[orientation=vertical]:hover:border-transparent',
'data-[orientation=vertical]:focus-visible:border-transparent',
'data-[orientation=vertical]:focus-visible:bg-base-bg-emphasized',
'data-[orientation=vertical]:focus-visible:text-elements-mid-em',
'data-[orientation=vertical]:data-[state=active]:font-normal',
'data-[orientation=vertical]:data-[state=active]:bg-base-bg-emphasized',
'data-[orientation=vertical]:data-[state=active]:border-transparent',
'data-[orientation=vertical]:data-[state=active]:hover:text-elements-high-em',
'data-[orientation=vertical]:data-[state=active]:focus-visible:text-elements-high-em',
], ],
trigger: [ trigger: [
'flex', 'flex',
@ -29,14 +48,22 @@ export const tabsTheme = tv({
'leading-none', 'leading-none',
'tracking-[-0.006em]', 'tracking-[-0.006em]',
'rounded-md', 'rounded-md',
'focus-ring', // Horizontal default
'data-[orientation=horizontal]:focus-ring',
// Vertical
'data-[orientation=vertical]:gap-2',
], ],
triggerList: [ triggerList: [
'flex', 'flex',
'shrink-0', 'shrink-0',
'gap-5', 'gap-5',
'border-b', 'border-b',
'border-border-interactive/10', 'border-transparent',
// Horizontal default
'data-[orientation=horizontal]:border-border-interactive/10',
// Vertical
'data-[orientation=vertical]:flex-col',
'data-[orientation=vertical]:gap-0.5',
], ],
content: ['text-elements-high-em', 'grow', 'outline-none', 'tab-content'], content: ['text-elements-high-em', 'grow', 'outline-none', 'tab-content'],
}, },

View File

@ -18,12 +18,21 @@ export interface TabsProps extends ComponentPropsWithoutRef<typeof TabsRoot> {
* A component that allows users to switch between different tabs. * A component that allows users to switch between different tabs.
* @returns JSX element representing the tabs component. * @returns JSX element representing the tabs component.
*/ */
export const Tabs = ({ config, className, ...props }: TabsProps) => { export const Tabs = ({
config,
className,
orientation = 'horizontal',
...props
}: TabsProps) => {
const { root } = tabsTheme(config); const { root } = tabsTheme(config);
return ( return (
<TabsProvider {...config}> <TabsProvider {...config} orientation={orientation}>
<TabsRoot {...props} className={root({ className })} /> <TabsRoot
{...props}
orientation={orientation}
className={root({ className })}
/>
</TabsProvider> </TabsProvider>
); );
}; };

View File

@ -2,10 +2,14 @@ import React, {
createContext, createContext,
useContext, useContext,
type PropsWithChildren, type PropsWithChildren,
ComponentPropsWithoutRef,
} from 'react'; } from 'react';
import { TabsVariants } from './Tabs.theme'; import { TabsVariants } from './Tabs.theme';
import { Root as TabsRoot } from '@radix-ui/react-tabs';
export interface TabsProviderProps extends Partial<TabsVariants> {} export interface TabsProviderProps
extends Partial<TabsVariants>,
ComponentPropsWithoutRef<typeof TabsRoot> {}
type TabsProviderContext = ReturnType<typeof useTabsValues>; type TabsProviderContext = ReturnType<typeof useTabsValues>;

View File

@ -27,18 +27,28 @@ const TabsTrigger = forwardRef<
>(({ className, icon, children, ...props }, ref) => { >(({ className, icon, children, ...props }, ref) => {
const config = useTabs(); const config = useTabs();
const { triggerWrapper, trigger } = tabsTheme(config); const { triggerWrapper, trigger } = tabsTheme(config);
const orientation = config.orientation;
return ( return (
<Trigger <Trigger
ref={ref} ref={ref}
tabIndex={-1} // Disabled focus state for horizontal tabs
tabIndex={orientation === 'horizontal' ? -1 : undefined}
className={triggerWrapper({ className })} className={triggerWrapper({ className })}
{...props} {...props}
> >
{/* Need to add button in the trigger children because there's focus state inside the children */} {/* Need to add button in the trigger children because there's focus state inside the children */}
<button className={trigger()}> <button
data-orientation={orientation}
// Disabled focus state for vertical tabs
tabIndex={orientation === 'vertical' ? -1 : undefined}
className={trigger()}
>
{/* Put the icon on the left of the text for veritcal tab */}
{orientation === 'vertical' && icon}
{children} {children}
{icon} {/* Put the icon on the right of the text for horizontal tab */}
{orientation === 'horizontal' && icon}
</button> </button>
</Trigger> </Trigger>
); );