import React, { useState, useRef, useEffect, createContext, useContext } from "react"
import { Tabs as RadixTabs } from "radix-ui"; // TODO: remove and use separation
import * as cn from "./TabsPrimary.styles"
import { useValueChange } from "./useValueChange";
import { useTabsAnalytics } from "./TabsAnalytics";
/**
* Context for managing the navigation direction in the TabsPrimary component
*/
const TabsPrimaryContext = createContext<{
direction: 'forward' | 'backward'
}>({
direction: 'forward'
});
/**
* Props for the TabsPrimary component
*/
export interface TabsPrimaryProps {
/** Child elements to be rendered within the navigation */
children: React.ReactNode
/** The currently selected tab value */
value?: string
/** Callback function triggered when a tab is selected */
onChange?: (value: string) => void
/** Whether to enable sliding animation between tabs */
slide?: boolean
/** Additional CSS class name for the component */
className?: string
}
/**
* A navigation component that displays tabs with an underline indicator
*
* @category Component
*/
export function TabsPrimary({
children,
value: controlledValue,
onChange,
slide = true,
className,
}: TabsPrimaryProps) {
const tabsAnalytics = useTabsAnalytics()
const childrenArray = React.Children.toArray(children);
const navItems = childrenArray.filter(
child => {
return React.isValidElement(child) &&
(child.type === TabsPrimary.Item ||
(typeof child.type === 'function' && 'displayName' in child.type && child.type.displayName === "Tabs.Item"))
}
);
const otherChildren = childrenArray.filter(
child => !React.isValidElement(child) ||
(child.type !== TabsPrimary.Item &&
!(typeof child.type === 'function' && 'displayName' in child.type && child.type.displayName === "Tabs.Item"))
);
const [direction, value, handleValueChange] = useValueChange(
controlledValue,
onChange,
navItems
);
useEffect(() => {
tabsAnalytics.setValue(value)
}, [value])
return (
{otherChildren}
);
}
/**
* Props for the TabsPrimary.Item component
*/
export interface TabsPrimaryItemProps {
/** Child elements to be rendered within the navigation item */
children: React.ReactNode
/** Unique identifier for the navigation item */
value: string
/** URL for the navigation item link */
href?: string
/** Custom component to render as the link element */
as?: React.ElementType
/** Whether this item should be active by default */
defaultActive?: boolean
}
/**
* Individual navigation item component
*
* @category Component
*/
TabsPrimary.Item = function TabsPrimaryItem({ children, value, href, as, defaultActive }: TabsPrimaryItemProps) {
const Link = as || _Link;
const controlByItem = typeof defaultActive === "boolean"
const [defaultActiveState, setDefaultActiveState] = useState(controlByItem ? (defaultActive ? "active" : "inactive") : undefined)
let activeProps = controlByItem && defaultActiveState != undefined
? { "data-state": defaultActiveState }
: undefined
useEffect(() => {
if (!controlByItem) {
return
}
setDefaultActiveState(undefined)
}, [])
return (
{children}
);
}
/**
* Props for the TabsPrimary.Content component
*/
export interface TabsPrimaryContentProps {
/** Child elements to be rendered within the content area */
children: React.ReactNode
/** Unique identifier for the content section */
value: string
/** Whether this content should be active by default */
defaultActive?: boolean
}
/**
* Content section component for the TabsPrimary
*
* @category Component
*/
TabsPrimary.Content = function TabsPrimaryContent({
children,
value,
defaultActive
}: TabsPrimaryContentProps) {
const { direction } = useContext(TabsPrimaryContext);
const controlByItem = typeof defaultActive === "boolean"
const [defaultActiveState, setDefaultActiveState] = useState(controlByItem ? (defaultActive ? "active" : "inactive") : undefined)
let activeProps = controlByItem && defaultActiveState != undefined
? { "data-state": defaultActiveState }
: undefined
useEffect(() => {
if (!controlByItem) {
return
}
setDefaultActiveState(undefined)
}, [])
return (
);
}
function _Link({ ...props }) {
return {props.children}
}