{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "changelog-list",
  "type": "registry:block",
  "title": "Changelog list",
  "description": "A list of releases. Each has a version, a date and its changes, labelled Added, Changed, Fixed, Removed, Deprecated or Security. Every release is its own article with a heading and an anchor.",
  "categories": [
    "section"
  ],
  "registryDependencies": [
    "https://facadeui.dev/r/badge.json",
    "https://facadeui.dev/r/container.json",
    "https://facadeui.dev/r/heading.json",
    "https://facadeui.dev/r/section.json",
    "https://facadeui.dev/r/section-header.json",
    "https://facadeui.dev/r/types.json",
    "https://facadeui.dev/r/utils.json"
  ],
  "files": [
    {
      "path": "src/sections/changelog-list.tsx",
      "type": "registry:component",
      "target": "components/sections/changelog-list.tsx",
      "content": "/**\n * ChangelogList — releases in order, each with its version, date and changes.\n *\n * `CardList` covers \"a grid of linked posts\"; a changelog needs the changes\n * themselves on the page, so readers can scan what moved without a click per\n * release.\n *\n * a11y:\n *\n *  - Each release is an `<article>` named by its own heading, inside an\n *    ordered list, so \"release 2 of 12\" is announced and heading navigation\n *    jumps release to release.\n *  - The date is a `<time>` with a machine-readable `dateTime`.\n *  - The kind of each change (\"Added\", \"Fixed\") is a word in a badge, not a\n *    colour alone. Pass `kindLabels` to translate the words.\n *  - Every release has a stable `id`, `release-v1-2-0` by default, so a\n *    release can be linked to directly.\n *\n * Dependencies: react, @/lib/types, @/lib/utils,\n * @/components/ui/badge, @/components/ui/container, @/components/ui/heading,\n * @/components/ui/section, @/components/ui/section-header.\n */\n\nimport type { ElementType, ReactNode } from \"react\"\n\nimport type {\n  HeadingLevel,\n  LinkComponent,\n  ListSlotProps,\n  SectionBaseProps,\n} from \"@/lib/types\"\nimport { slugId } from \"@/lib/utils\"\nimport { Badge, type BadgeProps } from \"@/components/ui/badge\"\nimport { Container } from \"@/components/ui/container\"\nimport { Heading } from \"@/components/ui/heading\"\nimport { Section } from \"@/components/ui/section\"\nimport { SectionHeader } from \"@/components/ui/section-header\"\n\nexport type ChangeKind =\n  \"added\" | \"changed\" | \"fixed\" | \"removed\" | \"deprecated\" | \"security\"\n\nexport interface ChangelogChange {\n  kind: ChangeKind\n  description: ReactNode\n}\n\nexport interface ChangelogEntry {\n  /** Shown as a badge and used for the anchor id, e.g. \"v1.2.0\". */\n  version: string\n  title: string\n  /** ISO 8601, for the `datetime` attribute. */\n  dateTime: string\n  /** Human label for the date, e.g. \"21 September 2026\". */\n  dateLabel: string\n  summary?: ReactNode\n  changes: ChangelogChange[]\n  /** Links the title, e.g. to the release notes on GitHub. */\n  href?: string\n  external?: boolean\n  /** Anchor id. Defaults to a slug of the version. */\n  id?: string\n  /** A small tag beside the version, such as \"Latest\". */\n  tag?: string\n}\n\nexport interface ChangelogListProps extends SectionBaseProps, ListSlotProps {\n  items: ChangelogEntry[]\n  title?: string\n  eyebrow?: string\n  description?: string\n  link?: LinkComponent\n  /** Heading level of each release. Defaults to one below `headingLevel`. */\n  itemHeadingLevel?: HeadingLevel\n  /** Words for the change kinds, for translation. */\n  kindLabels?: Partial<Record<ChangeKind, string>>\n  align?: \"start\" | \"center\"\n}\n\nconst KIND_LABELS: Record<ChangeKind, string> = {\n  added: \"Added\",\n  changed: \"Changed\",\n  fixed: \"Fixed\",\n  removed: \"Removed\",\n  deprecated: \"Deprecated\",\n  security: \"Security\",\n}\n\nconst KIND_VARIANTS: Record<ChangeKind, BadgeProps[\"variant\"]> = {\n  added: \"default\",\n  changed: \"outline\",\n  fixed: \"muted\",\n  removed: \"destructive\",\n  deprecated: \"outline\",\n  security: \"destructive\",\n}\n\nexport function ChangelogList({\n  items,\n  title,\n  eyebrow,\n  description,\n  link,\n  itemHeadingLevel,\n  kindLabels,\n  align = \"start\",\n  listAs,\n  itemAs,\n  headingLevel = 2,\n  as,\n  spacing = \"md\",\n  className,\n  id,\n}: ChangelogListProps) {\n  const List = (listAs ?? \"ol\") as ElementType\n  const Item = (itemAs ?? \"li\") as ElementType\n  const Link = (link ?? \"a\") as ElementType\n  const titleId = title ? (id ? `${id}-title` : slugId(title)) : undefined\n  const itemLevel = itemHeadingLevel ?? (Math.min(headingLevel + 1, 6) as HeadingLevel)\n  const labels = { ...KIND_LABELS, ...kindLabels }\n\n  return (\n    <Section\n      as={as ?? (title ? \"section\" : \"div\")}\n      spacing={spacing}\n      labelledBy={titleId}\n      id={id}\n      className={className}\n    >\n      <Container size=\"md\" className=\"flex flex-col gap-12\">\n        {title ? (\n          <SectionHeader\n            align={align}\n            eyebrow={eyebrow}\n            title={title}\n            description={description}\n            headingLevel={headingLevel}\n            titleId={titleId}\n          />\n        ) : null}\n\n        <List className=\"divide-border flex flex-col divide-y\">\n          {items.map((entry) => {\n            const entryId = entry.id ?? slugId(entry.version, \"release\")\n            const entryTitleId = `${entryId}-title`\n\n            return (\n              <Item key={entryId}>\n                <article\n                  id={entryId}\n                  aria-labelledby={entryTitleId}\n                  className=\"grid scroll-mt-24 gap-4 py-10 md:grid-cols-[10rem_minmax(0,1fr)] md:gap-8\"\n                >\n                  <div className=\"flex flex-col gap-2 md:sticky md:top-24 md:self-start\">\n                    <p className=\"flex flex-wrap items-center gap-2\">\n                      <Badge variant=\"outline\">{entry.version}</Badge>\n                      {entry.tag ? <Badge size=\"sm\">{entry.tag}</Badge> : null}\n                    </p>\n                    <time\n                      dateTime={entry.dateTime}\n                      className=\"text-muted-foreground text-sm\"\n                    >\n                      {entry.dateLabel}\n                    </time>\n                  </div>\n\n                  <div className=\"flex flex-col gap-4\">\n                    <Heading\n                      level={itemLevel}\n                      id={entryTitleId}\n                      className=\"text-foreground text-balance text-xl font-semibold tracking-tight\"\n                    >\n                      {entry.href ? (\n                        <Link\n                          href={entry.href}\n                          {...(entry.external\n                            ? { target: \"_blank\", rel: \"noopener noreferrer\" }\n                            : {})}\n                          className=\"focus-visible:ring-ring rounded-sm underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2\"\n                        >\n                          {entry.title}\n                          {entry.external ? (\n                            <span className=\"sr-only\"> (opens in a new tab)</span>\n                          ) : null}\n                        </Link>\n                      ) : (\n                        entry.title\n                      )}\n                    </Heading>\n\n                    {entry.summary ? (\n                      <p className=\"text-muted-foreground text-pretty\">{entry.summary}</p>\n                    ) : null}\n\n                    {entry.changes.length > 0 ? (\n                      <ul className=\"flex flex-col gap-3\">\n                        {entry.changes.map((change, index) => (\n                          <li key={index} className=\"flex items-start gap-3\">\n                            <Badge\n                              variant={KIND_VARIANTS[change.kind]}\n                              size=\"sm\"\n                              className=\"mt-0.5 w-24 shrink-0 justify-center\"\n                            >\n                              {labels[change.kind]}\n                            </Badge>\n                            <span className=\"text-foreground text-pretty\">\n                              {change.description}\n                            </span>\n                          </li>\n                        ))}\n                      </ul>\n                    ) : null}\n                  </div>\n                </article>\n              </Item>\n            )\n          })}\n        </List>\n      </Container>\n    </Section>\n  )\n}\n"
    }
  ],
  "docs": "Import styles/facade-tokens.css in your global stylesheet, after @import \"tailwindcss\". Set headingLevel to fit the page outline (sections default to h2). Pass next/link and next/image through the link and image props. Docs: https://facadeui.dev/components/changelog-list"
}
