import * as React from 'react' ; import { composeEventHandlers } from '@radix-ui/primitive' ; import { createContextScope } from '@radix-ui/react-context' ; import { useCallbackRef } from '@radix-ui/react-use-callback-ref' ; import { useControllableState } from '@radix-ui/react-use-controllable-state' ; import { Primitive } from '@radix-ui/react-primitive' ; import * as RovingFocusGroup from '@radix-ui/react-roving-focus' ; import { createRovingFocusGroupScope } from '@radix-ui/react-roving-focus' ; import { useId } from '@radix-ui/react-id' ; import type * as Radix from '@radix-ui/react-primitive' ; import type { Scope } from '@radix-ui/react-context' ; const TABS_NAME = 'Tabs' ; type ScopedProps < P > = P & { __scopeTabs ? : Scope ; } ; const [ createTabsContext , createTabsScope ] = createContextScope ( TABS_NAME , [ createRovingFocusGroupScope , ] ) ; const useRovingFocusGroupScope = createRovingFocusGroupScope ( ) ; type TabsContextValue = { baseId : string ; value ? : string ; onValueChange : ( value : string ) => void ; orientation ? : TabsProps [ 'orientation' ] ; dir ? : TabsProps [ 'dir' ] ; activationMode ? : TabsProps [ 'activationMode' ] ; } ; const [ TabsProvider , useTabsContext ] = createTabsContext < TabsContextValue > ( TABS_NAME ) ; type TabsElement = React . ElementRef < typeof Primitive . div > ; type RovingFocusGroupProps = Radix . ComponentPropsWithoutRef < typeof RovingFocusGroup . Root > ; type PrimitiveDivProps = Radix . ComponentPropsWithoutRef < typeof Primitive . div > ; interface TabsProps extends PrimitiveDivProps { /** The value for the selected tab, if controlled */ value ? : string ; /** The value of the tab to select by default, if uncontrolled */ defaultValue ? : string ; /** A function called when a new tab is selected */ onValueChange ? : ( value : string ) => void ; defaultValue orientation ? : RovingFocusGroupProps [ 'orientation' ] ; defaultValue dir ? : RovingFocusGroupProps [ 'dir' ] ; defaultValue activationMode ? : 'automatic' | 'manual' ; } const Tabs = React . forwardRef < TabsElement , TabsProps > ( ( props , forwardedRef ) => { const { __scopeTabs , value : valueProp , onValueChange , defaultValue , orientation = 'horizontal' , dir = 'ltr' , activationMode = 'automatic' , ... tabsProps } = props ; const [ value , setValue ] = useControllableState ( { prop : valueProp , onChange : onValueChange , defaultProp : defaultValue , } ) ; return ( < TabsProvider scope = { __scopeTabs } baseId = { useId ( ) } value = { value } onValueChange = { setValue } orientation = { orientation } dir = { dir } activationMode = { activationMode } > < Primitive . div data - orientation = { orientation } { ... tabsProps } ref = { forwardedRef } / > < /TabsProvider>); } ) ; Tabs . displayName = TABS_NAME ; const TAB_LIST_NAME = 'TabsList' ; type TabsListElement = React . ElementRef < typeof Primitive . div > ; interface TabsListProps extends PrimitiveDivProps { loop ? : RovingFocusGroupProps [ 'loop' ] ; } const TabsList = React . forwardRef < TabsListElement , TabsListProps > ( ( props , forwardedRef ) => { const { __scopeTabs , loop = true , ... listProps } = props ; const context = useTabsContext ( TAB_LIST_NAME , __scopeTabs ) ; const rovingFocusGroupScope = useRovingFocusGroupScope ( __scopeTabs ) ; return ( < RovingFocusGroup . Root asChild { ... rovingFocusGroupScope } orientation = { context . orientation } dir = { context . dir } loop = { loop } > < Primitive . div role = "tablist" aria - orientation = { context . orientation } dir = { context . dir } { ... listProps } ref = { forwardedRef } / > < /RovingFocusGroup.Root>); } ) ; TabsList . displayName = TAB_LIST_NAME ; const TRIGGER_NAME = 'TabsTrigger' ; type TabsTriggerElement = React . ElementRef < typeof Primitive . button > ; type PrimitiveButtonProps = Radix . ComponentPropsWithoutRef < typeof Primitive . button > ; interface TabsTriggerProps extends PrimitiveButtonProps { value : string ; } const TabsTrigger = React . forwardRef < TabsTriggerElement , TabsTriggerProps > ( ( props , forwardedRef ) => { const { __scopeTabs , value , disabled = false , ... triggerProps } = props ; const context = useTabsContext ( TRIGGER_NAME , __scopeTabs ) ; const rovingFocusGroupScope = useRovingFocusGroupScope ( __scopeTabs ) ; const triggerId = makeTriggerId ( context . baseId , value ) ; const contentId = makeContentId ( context . baseId , value ) ; const isSelected = value === context . value ; const handleTabChange = useCallbackRef ( ( ) => context . onValueChange ( value ) ) ; return ( < RovingFocusGroup . Item asChild { ... rovingFocusGroupScope } focusable = { ! disabled } active = { isSelected } > < Primitive . button type = "button" role = "tab" aria - selected = { isSelected } aria - controls = { contentId } data - state = { isSelected ? 'active' : 'inactive' } data - disabled = { disabled ? '' : undefined } disabled = { disabled } id = { triggerId } { ... triggerProps } ref = { forwardedRef } onClick = { composeEventHandlers ( props . onClick , handleTabChange ) } onMouseDown = { composeEventHandlers ( props . onMouseDown , ( event ) => { if ( ! disabled && event . button === 0 && event . ctrlKey === false ) { handleTabChange ( ) ; } } ) } onFocus = { composeEventHandlers ( props . onFocus , ( ) => { const isAutomaticActivation = context . activationMode !== 'manual' ; if ( ! isSelected && ! disabled && isAutomaticActivation ) { handleTabChange ( ) ; } } ) } /> < /RovingFocusGroup.Item>); } ) ; TabsTrigger . displayName = TRIGGER_NAME ; const CONTENT_NAME = 'TabsContent' ; type TabsContentElement = React . ElementRef < typeof Primitive . div > ; interface TabsContentProps extends PrimitiveDivProps { value : string ; } const TabsContent = React . forwardRef < TabsContentElement , TabsContentProps > ( ( props , forwardedRef ) => { const { __scopeTabs , value , children , ... contentProps } = props ; const context = useTabsContext ( CONTENT_NAME , __scopeTabs ) ; const triggerId = makeTriggerId ( context . baseId , value ) ; const contentId = makeContentId ( context . baseId , value ) ; const isSelected = value === context . value ; return ( < Primitive . div data - state = { isSelected ? 'active' : 'inactive' } data - orientation = { context . orientation } role = "tabpanel" aria - labelledby = { triggerId } hidden = { ! isSelected } id = { contentId } tabIndex = { 0 } { ... contentProps } ref = { forwardedRef } > { isSelected && children } < /Primitive.div>); } ) ; TabsContent . displayName = CONTENT_NAME ; function makeTriggerId ( baseId , value ) { return `${ baseId }-trigger-${ value }` ; } function makeContentId ( baseId , value ) { return `${ baseId }-content-${ value }` ; } const Root = Tabs ; const List = TabsList ; const Trigger = TabsTrigger ; const Content = TabsContent ; export { createTabsScope , Tabs , TabsList , TabsTrigger , TabsContent , Root , List , Trigger , Content , } ; export type { TabsProps , TabsListProps , TabsTriggerProps , TabsContentProps } ;