import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters" import type { Meta, StoryObj } from "@storybook/react" import { useState } from "react" import { toStoryChoice } from "../argTypes.storyHelpers.ts" import { Badge } from "../Badge/Badge.tsx" import { Button } from "../Button/Button.tsx" import { ContainerBoard, StoryCell, StoryGrid, } from "../board.storyHelpers.tsx" import { Field } from "../Field/Field.tsx" import { ProgressBar } from "../ProgressBar/ProgressBar.tsx" import { Tabs } from "./Tabs.tsx" import type { TabItem, TabLinkItem } from "./tabItems.ts" const BAY_TABS: TabItem[] = [ { content: ( ), key: "progress", label: "Progress", }, { content: (

14:02:11 AACS handshake complete, reading…

), key: "log", label: "Log", }, { content: (

Blade Runner (1982) · 9 titles · MakeMKV 1.17.8

), key: "disc", label: "Disc", }, ] const meta = { title: "Components/Layout/Tabs", component: Tabs, parameters: { layout: "padded" }, argTypes: { activation: toStoryChoice([ "automatic", "manual", ] as const), orientation: toStoryChoice([ "horizontal", "vertical", ] as const), }, args: { activation: "automatic", orientation: "horizontal", }, } satisfies Meta export default meta type Story = StoryObj export const Playground: Story = { parameters: playgroundParameters, args: { label: "Bay 3", tabs: BAY_TABS }, } export const AllVariants: Story = { args: { label: "Bay 3", tabs: BAY_TABS }, render: () => ( ), } const STATE_TABS: TabItem[] = [ ...BAY_TABS, { content: (

Unreachable — this bay has no verdict yet.

), isDisabled: true, key: "verdict", label: "Verdict", }, { content: (
1 retry AACS
), key: "flags", label: "Flags", }, ] /** * A disabled tab is out of the *focus* group and still one of the * *options* — it owns a panel and an id either way. Registration is * membership, so the arrow keys skip it with nothing in * `RovingFocus` knowing the word "disabled". */ export const AllStates: Story = { args: { label: "Bay 3", tabs: STATE_TABS }, } /** * A tab bar **scrolls**, it does not wrap. A wrapped tablist puts * tabs on two rows, which breaks both the visual row and the * mental model the arrow keys give — "right" stops meaning right. * * `ContainerBoard` is used here as a width harness rather than as * a container-query claim: `Tabs` declares no container, because * nothing about it needs to *know* its width. It just has to * survive being narrow. */ export const Responsive: Story = { args: { label: "Bay 3", tabs: STATE_TABS }, render: () => ( {(width) => ( )} ), } /** * The falsification point, and the reason `Tabs` is P0. * * In `manual`, an arrow key moves focus to a tab that is *not* * chosen — a state a three-kind model cannot represent at all, * because it had one notion of "the current one" doing both jobs. * Arrow through this one and watch the underline stay put until * Enter. */ export const Manual: Story = { args: { activation: "manual", label: "Bay 3 manual", tabs: BAY_TABS, }, } const BAY_ROUTE_TABS: TabLinkItem[] = [ { href: "/bays/3", label: "Overview", }, { href: "/bays/3/titles", label: "Titles", }, { href: "/bays/3/tracks", label: "Tracks", }, { href: "/bays/3/log", label: "Log", }, ] /** * A tab that is a **place**. Every trigger is a real ``, so * middle-click, ctrl-click, "open in a new tab" and "copy link * address" all work — and reloading the page comes back to the same * section, which is the whole reason to route one. * * The bar is a named `