{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "track-list",
  "title": "Track List",
  "description": "A list of tracks with active and playing states, arrow-key navigation and slots for artwork, duration and actions.",
  "dependencies": [
    "@base-ui/react",
    "class-variance-authority"
  ],
  "files": [
    {
      "path": "components/ui/track-list.tsx",
      "content": "\"use client\";\n\nimport { mergeProps } from \"@base-ui/react/merge-props\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport { cva } from \"class-variance-authority\";\nimport type { VariantProps } from \"class-variance-authority\";\nimport { createContext, useContext, useMemo } from \"react\";\nimport type { ComponentProps, KeyboardEvent } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst ITEM_SELECTOR = \"[data-slot='track-list-item']:not([data-disabled])\";\n\ninterface TrackListItemContextValue {\n  active: boolean;\n  playing: boolean;\n}\n\nconst TrackListItemContext = createContext<TrackListItemContextValue>({\n  active: false,\n  playing: false,\n});\n\nconst trackListVariants = cva(\"group/track-list flex w-full flex-col\", {\n  defaultVariants: { size: \"default\", variant: \"default\" },\n  variants: {\n    size: {\n      default: \"gap-0.5 [--track-row-height:3rem]\",\n      lg: \"gap-1 [--track-row-height:3.5rem]\",\n      sm: \"gap-0 [--track-row-height:2.25rem]\",\n    },\n    variant: {\n      default: \"\",\n      outline: \"rounded-xl border p-1\",\n    },\n  },\n});\n\nexport interface TrackListProps\n  extends ComponentProps<\"ul\">, VariantProps<typeof trackListVariants> {}\n\nconst moveFocus = (event: KeyboardEvent<HTMLUListElement>) => {\n  const items = [\n    ...event.currentTarget.querySelectorAll<HTMLElement>(ITEM_SELECTOR),\n  ];\n  const current = (event.target as HTMLElement).closest<HTMLElement>(\n    ITEM_SELECTOR\n  );\n  if (!current || current !== event.target) {\n    return;\n  }\n  const index = items.indexOf(current);\n  const targets: Record<string, number> = {\n    ArrowDown: index + 1,\n    ArrowUp: index - 1,\n    End: items.length - 1,\n    Home: 0,\n  };\n  const targetIndex = targets[event.key];\n  const next = targetIndex === undefined ? undefined : items[targetIndex];\n  if (next) {\n    event.preventDefault();\n    next.focus();\n  }\n};\n\nexport const TrackList = ({\n  size = \"default\",\n  variant = \"default\",\n  className,\n  onKeyDown,\n  ...props\n}: TrackListProps) => (\n  <ul\n    className={cn(trackListVariants({ size, variant }), className)}\n    data-size={size}\n    data-slot=\"track-list\"\n    onKeyDown={(event) => {\n      onKeyDown?.(event);\n      if (!event.defaultPrevented) {\n        moveFocus(event);\n      }\n    }}\n    {...props}\n  />\n);\n\nexport interface TrackListItemProps extends useRender.ComponentProps<\"li\"> {\n  /** The current track. */\n  active?: boolean;\n  /** The current track, playing. */\n  playing?: boolean;\n  disabled?: boolean;\n  /** Click, Enter or Space. */\n  onSelect?: () => void;\n}\n\nexport const TrackListItem = ({\n  active = false,\n  playing = false,\n  disabled = false,\n  onSelect,\n  render,\n  className,\n  children,\n  ...props\n}: TrackListItemProps) => {\n  const contextValue = useMemo(() => ({ active, playing }), [active, playing]);\n\n  return useRender({\n    defaultTagName: \"li\",\n    props: mergeProps<\"li\">(\n      {\n        \"aria-current\": active ? \"true\" : undefined,\n        \"aria-disabled\": disabled || undefined,\n        children: (\n          <TrackListItemContext.Provider value={contextValue}>\n            {children}\n          </TrackListItemContext.Provider>\n        ),\n        className: cn(\n          \"group/track-list-item hover:bg-muted/60 focus-visible:ring-ring/30 data-active:bg-muted relative flex min-h-(--track-row-height) cursor-default items-center gap-3 rounded-lg px-2 text-sm transition-colors outline-none focus-visible:ring-3 data-disabled:opacity-50\",\n          className\n        ),\n        onClick: (event) => {\n          const interactive = (event.target as HTMLElement).closest(\n            \"button, a, input\"\n          );\n          if (\n            !disabled &&\n            (!interactive || interactive === event.currentTarget)\n          ) {\n            onSelect?.();\n          }\n        },\n        onKeyDown: (event) => {\n          if (event.target !== event.currentTarget || disabled) {\n            return;\n          }\n          if (event.key === \"Enter\" || event.key === \" \") {\n            event.preventDefault();\n            onSelect?.();\n          }\n        },\n        tabIndex: disabled ? -1 : 0,\n      },\n      props\n    ),\n    render,\n    state: { active, disabled, playing, slot: \"track-list-item\" },\n  });\n};\n\nexport const TrackListItemIndex = ({\n  className,\n  children,\n  ...props\n}: ComponentProps<\"span\">) => {\n  const { playing } = useContext(TrackListItemContext);\n  return (\n    <span\n      className={cn(\n        \"text-muted-foreground group-data-active/track-list-item:text-primary flex w-5 shrink-0 items-center justify-center font-mono text-xs tabular-nums\",\n        className\n      )}\n      data-slot=\"track-list-item-index\"\n      {...props}\n    >\n      {playing ? (\n        <span\n          aria-label=\"Playing\"\n          className=\"flex h-3 items-end gap-px\"\n          role=\"img\"\n        >\n          <span className=\"h-3 w-0.5 animate-pulse rounded-full bg-current motion-reduce:animate-none\" />\n          <span className=\"h-2 w-0.5 animate-pulse rounded-full bg-current [animation-delay:200ms] motion-reduce:animate-none\" />\n          <span className=\"h-2.5 w-0.5 animate-pulse rounded-full bg-current [animation-delay:400ms] motion-reduce:animate-none\" />\n        </span>\n      ) : (\n        children\n      )}\n    </span>\n  );\n};\n\nexport const TrackListItemArtwork = ({\n  className,\n  alt = \"\",\n  ...props\n}: ComponentProps<\"img\">) => (\n  <img\n    alt={alt}\n    className={cn(\n      \"bg-muted size-9 shrink-0 rounded-md object-cover\",\n      className\n    )}\n    data-slot=\"track-list-item-artwork\"\n    {...props}\n  />\n);\n\nexport const TrackListItemContent = ({\n  className,\n  ...props\n}: ComponentProps<\"div\">) => (\n  <div\n    className={cn(\"flex min-w-0 flex-1 flex-col\", className)}\n    data-slot=\"track-list-item-content\"\n    {...props}\n  />\n);\n\nexport const TrackListItemTitle = ({\n  className,\n  ...props\n}: ComponentProps<\"span\">) => (\n  <span\n    className={cn(\n      \"group-data-active/track-list-item:text-primary truncate font-medium\",\n      className\n    )}\n    data-slot=\"track-list-item-title\"\n    {...props}\n  />\n);\n\nexport const TrackListItemDescription = ({\n  className,\n  ...props\n}: ComponentProps<\"span\">) => (\n  <span\n    className={cn(\"text-muted-foreground truncate text-xs\", className)}\n    data-slot=\"track-list-item-description\"\n    {...props}\n  />\n);\n\nexport const TrackListItemDuration = ({\n  className,\n  ...props\n}: ComponentProps<\"span\">) => (\n  <span\n    className={cn(\n      \"text-muted-foreground shrink-0 font-mono text-xs tabular-nums\",\n      className\n    )}\n    data-slot=\"track-list-item-duration\"\n    {...props}\n  />\n);\n\nexport const TrackListItemActions = ({\n  className,\n  ...props\n}: ComponentProps<\"div\">) => (\n  <div\n    className={cn(\"flex shrink-0 items-center gap-1\", className)}\n    data-slot=\"track-list-item-actions\"\n    {...props}\n  />\n);\n\nexport { trackListVariants };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}