import type * as React from 'react'; import type { PrimitivePropsWithRef } from '../utils/primitive.cjs'; /** Why the selected tab changed: keyboard, pointer, or programmatic value write. */ export type TabsChangeReason = 'keyboard' | 'pointer' | 'programmatic'; /** Payload passed to `onValueChange`: the old value, the new value, and what caused the change. */ export interface TabsValueChangeDetail { /** The tab that is now selected. */ value: string; /** The tab selected before this change, or `null` when nothing was. */ previousValue: string | null; /** What drove the change: pointer click/tap or keyboard activation/navigation. */ reason: TabsChangeReason; } /** @internal Shared state distributed from {@link Tabs} to its parts via context. */ export interface TabsContextValue { baseId: string; value?: string | undefined; /** Selects `value` and reports it, tagged with what drove the selection. */ onValueChange: (value: string, reason: TabsChangeReason) => void; orientation: 'horizontal' | 'vertical'; activationMode: 'automatic' | 'manual'; /** The root's `disabled`, OR-ed into every trigger's own. */ disabled: boolean; /** * Whether focus was moved by the tablist's own Arrow/Home/End handling, so * automatic activation ignores focus events from anywhere else. */ arrowNavigatingRef: React.RefObject; /** * Values whose panels are mounted; a trigger publishes `aria-controls` only * for a panel that is actually present, since `forceMount` is invisible to it. */ mountedContentValues: ReadonlySet; setContentMounted: (value: string, mounted: boolean) => void; /** * The tablist's single tab stop: the selected tab if mounted and enabled, * else the first enabled tab; `null` until resolved or all disabled. */ firstEnabledValue: string | null; setFirstEnabledValue: (value: string | null) => void; } /** One entry of {@link TabsProps.items} — a tab and the panel it reveals. */ export interface TabsItem { /** Unique identifier, matched against the selected value and shared by the derived trigger and panel. */ value: string; /** Text rendered inside the derived `TabsTrigger`. */ label: React.ReactNode; /** * The panel body revealed when this tab is selected. Ignored when * `renderPanel` is given. * @default undefined — the panel renders empty. */ content?: React.ReactNode | undefined; /** * Excludes this tab from selection, arrow-key navigation and the tab order. * @default false */ disabled?: boolean | undefined; } /** Props for the {@link Tabs} root. */ export interface TabsProps extends PrimitivePropsWithRef<'div'> { /** * The tabs to render as derived triggers and panels; ignored when `children` is given. * @default undefined — nothing is derived; compose the list and panels as `children`. */ items?: TabsItem[] | undefined; /** * Renders a derived panel's body in place of the entry's `content`, for content the item data can't hold. * @default undefined — the entry's `content` is rendered. */ renderPanel?: ((item: TabsItem) => React.ReactNode) | undefined; /** * Whether arrow-key navigation wraps from the last trigger to the first and back. * @default true */ loop?: boolean | undefined; /** * Selected tab's value, for controlled usage; pair with `onValueChange`. * @default undefined — uncontrolled, tracks its own selected value internally. */ value?: string | undefined; /** * Initially selected tab's value, for uncontrolled usage. * @default undefined — falls back to the first enabled trigger. */ defaultValue?: string | undefined; /** * Fires when the selected tab changes, controlled or not, with the new value, the previous value, and the reason. * @default undefined — no-op. */ onValueChange?: ((detail: TabsValueChangeDetail) => void) | undefined; /** * Layout axis, exposed as `data-orientation` and used to pick Arrow Left/Right * vs Arrow Up/Down for keyboard navigation between triggers. * @default 'horizontal' */ orientation?: 'horizontal' | 'vertical' | undefined; /** * `'automatic'` selects a tab as soon as it receives focus; `'manual'` only selects on Enter/Space. * @default 'automatic' */ activationMode?: 'automatic' | 'manual' | undefined; /** * Disables every trigger; OR-ed with each `TabsTrigger`'s own `disabled`, never overridden. * @default false */ disabled?: boolean | undefined; } /** Props for {@link TabsList}, the roving-focus container for `TabsTrigger`s. */ export interface TabsListProps extends PrimitivePropsWithRef<'div'> { /** * Whether arrow-key navigation wraps from the last trigger back to the first * (and vice versa). * @default true */ loop?: boolean | undefined; } /** Props for a single {@link TabsTrigger} button. */ export interface TabsTriggerProps extends PrimitivePropsWithRef<'button'> { /** Unique identifier matched against a sibling `TabsContent`'s `value`. */ value: string; /** * Excludes this trigger from selection and the tab order; OR-ed with the root's `disabled` and reflected as `data-disabled`. * @default false */ disabled?: boolean | undefined; } /** Props for a single {@link TabsContent} panel. */ export interface TabsContentProps extends PrimitivePropsWithRef<'div'> { /** Unique identifier matched against the `TabsTrigger` that reveals this panel. */ value: string; /** * Keeps this panel mounted and hidden via the `hidden` attribute instead of unmounting it while inactive. * @default false */ forceMount?: boolean | undefined; /** * Whether the panel itself is a tab stop; pass `-1` when the panel's own content is already focusable. * @default 0 */ tabIndex?: 0 | -1 | undefined; }