import { expect, within } from "storybook/test"; import type { Meta, StoryObj } from "@storybook/react-vite"; import { CheckCircleRegularIcon } from "alouette-icons/phosphor-icons/CheckCircle"; import { StarRegularIcon } from "alouette-icons/phosphor-icons/Star"; import { View } from "../primitives/View"; import { Story, accentsWithoutNeutral } from "../story-components/Story"; import { Bullet } from "./Bullet"; type ThisStory = StoryObj; export default { title: "alouette/Data/Bullet", component: Bullet, parameters: { componentSubtitle: "A list item pairing an accent icon with text", }, argTypes: { icon: { description: "The leading icon", control: false }, children: { description: "The content of the bullet", control: "text" }, }, } satisfies Meta; export const BulletPreviewStory: ThisStory = { name: "Bullet Preview", parameters: { layout: "padded", chromatic: { disableSnapshot: true }, }, args: { icon: , children: "Works on web, iOS and Android", }, render: (args) => , play: async ({ canvasElement }) => { const text = within(canvasElement).getByText( "Works on web, iOS and Android", ); const svg = canvasElement.querySelector("svg"); if (!svg) throw new Error("Bullet icon not rendered"); const icon: SVGSVGElement = svg; function measure(): { iconRect: DOMRect; lineTop: number; lineHeight: number; } { return { iconRect: icon.getBoundingClientRect(), lineTop: text.getBoundingClientRect().top, lineHeight: Number.parseFloat(getComputedStyle(text).lineHeight), }; } const root = document.documentElement; try { root.style.fontSize = "16px"; const fits = measure(); await expect( Math.abs( fits.iconRect.top + fits.iconRect.height / 2 - (fits.lineTop + fits.lineHeight / 2), ), ).toBeLessThan(0.1); root.style.fontSize = "14px"; const overflows = measure(); await expect( Math.abs( overflows.iconRect.bottom - (overflows.lineTop + overflows.lineHeight), ), ).toBeLessThan(0.1); } finally { root.style.fontSize = ""; } }, }; export const BulletVariantsStory: ThisStory = { name: "Bullet Variants", render: () => ( }>Consistent UI }>Accessible }>Animated }>Check circle }>Star }> A long bullet whose text wraps onto several lines, so the icon stays aligned with the first line while the text shrinks to the available width. } /> {accentsWithoutNeutral.map((accent) => ( }>{accent} ))} ), };