import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters" import type { Meta, StoryObj } from "@storybook/react" import { intentArgType, toStoryChoice, } from "../argTypes.storyHelpers.ts" import { Button } from "../Button/Button.tsx" import { ContainerBoard, StoryCell, StoryGrid, StorySection, } from "../board.storyHelpers.tsx" import { Alert } from "./Alert.tsx" const INTENTS = [ "neutral", "accent", "success", "warning", "danger", "info", ] as const const meta = { title: "Components/Feedback/Alert", component: Alert, parameters: { layout: "padded" }, argTypes: { intent: intentArgType, size: toStoryChoice(["sm", "md"] as const), }, // The component's own defaults, restated — Storybook does not seed // `args` from docgen, so an unstated default shows in the props // table with nothing selected in its control. args: { intent: "neutral", size: "md", }, } satisfies Meta export default meta type Story = StoryObj /** * rip-deck's grouped tower alert, verbatim: one trouble, the bays it * touches, and whether the house speakers already said it out loud. */ export const Playground: Story = { parameters: playgroundParameters, args: { description: "4 bays · 3, 4, 5, 6 · confirmed", heading: "Four bays stalled at once — check the USB hub's power", intent: "danger", }, } export const AllVariants: Story = { args: { heading: "The disc may need cleaning" }, render: (alertProps) => ( {INTENTS.map((intent) => ( ))} ), } /** * Every part is optional except the sentence, and `size="sm"` is the * in-card form — rip-deck's verdict chip, which sits under a bay's * progress bar rather than at the top of the page. */ export const AllStates: Story = { args: { heading: "The disc may need cleaning" }, render: (alertProps) => ( Open trays } description="2 discs · slots 4, 7" heading="There are still discs in the tower" intent="info" /> ), } /** * The `@container` claim: actions sit beside the sentence when there * is room and drop under it when there is not — and the width that * decides is the **panel's**, not the window's. A banner in a * sidebar and the same banner full-bleed is exactly the pair a media * query cannot tell apart. */ export const Responsive: Story = { args: { description: "2 discs · slots 4, 7", heading: "There are still discs in the tower", intent: "info", }, render: (alertProps) => ( {(width) => ( Open trays } label={`Discs still in the tower at ${width}`} /> )} ), } /** * An alert is not interactive, so what there is to drive is what it * *contains*. The action is an ordinary `Button` and stays reachable * by role and name from inside the landmark — which is the whole * reason `label` exists. */ export const Interactive: Story = { args: { details: [ "3 read errors in 40 s", "throughput 1.2x against a 6.0x baseline", ], heading: "Bay 7 is reading with errors — clean the disc", intent: "warning", label: "Bay 7 verdict", }, render: (alertProps) => ( Retry in another bay } /> ), }