import { connectionTransitions, useStatus, } from "@charcuterie/logic" import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters" import type { Meta, StoryObj } from "@storybook/react" import { connectionStatusArgType } from "../argTypes.storyHelpers.ts" import { Button } from "../Button/Button.tsx" import { ContainerBoard, StoryCell, StoryGrid, StoryRow, StorySection, } from "../board.storyHelpers.tsx" import { Card } from "../Card/Card.tsx" import { LiveStatusIndicator } from "./LiveStatusIndicator.tsx" const CONNECTION_STATUSES = [ "connecting", "connected", "reconnecting", "disconnected", ] as const const meta = { title: "Components/Feedback/LiveStatusIndicator", component: LiveStatusIndicator, parameters: { layout: "padded" }, argTypes: { status: connectionStatusArgType }, args: { isLabelVisible: true, size: "md" }, } satisfies Meta export default meta type Story = StoryObj /** * A named live region, plus a `data-status` attribute — the stable * handle for a Playwright assertion, because it survives translation * where the visible wording does not. */ export const Playground: Story = { parameters: playgroundParameters, args: { status: "connected" }, } /** * The four states, and the distinction four repos currently lose: * `connecting` is blue and cold-start, `reconnecting` is amber and * means "you had data, I am getting it back". Collapsing them is why * a flaky link reads wrong today. */ export const AllVariants: Story = { args: { status: "connected" }, render: (indicatorProps) => ( {CONNECTION_STATUSES.map((status) => ( ))} ), } export const AllStates: Story = { args: { status: "reconnecting" }, render: (indicatorProps) => ( {/* `stretch`, because `Card` declares a container query. A default `start` cell is shrink-to-fit, and `container-type: inline-size` forbids the element from being sized by its own contents — so the card collapses to min-content and "16 bays · 4 ripping" wraps after every word. `storyRules.test.ts` now fails on this. */} } heading="Tower" >

16 bays · 4 ripping

), } export const Responsive: Story = { args: { detail: "3 of 4 bays reporting", status: "reconnecting", }, render: (indicatorProps) => ( ), } const ConnectionLifecycle = () => { const { can, status, transitionTo } = useStatus({ initialState: "connecting", transitions: connectionTransitions, }) return (
{CONNECTION_STATUSES.map((next) => ( ))}

Buttons disable themselves on illegal edges — `connected → connecting` is not one, because a live link that wants to reconnect goes through `reconnecting`.

) } /** * The live region, driven. Each click is a real transition through * `connectionTransitions`, and the indicator's wording, colour, and * whether the dot moves all follow from the state rather than from * four independent booleans. */ export const Interactive: Story = { args: { status: "connecting" }, render: () => , }