Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 76 additions & 26 deletions src/components/AvatarGroup/AvatarGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,85 +20,85 @@ type Story = StoryObj<typeof meta>;
export const Single: Story = {
render: () => (
<AvatarGroup>
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
</AvatarGroup>
),
};

export const Two: Story = {
render: () => (
<AvatarGroup>
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="B" className="bg-green-100" />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
<AvatarGroupItem fallback="B" fallbackClassName="bg-green-100" />
</AvatarGroup>
),
};

export const Three: Story = {
render: () => (
<AvatarGroup>
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="B" className="bg-green-100" />
<AvatarGroupItem fallback="R" className="bg-pink-100" />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
<AvatarGroupItem fallback="B" fallbackClassName="bg-green-100" />
<AvatarGroupItem fallback="R" fallbackClassName="bg-pink-100" />
</AvatarGroup>
),
};

export const WithPresenceIndicator: Story = {
render: () => (
<AvatarGroup>
<AvatarGroupItem fallback="L" className="bg-orange-100" showPresence />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" showPresence />
</AvatarGroup>
),
};

export const TwoWithPresence: Story = {
render: () => (
<AvatarGroup>
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="B" className="bg-green-100" showPresence />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
<AvatarGroupItem fallback="B" fallbackClassName="bg-green-100" showPresence />
</AvatarGroup>
),
};

export const SmallSize: Story = {
render: () => (
<AvatarGroup size="sm">
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="B" className="bg-green-100" />
<AvatarGroupItem fallback="R" className="bg-pink-100" />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
<AvatarGroupItem fallback="B" fallbackClassName="bg-green-100" />
<AvatarGroupItem fallback="R" fallbackClassName="bg-pink-100" />
</AvatarGroup>
),
};

export const LargeSize: Story = {
render: () => (
<AvatarGroup size="lg">
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="B" className="bg-green-100" />
<AvatarGroupItem fallback="R" className="bg-pink-100" />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
<AvatarGroupItem fallback="B" fallbackClassName="bg-green-100" />
<AvatarGroupItem fallback="R" fallbackClassName="bg-pink-100" />
</AvatarGroup>
),
};

export const TightSpacing: Story = {
render: () => (
<AvatarGroup spacing="tight">
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="B" className="bg-green-100" />
<AvatarGroupItem fallback="R" className="bg-pink-100" />
<AvatarGroupItem fallback="D" className="bg-sky-100" />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
<AvatarGroupItem fallback="B" fallbackClassName="bg-green-100" />
<AvatarGroupItem fallback="R" fallbackClassName="bg-pink-100" />
<AvatarGroupItem fallback="D" fallbackClassName="bg-sky-100" />
</AvatarGroup>
),
};

export const LooseSpacing: Story = {
render: () => (
<AvatarGroup spacing="loose">
<AvatarGroupItem fallback="L" className="bg-orange-100" />
<AvatarGroupItem fallback="B" className="bg-green-100" />
<AvatarGroupItem fallback="R" className="bg-pink-100" />
<AvatarGroupItem fallback="D" className="bg-sky-100" />
<AvatarGroupItem fallback="L" fallbackClassName="bg-orange-100" />
<AvatarGroupItem fallback="B" fallbackClassName="bg-green-100" />
<AvatarGroupItem fallback="R" fallbackClassName="bg-pink-100" />
<AvatarGroupItem fallback="D" fallbackClassName="bg-sky-100" />
</AvatarGroup>
),
};
Expand All @@ -110,19 +110,69 @@ export const WithImages: Story = {
src="https://i.pravatar.cc/150?img=1"
alt="User 1"
fallback="L"
className="bg-orange-100"
fallbackClassName="bg-orange-100"
/>
<AvatarGroupItem
src="https://i.pravatar.cc/150?img=2"
alt="User 2"
fallback="B"
className="bg-green-100"
fallbackClassName="bg-green-100"
/>
<AvatarGroupItem
src="https://i.pravatar.cc/150?img=3"
alt="User 3"
fallback="R"
className="bg-pink-100"
fallbackClassName="bg-pink-100"
/>
</AvatarGroup>
),
};

/**
* Demonstrates using fallbackClassName for custom colors with text contrast.
* Use fallbackClassName for background/text colors on the fallback initials.
*/
export const CustomColors: Story = {
render: () => (
<AvatarGroup>
<AvatarGroupItem
fallback="RD"
fallbackClassName="bg-indigo-500 text-white"
/>
<AvatarGroupItem
fallback="JS"
fallbackClassName="bg-purple-500 text-white"
/>
<AvatarGroupItem
fallback="EM"
fallbackClassName="bg-teal-500 text-white"
showPresence
/>
</AvatarGroup>
),
};

/**
* Demonstrates separating container styling (borders) from fallback styling (colors).
* className applies to Avatar container, fallbackClassName to the fallback initials.
*/
export const CustomBordersAndColors: Story = {
render: () => (
<AvatarGroup>
<AvatarGroupItem
fallback="A"
className="border-2 border-orange-500"
fallbackClassName="bg-orange-500 text-white"
/>
<AvatarGroupItem
fallback="B"
className="border-2 border-green-500"
fallbackClassName="bg-green-500 text-white"
/>
<AvatarGroupItem
fallback="C"
className="border-2 border-pink-500"
fallbackClassName="bg-pink-500 text-white"
/>
</AvatarGroup>
),
Expand Down
9 changes: 7 additions & 2 deletions src/components/AvatarGroup/AvatarGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,20 @@ export interface AvatarGroupItemProps
* Whether to show a presence indicator (green dot)
*/
showPresence?: boolean;
/**
* Classes for the fallback background/text (e.g., bg-indigo-500 text-white)
* Defaults to bg-muted text-foreground if not provided
*/
fallbackClassName?: string;
}

const AvatarGroupItem = React.forwardRef<HTMLDivElement, AvatarGroupItemProps>(
({ className, src, alt, fallback, showPresence, ...props }, ref) => {
({ className, fallbackClassName, src, alt, fallback, showPresence, ...props }, ref) => {
return (
<div ref={ref} className="relative h-[inherit] w-[inherit]" {...props}>
<Avatar className={cn('h-full w-full border border-input', className)}>
{src && <AvatarImage src={src} alt={alt} />}
<AvatarFallback className={cn('font-semibold', className)}>
<AvatarFallback className={cn('font-semibold', fallbackClassName)}>
{fallback}
</AvatarFallback>
</Avatar>
Expand Down