{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "timeline",
  "title": "Timeline",
  "description": "Events rise in one after another, a finished step's check draws itself and the rail fills.",
  "dependencies": [
    "@ui-sdk/core@0.1.0-beta.2",
    "@ui-sdk/react@0.1.0-beta.2"
  ],
  "registryDependencies": [
    "@keyframery/motion"
  ],
  "files": [
    {
      "path": "registry/components/keyframery/primitives/timeline.tsx",
      "content": "\"use client\"\n\n/* Animated drop-in for `@ui-sdk/react/timeline`: same parts, same props. Swap the import and keep your code.\n   This file adds motion only. Colours, radii, shadows and spacing stay yours.\n\n   - Cascade: events rise in one after another, with a blur, when the timeline first appears.\n   - Draw: when a step completes, its marker pops and the strokes of its icon draw themselves. Set\n     `--kf-draw` on the marker to your icon's path length (24 by default, right for a 24px check).\n   - The rail fills: a finished step's connector fills from its marker toward the next one. The fill is\n     the connector's `after:`; give it your own colour with `after:` classes. */\n\nimport {\n  TimelineConnector as TimelineConnectorPart,\n  TimelineItem as TimelineItemPart,\n  TimelineMarker as TimelineMarkerPart,\n} from \"@ui-sdk/react/timeline\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport * from \"@ui-sdk/react/timeline\"\n\nconst keyframes =\n  \"@keyframes kf-timeline-pop{from{scale:.6}}\" +\n  \"@keyframes kf-timeline-draw{from{stroke-dashoffset:var(--kf-draw,24)}to{stroke-dashoffset:0}}\"\n\n/* Only opacity, translate and filter transition here, so the stagger never slows anything else. */\nfunction TimelineItem({ className, ...props }: React.ComponentProps<typeof TimelineItemPart>) {\n  return (\n    <TimelineItemPart\n      className={cn(\n        \"transition-[opacity,translate,filter] duration-[calc(420ms*var(--kf-speed,1))] ease-spring [transition-delay:calc((min(sibling-index(),10)-1)*calc(32ms*var(--kf-speed,1)))]\",\n        \"starting:translate-y-2 starting:opacity-0 starting:blur-[4px]\",\n        \"motion-reduce:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TimelineMarker({ className, ...props }: React.ComponentProps<typeof TimelineMarkerPart>) {\n  return (\n    <>\n      <style href=\"kf-timeline\" precedence=\"default\">\n        {keyframes}\n      </style>\n      <TimelineMarkerPart\n        className={cn(\n          \"motion-reduce:animate-none! motion-reduce:[&_path]:animate-none! data-complete:animate-[kf-timeline-pop_calc(420ms*var(--kf-speed,1))_var(--ease-pop)]\",\n          \"data-complete:[&_path]:[stroke-dasharray:var(--kf-draw,24)] data-complete:[&_path]:animate-[kf-timeline-draw_calc(260ms*var(--kf-speed,1))_var(--ease-house)_calc(140ms*var(--kf-speed,1))_both]\",\n          \"motion-reduce:animate-none! motion-reduce:[&_path]:animate-none\",\n          className,\n        )}\n        {...props}\n      />\n    </>\n  )\n}\n\n/* The fill grows along the connector once its step is complete, a moment after the check. */\nfunction TimelineConnector({ className, ...props }: React.ComponentProps<typeof TimelineConnectorPart>) {\n  return (\n    <TimelineConnectorPart\n      className={cn(\n        \"overflow-hidden\",\n        \"after:absolute after:inset-0 after:origin-top after:scale-y-0 after:content-['']\",\n        \"after:bg-[color-mix(in_oklch,currentColor_35%,transparent)]\",\n        \"data-[orientation=horizontal]:after:origin-left data-[orientation=horizontal]:after:scale-x-0 data-[orientation=horizontal]:after:scale-y-100\",\n        \"data-complete:after:scale-100\",\n        \"after:transition-[scale] after:delay-[calc(200ms*var(--kf-speed,1))] after:duration-[calc(600ms*var(--kf-speed,1))] after:ease-house motion-reduce:after:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { TimelineConnector, TimelineItem, TimelineMarker }\n",
      "type": "registry:component",
      "target": "components/keyframery/primitives/timeline.tsx"
    },
    {
      "path": "registry/components/keyframery/timeline.tsx",
      "content": "\"use client\"\n\n/* Styled timeline: the animated primitive plus the Keyframery look. */\n\nimport * as React from \"react\"\n\nimport {\n  Timeline as TimelineRoot,\n  TimelineConnector as TimelineConnectorPart,\n  TimelineDescription as TimelineDescriptionPart,\n  TimelineItem as TimelineItemPart,\n  TimelineMarker as TimelineMarkerPart,\n  TimelineTime as TimelineTimePart,\n  TimelineTitle as TimelineTitlePart,\n  createTimelineController,\n} from \"@/components/keyframery/primitives/timeline\"\nimport { cn } from \"@/lib/utils\"\n\n/* The events, one above the other, or side by side in a row of equal columns. */\nfunction Timeline({ className, ...props }: React.ComponentProps<typeof TimelineRoot>) {\n  return (\n    <TimelineRoot\n      className={cn(\n        \"flex flex-col text-[13px]\",\n        \"data-[orientation=horizontal]:grid data-[orientation=horizontal]:grid-cols-[repeat(var(--timeline-count,1),minmax(0,1fr))]\",\n        \"data-busy:opacity-70\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* One event. The marker has its own column and the text sits beside it. The primitive\n   cascades the events in when the timeline first appears. */\nfunction TimelineItem({ className, ...props }: React.ComponentProps<typeof TimelineItemPart>) {\n  return (\n    <TimelineItemPart\n      className={cn(\n        \"relative -mx-2 grid grid-cols-[20px_minmax(0,1fr)_auto] content-start gap-x-3 rounded-[10px] px-2 pt-1.5 pb-4 outline-none last:pb-1.5\",\n        \"data-[orientation=horizontal]:mx-0 data-[orientation=horizontal]:grid-cols-[minmax(0,1fr)] data-[orientation=horizontal]:px-0 data-[orientation=horizontal]:pr-4 data-[orientation=horizontal]:pb-1.5\",\n        \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The dot on the rail. A plain event is a small dot; an upcoming step is hollow; the\n   current step is a primary key; a finished step turns the one success green, and the\n   primitive pops it and draws its check. */\nfunction TimelineMarker({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof TimelineMarkerPart>) {\n  return (\n    <TimelineMarkerPart\n      className={cn(\n        \"relative col-start-1 [--kf-draw:11] row-start-1 grid size-5 place-items-center self-start\",\n        \"data-[orientation=horizontal]:mb-2.5\",\n        /* The dot itself, drawn behind any icon. */\n        \"before:absolute before:top-1/2 before:left-1/2 before:size-2 before:-translate-1/2 before:rounded-full before:bg-muted-foreground/45\",\n        \"before:transition-[width,height,background-color,box-shadow] before:duration-[calc(200ms*var(--kf-speed,1))] before:ease-house\",\n        \"data-upcoming:before:size-2.5 data-upcoming:before:bg-background data-upcoming:before:shadow-[inset_0_0_0_1.5px_color-mix(in_oklab,var(--foreground)_24%,transparent)]\",\n        \"data-current:before:size-4 data-current:before:bg-primary\",\n        \"data-current:before:shadow-[inset_0_1px_0_rgb(255_255_255/0.14),0_1px_2px_rgb(0_0_0/0.25),0_0_0_4px_color-mix(in_oklab,var(--primary)_10%,transparent)]\",\n        \"dark:data-current:before:shadow-[inset_0_1px_0_rgb(255_255_255/0.7),0_1px_2px_rgb(0_0_0/0.5),0_0_0_4px_color-mix(in_oklab,var(--primary)_14%,transparent)]\",\n        \"data-complete:before:size-4 data-complete:before:bg-[oklch(0.62_0.16_150)] data-complete:before:shadow-[inset_0_1px_0_rgb(255_255_255/0.2),0_1px_2px_rgb(0_0_0/0.2)]\",\n        /* The current step's centre. */\n        \"after:absolute after:top-1/2 after:left-1/2 after:size-0 after:-translate-1/2 after:rounded-full after:bg-primary-foreground after:transition-[width,height] after:duration-[calc(200ms*var(--kf-speed,1))]\",\n        \"data-current:after:size-1.5\",\n        \"[&_svg]:relative [&_svg]:size-3 [&_svg]:text-white\",\n        \"motion-reduce:before:transition-none! motion-reduce:after:transition-none!\",\n        className,\n      )}\n      {...props}\n    >\n      {children ??\n        ((state) =>\n          state.status === \"complete\" && (\n            <svg\n              viewBox=\"0 0 16 16\"\n              fill=\"none\"\n              stroke=\"currentColor\"\n              strokeWidth=\"2\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              aria-hidden\n            >\n              <path d=\"m4.5 8.25 2.25 2.25 4.75-5\" />\n            </svg>\n          ))}\n    </TimelineMarkerPart>\n  )\n}\n\n/* The hairline from this event's marker down to the next one. Past a finished step the\n   primitive fills it, so the rail reads as travelled. The last event has none. */\nfunction TimelineConnector({\n  className,\n  ...props\n}: React.ComponentProps<typeof TimelineConnectorPart>) {\n  return (\n    <TimelineConnectorPart\n      className={cn(\n        \"pointer-events-none absolute top-[30px] -bottom-1 left-[17.5px] w-px rounded-full bg-border\",\n        \"after:bg-foreground/30\",\n        \"data-[orientation=horizontal]:top-[15.5px] data-[orientation=horizontal]:right-1 data-[orientation=horizontal]:bottom-auto data-[orientation=horizontal]:left-6 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-auto\",\n        \"in-data-last:hidden\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TimelineTitle({ className, ...props }: React.ComponentProps<typeof TimelineTitlePart>) {\n  return (\n    <TimelineTitlePart\n      className={cn(\n        \"col-start-2 row-start-1 min-w-0 self-center leading-5 font-medium text-foreground\",\n        \"data-upcoming:text-muted-foreground data-current:font-semibold\",\n        \"data-[orientation=horizontal]:col-start-1 data-[orientation=horizontal]:row-start-2\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TimelineTime({ className, ...props }: React.ComponentProps<typeof TimelineTimePart>) {\n  return (\n    <TimelineTimePart\n      className={cn(\n        \"col-start-3 row-start-1 self-center text-[12px] leading-5 whitespace-nowrap text-muted-foreground tabular-nums\",\n        \"data-[orientation=horizontal]:col-start-1 data-[orientation=horizontal]:row-start-3\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction TimelineDescription({\n  className,\n  ...props\n}: React.ComponentProps<typeof TimelineDescriptionPart>) {\n  return (\n    <TimelineDescriptionPart\n      className={cn(\n        \"col-span-2 col-start-2 row-start-2 mt-0.5 text-[13px] leading-[18px] text-muted-foreground\",\n        \"data-upcoming:text-muted-foreground/80\",\n        \"data-[orientation=horizontal]:col-span-1 data-[orientation=horizontal]:col-start-1 data-[orientation=horizontal]:row-start-4\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Timeline,\n  TimelineConnector,\n  TimelineDescription,\n  TimelineItem,\n  TimelineMarker,\n  TimelineTime,\n  TimelineTitle,\n  createTimelineController,\n}\n",
      "type": "registry:component",
      "target": "components/keyframery/timeline.tsx"
    }
  ],
  "type": "registry:component"
}