import type { ColorSchemeMode } from "@charcuterie/logic" import { playgroundParameters } from "@charcuterie/storybook-config/story-parameters" import type { Meta, StoryObj } from "@storybook/react" import { useState } from "react" import { controlSizeArgType, intentArgType, } from "../argTypes.storyHelpers.ts" import { ContainerBoard, StoryCell, StoryGrid, StoryRow, StorySection, } from "../board.storyHelpers.tsx" import { MonitorIcon, MoonIcon, SunIcon, } from "../icons.storyHelpers.tsx" import type { ColorSchemeIcons } from "./ColorSchemeToggle.tsx" import { ColorSchemeToggle } from "./ColorSchemeToggle.tsx" /** * The library ships **no icons** — these are the story-only * hand-drawn SVGs an app would replace with lucide `Sun` / `Moon` / * `Monitor`. */ const ICONS: ColorSchemeIcons = { dark: , light: , system: , } const meta = { title: "Utilities/ColorSchemeToggle", component: ColorSchemeToggle, parameters: { layout: "padded" }, argTypes: { intent: intentArgType, // `mode` is `ColorSchemeMode` from @charcuterie/logic — a bare // specifier docgen cannot enumerate, so it gets an explicit // radio rather than falling through to the object control. mode: { control: "radio", options: ["light", "dark", "system"], }, size: controlSizeArgType, }, args: { appearance: "ghost", icons: ICONS, intent: "neutral", isDisabled: false, mode: "system", onCycle: () => {}, size: "md", }, } satisfies Meta export default meta type Story = StoryObj /** * Controlled and self-contained: this story owns the mode in local * state and advances it on each press, which is what a plain * consumer wires up. `` wires the same * `onCycle` to the `useColorScheme` hook instead. * * The accessible name states the current mode and the next one, so * it changes as the button cycles — that is what the test asserts. */ export const Playground: Story = { parameters: playgroundParameters, render: (toggleProps) => { const [mode, setMode] = useState("system") return ( ) }, } /** * Each mode's icon, held fixed so the three glyphs are visible at * once — light is the sun, dark the moon, system the monitor. */ export const AllModes: Story = { render: (toggleProps) => ( {}} /> {}} /> {}} /> ), } /** * The tone is **neutral by default** — a scheme switcher is toolbar * chrome, so its ghost hover is `hover:bg-intent-neutral-surface` and * its icon `text-intent-neutral-content`, which read as chrome on a * normal surface rather than as an accent action. A consumer that * wants it to draw attention passes `intent="accent"` (or any tone). */ export const Intents: Story = { render: (toggleProps) => ( {}} /> {}} /> ), } export const Sizes: Story = { render: (toggleProps) => ( {}} size="sm" /> {}} size="md" /> {}} size="lg" /> ), } export const Responsive: Story = { render: (toggleProps) => ( {}} /> ), }