diff --git a/src/components/ui/__stories__/Accordion.stories.tsx b/src/components/ui/__stories__/Accordion.stories.tsx new file mode 100644 index 00000000000..e34c43e6cc0 --- /dev/null +++ b/src/components/ui/__stories__/Accordion.stories.tsx @@ -0,0 +1,164 @@ +import type { Meta, StoryObj } from "@storybook/nextjs" + +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "../accordion" + +const meta = { + title: "UI / Accordion", + component: Accordion, + decorators: [ + (Story) => ( +
+ +
+ ), + ], + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + component: + "Vertically-stacked disclosure built on Radix Accordion. `type='single'` allows only one open at a time (with optional `collapsible`); `type='multiple'` allows any combination. The chevron icon flips for RTL via `:dir(rtl)` and rotates open via `data-state=open`. Pass `hideIcon` to suppress the chevron and provide your own visual cue.", + }, + }, + }, +} satisfies Meta + +export default meta + +type Story = StoryObj + +const SAMPLE = [ + { + id: "item-1", + title: "What is Ethereum?", + body: "Ethereum is open access to digital money and data-friendly services for everyone -- no matter your background or location.", + }, + { + id: "item-2", + title: "What is a layer 2?", + body: "Layer 2 networks scale Ethereum by handling transactions off the main chain while inheriting its security guarantees.", + }, + { + id: "item-3", + title: "What is a validator?", + body: "Validators secure the network by proposing and attesting to blocks.", + }, +] + +export const SingleCollapsible: Story = { + parameters: { + docs: { + description: { + story: + "`type='single' collapsible` allows only one item open at a time, with the option to close the active item.", + }, + }, + }, + render: () => ( + + {SAMPLE.map((item) => ( + + {item.title} + {item.body} + + ))} + + ), +} + +export const Multiple: Story = { + parameters: { + docs: { + description: { + story: + "`type='multiple'` allows any combination of items to be open simultaneously.", + }, + }, + }, + render: () => ( + + {SAMPLE.map((item) => ( + + {item.title} + {item.body} + + ))} + + ), +} + +export const HideIcon: Story = { + parameters: { + docs: { + description: { + story: + "`hideIcon` on `AccordionTrigger` removes the default chevron. Useful when supplying a custom visual cue.", + }, + }, + }, + render: () => ( + + {SAMPLE.map((item) => ( + + {item.title} + {item.body} + + ))} + + ), +} + +export const CustomTrigger: Story = { + parameters: { + docs: { + description: { + story: + "Build a custom trigger by passing structured children to `AccordionTrigger`. The default chevron stays at the end.", + }, + }, + }, + render: () => ( + + {SAMPLE.map((item, idx) => ( + + + + + {idx + 1} + + {item.title} + + + {item.body} + + ))} + + ), +} + +export const RtlChevron: Story = { + parameters: { + docs: { + description: { + story: + "The chevron uses `ChevronNext`, which rotates for RTL locales via `:dir(rtl)`. Toggle the locale in the Storybook toolbar to see the flip.", + }, + }, + }, + render: () => ( + + + Toggle locale to test RTL flip + + When the locale is RTL (Arabic, Urdu), the chevron points the other + way to match reading direction. + + + + ), +} diff --git a/src/components/ui/__stories__/Alert.stories.tsx b/src/components/ui/__stories__/Alert.stories.tsx index 1004907a00a..197b9e72b8f 100644 --- a/src/components/ui/__stories__/Alert.stories.tsx +++ b/src/components/ui/__stories__/Alert.stories.tsx @@ -1,11 +1,12 @@ import { Info } from "lucide-react" -import { Meta, StoryObj } from "@storybook/nextjs" +import type { Meta, StoryObj } from "@storybook/nextjs" import { Alert, AlertCloseButton, AlertContent, AlertDescription, + AlertEmoji, AlertIcon, AlertTitle, } from "../alert" @@ -15,6 +16,12 @@ const meta = { title: "Molecules / Action Feedback / Alerts", component: Alert, parameters: { + docs: { + description: { + component: + "Inline alert/callout. Six `variant` colors (`info | error | success | warning | update | banner`); `banner` renders edge-to-edge with no border-radius for top-of-page use. Sub-components: `AlertContent`, `AlertTitle`, `AlertDescription`, `AlertIcon` (lucide or other SVG), `AlertEmoji`, `AlertCloseButton`.", + }, + }, layout: "none", }, decorators: [ @@ -35,7 +42,26 @@ const DEMO_DESC = "This is an alert to be used for important information." const VARIANTS = ["info", "error", "success", "warning", "update"] as const +export const Default: Story = { + parameters: { chromatic: { disableSnapshot: true } }, + render: (args) => ( + + + {DEMO_TITLE} + {DEMO_DESC} + + + ), +} + export const Variants: Story = { + parameters: { + docs: { + description: { + story: "All five `variant` options stacked for visual comparison.", + }, + }, + }, render: (args) => (
{VARIANTS.map((variant) => ( @@ -67,6 +93,14 @@ export const WithCloseButton: Story = { } export const WithIcon: Story = { + parameters: { + docs: { + description: { + story: + "`AlertIcon` wraps an SVG icon with `[&>svg]:size-6` to constrain size. Icon color inherits from the variant via the alert's `**:[svg]:text-*` class.", + }, + }, + }, render: (args) => (
{VARIANTS.map((variant) => ( @@ -84,6 +118,41 @@ export const WithIcon: Story = { ), } +export const WithEmoji: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`AlertEmoji` renders the project's `Emoji` component at `text-4xl` aligned to the start of the alert.", + }, + }, + }, + render: (args) => ( +
+ + + + New feature + + Layer 2 network filtering is now live across the dapps directory. + + + + + + + Did you know? + + Validators secure the Ethereum network by proposing and attesting to + blocks. + + + +
+ ), +} + export const Banner: Story = { render: (args) => (
diff --git a/src/components/ui/__stories__/Avatar.stories.tsx b/src/components/ui/__stories__/Avatar.stories.tsx index 45a701ce12f..d5c6a66fb77 100644 --- a/src/components/ui/__stories__/Avatar.stories.tsx +++ b/src/components/ui/__stories__/Avatar.stories.tsx @@ -1,41 +1,94 @@ import type { Meta, StoryObj } from "@storybook/nextjs" -import { Avatar, AvatarGroup } from "../avatar" +import { + Avatar, + AvatarBase, + AvatarFallback, + AvatarGroup, + AvatarImage, +} from "../avatar" import { HStack, VStack } from "../flex" +const SAMPLE = { + name: "Sam Richards", + src: "https://avatars.githubusercontent.com/u/8097623?v=4", + href: "#", +} + const meta = { - title: "Atoms / Media & Icons / Avatars", + title: "UI / Avatar", component: Avatar, + args: SAMPLE, + parameters: { + docs: { + description: { + component: + "User avatar built on Radix Avatar. `Avatar` is the high-level component (link + image + fallback + optional label). The lower-level `AvatarBase` + `AvatarImage` + `AvatarFallback` primitives are exposed for custom compositions. `AvatarGroup` stacks avatars with overlap and an optional `max` cap.", + }, + }, + }, } satisfies Meta export default meta type Story = StoryObj -export const Single: Story = { - args: { - name: "Sam Richards", - src: "https://avatars.githubusercontent.com/u/8097623?v=4", - href: "#", - }, +export const Sizes: Story = { + parameters: { chromatic: { disableSnapshot: true } }, + args: SAMPLE, render: (args) => ( - - {(["lg", "md", "sm", "xs"] as const).map((size) => ( + + {(["xs", "sm", "md", "lg"] as const).map((size) => ( ))} - + ), } -export const Group: Story = { +export const WithLabel: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "When `label` is provided, the avatar renders alongside the label inside a `LinkBox`. `direction: 'row'` (default) is horizontal; `'column'` stacks vertically.", + }, + }, + }, args: { - name: "Sam Richards", - src: "https://avatars.githubusercontent.com/u/8097623?v=4", - href: "#", + ...SAMPLE, + href: "https://github.com/samajammin", + label: "samajammin", }, render: (args) => ( - - {(["sm", "xs"] as const).map((size) => ( + + + {(["md", "sm", "xs"] as const).map((size, idx) => ( + + ))} + + + {(["md", "sm", "xs"] as const).map((size, idx) => ( + + ))} + + + ), +} + +export const Group: Story = { + args: SAMPLE, + parameters: { + docs: { + description: { + story: + "`AvatarGroup` overlaps avatars and renders a `+N` overflow fallback when `max` is exceeded.", + }, + }, + }, + render: (args) => ( + + {(["sm", "md"] as const).map((size) => ( @@ -49,38 +102,66 @@ export const Group: Story = { export const BrokenImageFallback: Story = { args: { - name: "Sam Richards", + ...SAMPLE, src: "https://placehold.co/404error", - href: "#", + }, + parameters: { + docs: { + description: { + story: + "When the image fails to load, `Avatar` swaps to `AvatarImage` (which then falls back to `AvatarFallback` rendering the user's initials).", + }, + }, }, render: (args) => ( - - {(["lg", "md", "sm", "xs"] as const).map((size) => ( + + {(["xs", "sm", "md", "lg"] as const).map((size) => ( ))} - + ), } -export const WithUsername: Story = { - args: { - name: "Sam Richards", - src: "https://avatars.githubusercontent.com/u/8097623?v=4", - href: "https://github.com/samajammin", - label: "samajammin", +export const BasePrimitives: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`AvatarBase`, `AvatarImage`, and `AvatarFallback` exposed for custom compositions. Combine them when the high-level `Avatar` does not fit the use case.", + }, + }, }, - render: (args) => ( - - - {(["md", "sm", "xs"] as const).map((size, idx) => ( - - ))} - - - {(["md", "sm", "xs"] as const).map((size, idx) => ( - - ))} - + render: () => ( + + + + SR + + + + SR + + + ), +} + +export const FallbackOnly: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: "`AvatarFallback` rendered without an image source.", + }, + }, + }, + render: () => ( + + {(["xs", "sm", "md", "lg"] as const).map((size) => ( + + SR + + ))} ), } diff --git a/src/components/ui/__stories__/Button.stories.tsx b/src/components/ui/__stories__/Button.stories.tsx index 1e8db8be06d..57c8b2c3eb0 100644 --- a/src/components/ui/__stories__/Button.stories.tsx +++ b/src/components/ui/__stories__/Button.stories.tsx @@ -5,37 +5,149 @@ import { Button, type ButtonVariantProps } from "../buttons/Button" import { HStack, VStack } from "../flex" const meta = { - title: "Atoms / Form / Buttons", + title: "UI / Button", component: Button, args: { children: "What is Ethereum?", }, + parameters: { + docs: { + description: { + component: + "Action button. `variant`: `solid | outline | ghost | link`. `size`: `lg | md | sm`. `isSecondary` switches the text/border tone from primary to body color, but is a no-op on `solid` and `link`. Pass `asChild` to render as another element (e.g. anchor) while keeping the button styling.", + }, + }, + }, } satisfies Meta export default meta type Story = StoryObj -const variants: ButtonVariantProps["variant"][] = [ +const VARIANTS: ButtonVariantProps["variant"][] = [ "solid", "outline", "ghost", "link", ] -export const StyleVariants: Story = { +const SIZES: ButtonVariantProps["size"][] = ["lg", "md", "sm"] + +export const Default: Story = { + parameters: { chromatic: { disableSnapshot: true } }, +} + +export const Variants: Story = { + parameters: { chromatic: { disableSnapshot: true } }, render: (args) => ( - - {variants.map((variant) => ( + + {VARIANTS.map((variant) => ( + + + ))} + + ), +} + +export const AsChild: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`asChild` renders the button styling on the child element. Useful for wrapping non-button elements (anchors, custom components) without losing button styles.", + }, + }, + }, + render: () => ( + + + + + ), +} + export const IconVariants: Story = { render: (args) => ( diff --git a/src/components/ui/__stories__/ButtonLink.stories.tsx b/src/components/ui/__stories__/ButtonLink.stories.tsx index 3fa557a06ee..44f5bd91c9c 100644 --- a/src/components/ui/__stories__/ButtonLink.stories.tsx +++ b/src/components/ui/__stories__/ButtonLink.stories.tsx @@ -1,17 +1,128 @@ import type { Meta, StoryObj } from "@storybook/nextjs" -import { ButtonLink as ButtonLinkComponent } from "../buttons/Button" +import { ButtonLink, type ButtonVariantProps } from "../buttons/Button" +import { HStack, VStack } from "../flex" const meta = { - title: "Atoms / Form / Buttons", - component: ButtonLinkComponent, -} satisfies Meta + title: "UI / ButtonLink", + component: ButtonLink, + args: { + href: "#", + children: "What is Ethereum?", + }, + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + component: + "Anchor styled as a `Button`. Same `variant`, `size`, and `isSecondary` props as `Button`. Inherits auto-detected behaviors from `BaseLink`: external links open in a new tab, file links get a download icon, hash links smooth-scroll within the page.", + }, + }, + }, +} satisfies Meta export default meta -export const ButtonLink: StoryObj = { +type Story = StoryObj + +const VARIANTS: ButtonVariantProps["variant"][] = [ + "solid", + "outline", + "ghost", + "link", +] + +const SIZES: ButtonVariantProps["size"][] = ["lg", "md", "sm"] + +export const Default: Story = {} + +export const Variants: Story = { + render: (args) => ( + + {VARIANTS.map((variant) => ( + + {variant} + + ))} + + ), +} + +export const Sizes: Story = { + render: (args) => ( + + {SIZES.map((size) => ( + + ))} + + ), +} + +export const IsSecondary: Story = { + parameters: { + docs: { + description: { + story: + "Same `isSecondary` semantics as `Button`: no-op on `solid` and `link`.", + }, + }, + }, + render: (args) => ( + + {VARIANTS.map((variant) => ( + + + {variant} + + + {variant} + isSecondary + + + ))} + + ), +} + +export const ExternalLink: Story = { + parameters: { + docs: { + description: { + story: + "External URLs open in a new tab and get a small external-link arrow appended via `BaseLink`'s auto-detection.", + }, + }, + }, args: { - href: "#", - children: "What is Ethereum?", + href: "https://ethresear.ch", + children: "ethresear.ch", + }, +} + +export const FileDownload: Story = { + parameters: { + docs: { + description: { + story: + "URLs ending in a recognized file extension are detected by `BaseLink` and rendered with a download icon.", + }, + }, + }, + args: { + href: "/ethereum-whitepaper.pdf", + children: "Download whitepaper", + }, +} + +export const HashLink: Story = { + parameters: { + docs: { + description: { + story: "Hash-only hrefs scroll within the page rather than navigating.", + }, + }, + }, + args: { + href: "#section", + children: "Jump to section", }, } diff --git a/src/components/ui/__stories__/EdgeScrollContainer.stories.tsx b/src/components/ui/__stories__/EdgeScrollContainer.stories.tsx index ae71bdaf8a6..efe4cb50459 100644 --- a/src/components/ui/__stories__/EdgeScrollContainer.stories.tsx +++ b/src/components/ui/__stories__/EdgeScrollContainer.stories.tsx @@ -1,12 +1,11 @@ -import { Meta, StoryObj } from "@storybook/nextjs" +import type { Meta, StoryObj } from "@storybook/nextjs" import { EdgeScrollContainer, EdgeScrollItem } from "../edge-scroll-container" const meta = { - title: "Molecules / Navigation / EdgeScrollContainer", + title: "UI / EdgeScrollContainer", component: EdgeScrollContainer, decorators: [ - // Simulate page container to demonstrate edge-to-edge effect (Story) => (
@@ -15,6 +14,12 @@ const meta = { ], parameters: { layout: "fullscreen", + docs: { + description: { + component: + "Horizontal scroll container that bleeds to the screen edges while keeping content aligned with the page gutter. Items snap by default; pass `snap={false}` to disable. CSS variables (`--edge-spacing`, `--edge-mask-size`, `--edge-overflow-y-pad`) are configurable via props or `className` for responsive overrides.", + }, + }, }, } satisfies Meta @@ -30,7 +35,8 @@ const SampleCard = ({ children }: { children: React.ReactNode }) => ( const cardsArray = Array.from({ length: 10 }).map((_, idx) => idx + 1) -export const Basic: Story = { +export const Default: Story = { + parameters: { chromatic: { disableSnapshot: true } }, render: () => ( {cardsArray.map((i) => ( @@ -43,6 +49,14 @@ export const Basic: Story = { } export const WithoutSnap: Story = { + parameters: { + docs: { + description: { + story: + "`snap={false}` disables snap-mandatory scrolling. Use for free-scroll content where snap points would feel constrained.", + }, + }, + }, render: () => ( {cardsArray.map((i) => ( @@ -54,17 +68,68 @@ export const WithoutSnap: Story = { ), } -export const AsChildExample: Story = { +export const AsChild: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`EdgeScrollItem asChild` renders the wrapper as the child element so each card can be a single `` with the same scroll-snap behavior.", + }, + }, + }, render: () => ( {cardsArray.map((i) => ( - - Clickable Card {i} - + Clickable card {i} + + + ))} + + ), +} + +export const CustomSpacing: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "Override edge spacing via the `spacing` prop. For responsive overrides, pass via `className` (e.g. `[--edge-spacing:0.5rem] md:[--edge-spacing:1rem]`).", + }, + }, + }, + render: () => ( + + {cardsArray.map((i) => ( + + Card {i} + + ))} + + ), +} + +export const FewItems: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "When content does not overflow, the container behaves like a regular flex row. Useful for confirming the no-scroll state.", + }, + }, + }, + render: () => ( + + {[1, 2].map((i) => ( + + Card {i} ))} diff --git a/src/components/ui/__stories__/Link.stories.tsx b/src/components/ui/__stories__/Link.stories.tsx index d99ac27fc4d..726413b9adb 100644 --- a/src/components/ui/__stories__/Link.stories.tsx +++ b/src/components/ui/__stories__/Link.stories.tsx @@ -1,12 +1,12 @@ -import { Meta, StoryObj } from "@storybook/nextjs" +import type { Meta, StoryObj } from "@storybook/nextjs" -import { Center, Stack } from "../flex" -import Link from "../Link" +import { Center, Stack, VStack } from "../flex" +import InlineLink, { BaseLink, LinkWithArrow } from "../Link" import { ListItem, UnorderedList } from "../list" const meta = { - title: "Molecules / Navigation / Links", - component: Link, + title: "UI / Link", + component: InlineLink, decorators: [ (Story) => (
@@ -14,7 +14,15 @@ const meta = {
), ], -} satisfies Meta + parameters: { + docs: { + description: { + component: + "Link variants. `InlineLink` (default export) is the in-prose link with visited styling. `BaseLink` is the underlying primitive without visited styling -- use for nav/CTA contexts. `LinkWithArrow` appends a chevron that flips for RTL locales. All three auto-detect external URLs (open in new tab + external icon), `mailto:` (mail icon), and recognized file extensions (download icon).", + }, + }, + }, +} satisfies Meta export default meta @@ -22,45 +30,157 @@ type Story = StoryObj const MockParagraph = ({ href }: { href: string }) => (

- Text body normal. Ethereum is open access to digital money and data-friendly - services for everyone – no matter your background or location. - It's a community-built technology behind the + Ethereum is open access to digital money and data-friendly services for + everyone -- no matter your background or location. It is a{" "} + community-built technology behind the cryptocurrency ether (ETH) and thousands of applications you can use today.

) -export const InternalLink: Story = { - args: { - href: "#", +export const InlineLinkStory: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`InlineLink` (default export of `Link.tsx`). Use in prose; the visited state is preserved.", + }, + }, }, + name: "InlineLink", + args: { href: "#" }, render: (args) => , } -export const ExternalLink: Story = { - args: { - href: "https://example.com", +export const BaseLinkStory: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`BaseLink` is the underlying anchor without visited styling. Use in nav, CTA, or non-prose contexts.", + }, + }, + }, + name: "BaseLink", + render: () => ( + + Internal nav link + External nav link + mailto: link + + ), +} + +export const LinkWithArrowStory: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`LinkWithArrow` appends a chevron that flips for RTL locales (Arabic, Urdu). Toggle the locale in the Storybook toolbar to see the flip.", + }, + }, + }, + name: "LinkWithArrow", + render: () => ( + + Read more + Explore dapps + + ), +} + +export const ExternalDetection: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "External URLs (anything outside the site origin) open in a new tab and get an external-link icon.", + }, + }, }, + args: { href: "https://example.com" }, render: (args) => , } +export const MailtoDetection: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "`mailto:` URLs are detected and rendered with a mail icon by `BaseLink`.", + }, + }, + }, + render: () => ( +

+ Send feedback to{" "} + hello@example.com + . +

+ ), +} + +export const FileExtensionDetection: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: + "Recognized file extensions (e.g. `.pdf`) trigger download styling and a new-tab open behavior.", + }, + }, + }, + render: () => ( +

+ Read the{" "} + + Ethereum whitepaper + {" "} + for the original design rationale. +

+ ), +} + +export const HashLink: Story = { + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + story: "Hash-only hrefs scroll within the page rather than navigating.", + }, + }, + }, + render: () => ( +

+ Skip to the summary for the + bottom-line answer. +

+ ), +} + export const LinkList: Story = { + parameters: { + docs: { + description: { + story: + "Realistic list of mixed internal and external links to confirm visited styling and external-icon placement.", + }, + }, + }, render: () => ( -

- Text body normal. Ethereum is open access to digital money and - data-friendly services for everyone – no matter your background or - location. It's a community-built technology behind the - cryptocurrency ether (ETH) and thousands of applications you can use - today. -

- - {Array.from({ length: 9 }).map((_, idx) => ( + + {Array.from({ length: 6 }).map((_, idx) => ( - {`List Item ${idx % 2 === 0 ? "External" : "Internal"} ${ + >{`List item ${idx % 2 === 0 ? "external" : "internal"} ${ idx + 1 - }`} + }`} ))} diff --git a/src/components/ui/__stories__/Table/Table.stories.tsx b/src/components/ui/__stories__/Table/Table.stories.tsx index 195a5425127..724e7d27a54 100644 --- a/src/components/ui/__stories__/Table/Table.stories.tsx +++ b/src/components/ui/__stories__/Table/Table.stories.tsx @@ -1,7 +1,7 @@ -import { Meta, StoryObj } from "@storybook/nextjs" +import type { Meta, StoryObj } from "@storybook/nextjs" import { Flex } from "../../flex" -import { Table as TableComponent } from "../../table" +import { Table } from "../../table" import { MdxDemoData, @@ -10,44 +10,79 @@ import { } from "./mockMdxData" const meta = { - title: "Molecules / Display Content / Tables", - component: TableComponent, + title: "UI / Table", + component: Table, decorators: [ (Story) => ( - + ), ], -} satisfies Meta + parameters: { + docs: { + description: { + component: + "Tabular data primitive. Six `variant` styles cover most layouts: `simple` (default, header bg), `minimal` (no header bg), `simple-striped`, `minimal-striped`, `product` (sm text, hover row), `highlight-first-column`.", + }, + }, + }, +} satisfies Meta export default meta type Story = StoryObj -export const Tables: Story = { +export const Simple: Story = { + parameters: { chromatic: { disableSnapshot: true } }, + args: { variant: "simple", children: }, +} + +export const Minimal: Story = { + parameters: { chromatic: { disableSnapshot: true } }, + args: { variant: "minimal", children: }, +} + +export const SimpleStriped: Story = { + parameters: { chromatic: { disableSnapshot: true } }, + args: { variant: "simple-striped", children: }, +} + +export const MinimalStriped: Story = { + parameters: { chromatic: { disableSnapshot: true } }, + args: { variant: "minimal-striped", children: }, +} + +export const Product: Story = { + parameters: { chromatic: { disableSnapshot: true } }, + args: { variant: "product", children: }, +} + +export const HighlightFirstColumn: Story = { + parameters: { chromatic: { disableSnapshot: true } }, args: { - children: , + variant: "highlight-first-column", + children: , }, - render: (args) => ( - <> - - - - - - ), } -export const MockDocContent: StoryObj = { +export const MockDocContent: Story = { + parameters: { + docs: { + description: { + story: + "Realistic doc-content composition using the markdown table mock data.", + }, + }, + }, render: () => ( <> - + - - +
+ - +
), } diff --git a/src/components/ui/__stories__/Tag.stories.tsx b/src/components/ui/__stories__/Tag.stories.tsx index 1c5c4264fd3..bf590a76713 100644 --- a/src/components/ui/__stories__/Tag.stories.tsx +++ b/src/components/ui/__stories__/Tag.stories.tsx @@ -1,60 +1,96 @@ -import { Meta, StoryObj } from "@storybook/nextjs" +import type { Meta, StoryObj } from "@storybook/nextjs" import { HStack, VStack } from "../flex" -import { Tag, TagButton } from "../tag" +import { Tag, TagButton, TagsInlineText } from "../tag" const meta = { - title: "Molecules / Display Content / Tags", + title: "UI / Tag", component: Tag, + parameters: { + chromatic: { disableSnapshot: true }, + docs: { + description: { + component: + "Pill-style label. Combines `status` (color), `variant` (fill style), and `size`. `Tag` renders a `
`; `TagButton` renders a `