import { expect, within } from "storybook/test";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { Box } from "../containers/Box";
import { View } from "../primitives/View";
import { Story } from "../story-components/Story";
export default {
title: "alouette/Feedback/Skeleton",
parameters: {
componentSubtitle:
"The `skeleton` utility: a pulsing placeholder standing in for content still loading.",
docs: {
description: {
component: `### Usage
~~~tsx
~~~
- \`skeleton\` is \`animate-pulse rounded-sm bg-lowered\`: size it with \`w-*\` / \`h-*\`, round it differently with a \`rounded-*\` written after it
- A bar announces nothing: the region it stands in for carries \`role="status"\` and an \`aria-label\`
- The pulse stops under reduced motion, like every alouette animation`,
},
},
},
} satisfies Meta;
function SkeletonList() {
return (
);
}
function SkeletonCard() {
return (
);
}
export const PreviewSkeletonStory: StoryObj = {
name: "Skeleton Preview",
parameters: { chromatic: { disableSnapshot: true } },
render: () => ,
};
export const VariantsSkeletonStory: StoryObj = {
name: "Skeleton Variants",
render: () => (
),
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const [list] = canvas.getAllByRole("status", { name: "Loading list" });
const bar = list?.firstElementChild;
if (!bar) throw new Error("expected a skeleton bar");
const style = getComputedStyle(bar);
await expect(style.animationName).toBe("pulse");
await expect(style.animationIterationCount).toBe("infinite");
await expect(style.backgroundColor).not.toBe("rgba(0, 0, 0, 0)");
// A rounded-* written after it overrides its radius.
const [profile] = canvas.getAllByRole("status", {
name: "Loading profile",
});
const avatar = profile?.firstElementChild;
if (!avatar) throw new Error("expected an avatar placeholder");
await expect(getComputedStyle(avatar).borderRadius).not.toBe(
style.borderRadius,
);
},
};