{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "avatar",
  "title": "Avatar",
  "description": "Photos fade up out of a blur once loaded, and stacked avatars spring apart on hover.",
  "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/avatar.tsx",
      "content": "\"use client\"\n\n/* Animated drop-in for `@ui-sdk/react/avatar`: 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\nimport { Avatar as AvatarRoot, AvatarImage as AvatarImagePart } from \"@ui-sdk/react/avatar\"\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport * from \"@ui-sdk/react/avatar\"\n\n/* Moves on a spring when a group makes room for its neighbour, and dips when pressed\n   (rendered as a button or link). */\nfunction Avatar({ className, ...props }: React.ComponentProps<typeof AvatarRoot>) {\n  return (\n    <AvatarRoot\n      className={cn(\n        \"[transition:translate_calc(460ms*var(--kf-speed,1))_var(--ease-spring),scale_calc(220ms*var(--kf-speed,1))_var(--ease-pop)] [&:is(button,a)]:active:scale-[0.92]\",\n        \"motion-reduce:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Blur-in: the photo arrives out of a 10px blur and a 1.25 zoom, the zoom settling on a spring.\n   Until it has loaded, UI SDK keeps it out of sight with its own inline style. A cached image is\n   loaded before its first paint, so `starting:` gives it the same entrance. */\nfunction AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarImagePart>) {\n  return (\n    <AvatarImagePart\n      className={cn(\n        \"[transition:opacity_calc(420ms*var(--kf-speed,1))_var(--ease-house),filter_calc(560ms*var(--kf-speed,1))_var(--ease-house),scale_calc(680ms*var(--kf-speed,1))_var(--ease-spring)]\",\n        \"not-data-[loading-status=loaded]:scale-125 not-data-[loading-status=loaded]:blur-[10px]\",\n        \"starting:scale-125 starting:opacity-0 starting:blur-[10px]\",\n        \"motion-reduce:transition-none!\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Extra helper: overlapping avatars. The hovered one rises 4px and comes to the front; the ones\n   after it step 6px right and the ones before it 6px left, so it has room. `data-hovered` on a\n   child does the same, for hover you track yourself (touch, or a scripted demo). */\nfunction AvatarGroup({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"avatar-group\"\n      className={cn(\n        \"isolate flex items-center *:relative\",\n        \"[&>*:is(:hover,[data-hovered])]:z-10 [&>*:is(:hover,[data-hovered])]:-translate-y-1\",\n        \"[&>*:is(:hover,[data-hovered])~*]:translate-x-1.5 [&>*:has(~*:is(:hover,[data-hovered]))]:-translate-x-1.5\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Extra helper: the \"+3\" that closes a group, moving with it. */\nfunction AvatarGroupCount({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"avatar-group-count\"\n      className={cn(\"transition-[translate] duration-[calc(460ms*var(--kf-speed,1))] ease-spring motion-reduce:transition-none!\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { Avatar, AvatarGroup, AvatarGroupCount, AvatarImage }\n",
      "type": "registry:component",
      "target": "components/keyframery/primitives/avatar.tsx"
    },
    {
      "path": "registry/components/keyframery/avatar.tsx",
      "content": "\"use client\"\n\n/* Styled avatar: the animated primitive plus the Keyframery look. */\n\nimport * as React from \"react\"\n\nimport {\n  Avatar as AvatarRoot,\n  AvatarFallback as AvatarFallbackPart,\n  AvatarGroup as AvatarGroupPrimitive,\n  AvatarGroupCount as AvatarGroupCountPrimitive,\n  AvatarImage as AvatarImagePart,\n} from \"@/components/keyframery/primitives/avatar\"\n\nimport { cn } from \"@/lib/utils\"\n\ntype AvatarSize = \"sm\" | \"md\" | \"lg\"\n\nconst sizes: Record<AvatarSize, string> = {\n  sm: \"size-6 text-[10px]\",\n  md: \"size-8 text-[11px]\",\n  lg: \"size-10 text-[13px]\",\n}\n\n/* A disc with a hairline drawn above the image, so photos with light edges keep their shape.\n   Inside a group, each avatar wears a ring in the surface colour (--avatar-ring). */\nconst disc = [\n  \"relative inline-grid shrink-0 place-items-center overflow-hidden rounded-full bg-muted align-middle leading-none select-none\",\n  \"after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit]\",\n  \"after:shadow-[inset_0_0_0_1px_rgb(0_0_0/0.08)] dark:after:shadow-[inset_0_0_0_1px_rgb(255_255_255/0.1)]\",\n  \"ring-(color:--avatar-ring) in-data-[slot=avatar-group]:ring-2\",\n]\n\nfunction Avatar({\n  className,\n  size = \"md\",\n  ...props\n}: React.ComponentProps<typeof AvatarRoot> & { size?: AvatarSize }) {\n  return (\n    <AvatarRoot\n      data-size={size}\n      className={cn(\n        disc,\n        sizes[size],\n        /* When rendered as a button or link. */\n        \"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n        \"[&:is(button,a)]:cursor-pointer\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The photo fills the disc; its blur-in comes from the primitive. */\nfunction AvatarImage({ className, ...props }: React.ComponentProps<typeof AvatarImagePart>) {\n  return (\n    <AvatarImagePart\n      className={cn(\n        \"absolute inset-0 size-full object-cover\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction AvatarFallback({ className, ...props }: React.ComponentProps<typeof AvatarFallbackPart>) {\n  return (\n    <AvatarFallbackPart\n      className={cn(\n        \"grid size-full place-items-center rounded-[inherit] font-semibold tracking-[0.01em] text-muted-foreground uppercase\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* Overlapping avatars. Set --avatar-ring to the surface they sit on (it defaults to the page background).\n   Hover one and it rises while its neighbours make room (from the primitive). */\nfunction AvatarGroup({ className, ...props }: React.ComponentProps<typeof AvatarGroupPrimitive>) {\n  return (\n    <AvatarGroupPrimitive\n      className={cn(\n        \"[--avatar-ring:var(--background)] *:not-first:-ml-1\",\n        className,\n      )}\n      {...props}\n    />\n  )\n}\n\n/* The \"+3\" that closes a group. */\nfunction AvatarGroupCount({\n  className,\n  size = \"md\",\n  ...props\n}: React.ComponentProps<typeof AvatarGroupCountPrimitive> & { size?: AvatarSize }) {\n  return (\n    <AvatarGroupCountPrimitive\n      className={cn(disc, sizes[size], \"font-medium text-muted-foreground tabular-nums\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage }\n",
      "type": "registry:component",
      "target": "components/keyframery/avatar.tsx"
    }
  ],
  "type": "registry:component"
}