import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters"
import type { Meta, StoryObj } from "@storybook/react"
import type { ReactNode } from "react"
import {
controlSizeArgType,
intentArgType,
} from "../argTypes.storyHelpers.ts"
import { Button } from "../Button/Button.tsx"
import {
ContainerBoard,
StoryCell,
StoryGrid,
StoryRow,
StorySection,
} from "../board.storyHelpers.tsx"
import {
ArrowRightIcon,
ExternalIcon,
} from "../icons.storyHelpers.tsx"
import type { IntentAppearance } from "../intentStyles.ts"
import { RouterLinkProvider } from "../RouterLink/RouterLinkProvider.tsx"
import type { RouterLinkProps } from "../RouterLink/routerLink.ts"
import { ButtonLink } from "./ButtonLink.tsx"
/**
* A stand-in for react-router's `` — the marker attribute is
* how the board (and `ButtonLink.test.tsx`) shows which destinations
* the injected router was handed.
*/
const SoftRouterLink = ({
href,
...linkProps
}: RouterLinkProps): ReactNode => (
)
const INTENTS = [
"neutral",
"accent",
"success",
"warning",
"danger",
"info",
] as const
const APPEARANCES: IntentAppearance[] = [
"solid",
"soft",
"outline",
"ghost",
]
const meta = {
title: "Components/Actions/ButtonLink",
component: ButtonLink,
parameters: { layout: "padded" },
argTypes: {
intent: intentArgType,
size: controlSizeArgType,
},
// The component's own defaults, restated. Storybook has not
// seeded `args` from a docgen `defaultValue` since v7, so without
// this the props table prints `"solid"` in the Default column
// while the radio beside it has nothing selected.
args: {
appearance: "solid",
href: "/channels/settings",
intent: "accent",
isDisabled: false,
isExternal: false,
isFullWidth: false,
size: "md",
},
} satisfies Meta
export default meta
type Story = StoryObj
export const Playground: Story = {
parameters: playgroundParameters,
args: { children: "Configure" },
}
/**
* The claim this component exists to make, side by side: a
* `ButtonLink` and a `Button` with identical visual props are the
* same pixels, and one of them is an ``.
*
* `ButtonLink.test.tsx` compares their computed styles rather than
* trusting this board — but the board is where a human sees it.
*/
export const BesideAButton: Story = {
args: { children: "Configure" },
render: (buttonLinkProps) => (
),
}
export const AllVariants: Story = {
args: { children: "Configure" },
render: (buttonLinkProps) => (
{APPEARANCES.flatMap((appearance) =>
INTENTS.map((intent) => (
{intent}
)),
)}
),
}
export const AllSizes: Story = {
args: { children: "Configure" },
render: (buttonLinkProps) => (
Small
Medium
Large
),
}
/**
* Hover, active, and focus are real here, not simulated: the
* pseudo-states addon forces them, which is the only way to review a
* hover colour in a static board.
*
* There is no `loading` cell, and that is the design: a navigation has
* no pending state this component owns.
*/
export const AllStates: Story = {
args: { children: "Configure" },
parameters: {
pseudo: {
active: ["#active"],
focusVisible: ["#focus-target"],
hover: ["#hover"],
},
},
render: (buttonLinkProps) => (
}
/>
),
}
/**
* Plex Channels' actual control. It reads as the primary action on the
* card and it goes to another page, so it is an `` — today it is a
* `