import type { ReactNode } from "react"
import { PanelTabs } from "./PanelTabs.tsx"
import { RoutedTabs } from "./RoutedTabs.tsx"
import type {
TabItem,
TabLinkItem,
TabsActivation,
TabsOrientation,
} from "./tabItems.ts"
type TabsCommonProps = {
className?: string
/** The tab bar's accessible name. Required. */
label: string
orientation?: TabsOrientation
}
export type TabsPanelProps = TabsCommonProps & {
/** **Initial** only. Charcuterie owns it from then on. */
activeKey?: string
/**
* `automatic` — the ARIA Authoring Practices default — shows a
* panel as soon as the arrow keys reach its tab. `manual` moves
* focus only, and Enter or Space commits.
*
* The distinction exists because **focus is not selection**, and
* it is the entire reason `RovingFocus` is its own state kind. A
* tab whose panel costs a network request wants `manual`, and
* the two modes differ by one line below — because two kinds are
* composed rather than one kind doing both jobs badly.
*/
activation?: TabsActivation
onChange?: (activeKey: string | null) => void
tabs: readonly TabItem[]
}
export type TabsLinkProps = TabsCommonProps & {
/**
* The address the app is at — usually `location.pathname`. The tab
* whose `href` matches wears `aria-current="page"`.
*
* **Required, and it is the discriminant.** `Nav` leaves the
* equivalent optional because a top-level bar is honest about
* naming nothing on a screen it does not contain. A routed tab bar
* is drawn *inside* the section it divides, so "none of these" is
* not a state it has; an app that wants it passes a path that
* matches no tab.
*/
activeHref: string
tabs: readonly TabLinkItem[]
}
/**
* The union splits on `activeHref`, which only the routed member
* has. `tabs` alone could not carry the split — TypeScript does not
* narrow a union by the shape of an array's elements, so a mixed bar
* would type-check and then render half a navigation.
*/
export type TabsProps = TabsLinkProps | TabsPanelProps
const getIsRoutedProps = (
props: TabsProps,
): props is TabsLinkProps => "activeHref" in props
/**
* One choice out of a handful, all of them on screen at once — and
* the choice is either a **panel** this component reveals or a
* **place** the router goes to.
*
* ```tsx
* // A section of this screen. Nothing outside knows about it.
*
*
* // A section that has an address.
*
*
* ```
*
* ## Which one, and the question is not "how does it look"
*
* **Does this section have an address?** If reloading the page, or
* opening it in a second tab, or pressing Back has to land the
* reader back on the same section, it is routed and every tab is an
* ``. If the section is a disclosure inside one screen —
* Settings' groups, a card's detail — it is a panel and every tab is
* a `