import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters" import type { Meta, StoryObj } from "@storybook/react" import { useState } from "react" import { StoryCell, StoryGrid, } from "../board.storyHelpers.tsx" import type { SortDirection } from "./SortableTableHeader.tsx" import { SortableTableHeader } from "./SortableTableHeader.tsx" const noop = () => undefined const ROWS = [ { size: "24.1 GB", title: "Blade Runner", year: 1982 }, { size: "31.7 GB", title: "Alien", year: 1979 }, { size: "18.2 GB", title: "Solaris", year: 1972 }, ] const TABLE_CLASS = "w-full border-collapse text-content-primary text-sm" const CELL_CLASS = "border-border-subtle border-b px-3 py-2 text-start" /** * The component owns **only** the header cell, so every story has to * bring its own table. That is the point rather than an * inconvenience: sorting the data is app logic that differs per * column type, and announcing *that* a column is sorted is markup * every table gets wrong the same way. */ const meta = { title: "Components/Data/SortableTableHeader", component: SortableTableHeader, parameters: { layout: "padded" }, args: { onSort: noop }, } satisfies Meta export default meta type Story = StoryObj export const Playground: Story = { parameters: playgroundParameters, args: { children: "Title", direction: "ascending" }, render: (args) => ( Year {ROWS.map((row) => ( ))}
{row.title} {row.year}
), } /** * `aria-sort="none"` on the unsorted columns, not an omitted * attribute. Absent means "this column is not sortable"; `none` * means "sortable, not currently sorted" — and a table mixing the * two tells a screen-reader user the other columns cannot be sorted * at all. */ export const AllVariants: Story = { args: { children: "Title" }, render: () => ( Title Year Size {ROWS.map((row) => ( ))}
{row.title} {row.year} {row.size}
), } export const AllStates: Story = { args: { children: "Title", direction: "ascending" }, render: (args) => (
Blade Runner
), } /** * Click a header and watch `aria-sort` move — exactly one column * ever holds a direction, which is the invariant a hand-rolled * `▲`/`▼` cannot express at all. */ export const Interactive: Story = { args: { children: "Title" }, render: function SortableTable() { const [sort, setSort] = useState<{ column: "title" | "year" direction: SortDirection }>({ column: "title", direction: "ascending" }) const sorted = [...ROWS].sort((first, second) => { const order = sort.column === "title" ? first.title.localeCompare(second.title) : first.year - second.year return sort.direction === "ascending" ? order : -order }) return ( { setSort({ column: "title", direction }) }} > Title { setSort({ column: "year", direction }) }} > Year {sorted.map((row) => ( ))}
{row.title} {row.year}
) }, }