import { expect, within } from "storybook/test"; import type { Meta, StoryObj } from "@storybook/react-vite"; import type { ReactNode } from "react"; import { Box } from "../containers/Box"; import { Story } from "../story-components/Story"; import { CodeBlock } from "./CodeBlock"; type ThisStory = StoryObj; export default { title: "alouette/Data/CodeBlock", component: CodeBlock, parameters: { componentSubtitle: "A block of code on the lowered layer, scrolling horizontally instead of wrapping", }, argTypes: { title: { description: "Label above the code — a file name or a language", control: "text", }, size: { description: "The size of the code text", control: "inline-radio", options: ["sm", "md"], table: { defaultValue: { summary: "md" } }, }, wrap: { description: "Wrap long lines instead of scrolling them — for content read end to end, like a shell command", control: "boolean", table: { defaultValue: { summary: "false" } }, }, children: { description: "The code", control: "text" }, }, } satisfies Meta; export const CodeBlockPreviewStory: ThisStory = { name: "CodeBlock Preview", parameters: { layout: "padded", chromatic: { disableSnapshot: true }, }, args: { title: "theme.ts", children: `export const theme = { accent: "brand", };`, }, render: (args) => , }; interface ThemeSnippetProps { size?: "md" | "sm"; title?: ReactNode; } function ThemeSnippet({ size, title }: ThemeSnippetProps): ReactNode { return ( {`import { writeTheme } from "alouette/theme-generator"; writeTheme({ outDir: "./src", overrides: { brand: { hue: 280 } } });`} ); } export const CodeBlockVariantsStory: ThisStory = { name: "CodeBlock Variants", render: () => ( pnpm --filter alouette build:css { "const { css, oklchCss, themeVariables, oklchThemeVariables } = generateTheme({ brand: { hue: 280, chroma: 0.14 }, danger: { hue: 25 } });" } curl -fsSL https://raw.githubusercontent.com/christophehurpeau/alouette/main/scripts/install.sh | bash -s -- --prefix=/usr/local/share/alouette ), }; export const CodeBlockTestsStory: ThisStory = { name: "CodeBlock Tests", render: () => ( pnpm add alouette scrolling --long-line-that-overflows-the-block-and-scrolls-sideways wrapping --long-line-that-overflows-the-block-and-wraps-onto-several-lines ), play: async ({ canvasElement }) => { const canvas = within(canvasElement); const code = canvas.getByText("pnpm add alouette"); // react-native-web maps role="code" onto a real element. await expect(code.tagName).toBe("CODE"); await expect(canvas.getByText("install.sh")).toBeTruthy(); const scrolling = canvas.getByText(/^scrolling/); await expect(getComputedStyle(scrolling).whiteSpace).toBe("pre"); const wrapping = canvas.getByText(/^wrapping/); await expect(wrapping.tagName).toBe("CODE"); await expect(getComputedStyle(wrapping).whiteSpace).toBe("pre-wrap"); await expect(getComputedStyle(wrapping).overflowWrap).toBe("anywhere"); const frame = wrapping.parentElement; if (!frame) throw new Error("CodeBlock frame not found"); await expect(wrapping.getBoundingClientRect().right).toBeLessThanOrEqual( frame.getBoundingClientRect().right, ); }, };