{
  "name": "avatar-group",
  "type": "registry:ui",
  "dependencies": [
    "cn",
    "radix-ui"
  ],
  "files": [
    {
      "path": "ui/avatar-group.tsx",
      "type": "registry:ui",
      "content": "import { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"cn\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport * as React from \"react\";\n\nconst avatarGroupVariants = cva(\"flex items-center\", {\n  variants: {\n    orientation: {\n      horizontal: \"flex-row\",\n      vertical: \"flex-col\",\n    },\n    dir: {\n      ltr: \"\",\n      rtl: \"\",\n    },\n  },\n  compoundVariants: [\n    {\n      orientation: \"horizontal\",\n      dir: \"ltr\",\n      className: \"-space-x-1\",\n    },\n    {\n      orientation: \"horizontal\",\n      dir: \"rtl\",\n      className: \"flex-row-reverse -space-x-1 space-x-reverse\",\n    },\n    {\n      orientation: \"vertical\",\n      dir: \"ltr\",\n      className: \"-space-y-1\",\n    },\n    {\n      orientation: \"vertical\",\n      dir: \"rtl\",\n      className: \"flex-col-reverse -space-y-1 space-y-reverse\",\n    },\n  ],\n  defaultVariants: {\n    orientation: \"horizontal\",\n    dir: \"ltr\",\n  },\n});\n\ninterface AvatarGroupProps\n  extends\n    Omit<React.ComponentProps<\"div\">, \"dir\">,\n    VariantProps<typeof avatarGroupVariants> {\n  size?: number;\n  max?: number;\n  asChild?: boolean;\n  reverse?: boolean;\n  renderOverflow?: (count: number) => React.ReactNode;\n}\n\nfunction AvatarGroup(props: AvatarGroupProps) {\n  const {\n    orientation = \"horizontal\",\n    dir = \"ltr\",\n    size = 40,\n    max,\n    asChild,\n    reverse = false,\n    renderOverflow,\n    className,\n    children,\n    ...rootProps\n  } = props;\n\n  const childrenArray = React.Children.toArray(children).filter(\n    React.isValidElement,\n  );\n  const itemCount = childrenArray.length;\n  const shouldTruncate = max && itemCount > max;\n  const visibleItems = shouldTruncate\n    ? childrenArray.slice(0, max - 1)\n    : childrenArray;\n  const overflowCount = shouldTruncate ? itemCount - (max - 1) : 0;\n  const totalRenderedItems = shouldTruncate ? max : itemCount;\n\n  const RootPrimitive = asChild ? SlotPrimitive.Slot : \"div\";\n\n  return (\n    <RootPrimitive\n      data-orientation={orientation}\n      data-slot=\"avatar-group\"\n      {...rootProps}\n      className={cn(avatarGroupVariants({ orientation, dir }), className)}\n    >\n      {visibleItems.map((child, index) => (\n        <AvatarGroupItem\n          key={index}\n          child={child}\n          index={index}\n          itemCount={totalRenderedItems}\n          orientation={orientation}\n          dir={dir}\n          size={size}\n          reverse={reverse}\n        />\n      ))}\n      {shouldTruncate && (\n        <AvatarGroupItem\n          key=\"overflow\"\n          child={\n            renderOverflow ? (\n              renderOverflow(overflowCount)\n            ) : (\n              <div className=\"inline-flex size-full items-center justify-center rounded-full bg-muted text-xs font-medium text-muted-foreground\">\n                +{overflowCount}\n              </div>\n            )\n          }\n          index={visibleItems.length}\n          itemCount={totalRenderedItems}\n          orientation={orientation}\n          dir={dir}\n          size={size}\n          reverse={reverse}\n        />\n      )}\n    </RootPrimitive>\n  );\n}\n\ninterface AvatarGroupItemProps\n  extends\n    Omit<React.ComponentProps<typeof SlotPrimitive.Slot>, \"dir\">,\n    VariantProps<typeof avatarGroupVariants> {\n  child: React.ReactNode;\n  index: number;\n  itemCount: number;\n  size: number;\n  reverse: boolean;\n}\n\nfunction AvatarGroupItem(props: AvatarGroupItemProps) {\n  const {\n    child,\n    index,\n    size,\n    orientation,\n    dir = \"ltr\",\n    reverse = false,\n    itemCount,\n    className,\n    style,\n    ...itemProps\n  } = props;\n\n  const maskStyle = React.useMemo<React.CSSProperties>(() => {\n    let maskImage = \"\";\n\n    let shouldMask = false;\n\n    if (orientation === \"vertical\" && dir === \"rtl\" && reverse) {\n      shouldMask = index !== itemCount - 1;\n    } else {\n      shouldMask = reverse ? index < itemCount - 1 : index > 0;\n    }\n\n    if (shouldMask) {\n      const maskRadius = size / 2;\n      const maskOffset = size / 4 + size / 10;\n\n      if (orientation === \"vertical\") {\n        if (dir === \"ltr\") {\n          if (reverse) {\n            maskImage = `radial-gradient(circle ${maskRadius}px at 50% ${size + maskOffset}px, transparent 99%, white 100%)`;\n          } else {\n            maskImage = `radial-gradient(circle ${maskRadius}px at 50% -${maskOffset}px, transparent 99%, white 100%)`;\n          }\n        } else {\n          if (reverse) {\n            maskImage = `radial-gradient(circle ${maskRadius}px at 50% -${maskOffset}px, transparent 99%, white 100%)`;\n          } else {\n            maskImage = `radial-gradient(circle ${maskRadius}px at 50% ${size + maskOffset}px, transparent 99%, white 100%)`;\n          }\n        }\n      } else {\n        if (dir === \"ltr\") {\n          if (reverse) {\n            maskImage = `radial-gradient(circle ${maskRadius}px at ${size + maskOffset}px 50%, transparent 99%, white 100%)`;\n          } else {\n            maskImage = `radial-gradient(circle ${maskRadius}px at -${maskOffset}px 50%, transparent 99%, white 100%)`;\n          }\n        } else {\n          if (reverse) {\n            maskImage = `radial-gradient(circle ${maskRadius}px at -${maskOffset}px 50%, transparent 99%, white 100%)`;\n          } else {\n            maskImage = `radial-gradient(circle ${maskRadius}px at ${size + maskOffset}px 50%, transparent 99%, white 100%)`;\n          }\n        }\n      }\n    }\n\n    return {\n      width: size,\n      height: size,\n      maskImage,\n    };\n  }, [size, index, orientation, dir, reverse, itemCount]);\n\n  return (\n    <SlotPrimitive.Slot\n      data-slot=\"avatar-group-item\"\n      className={cn(\n        \"size-full shrink-0 overflow-hidden rounded-full [&_img]:size-full\",\n        className,\n      )}\n      style={{\n        ...maskStyle,\n        ...style,\n      }}\n      {...itemProps}\n    >\n      {child}\n    </SlotPrimitive.Slot>\n  );\n}\n\nexport { AvatarGroup };\n",
      "target": ""
    }
  ]
}