Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/bitter-cougars-deny.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

AvatarStack: Border was incorrectly applying to elements that were not `Avatar` children.
5 changes: 5 additions & 0 deletions .changeset/evil-zebras-train.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/react': patch
---

AvatarStack: The square prop was not applying to individual `Avatar` components.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions e2e/components/AvatarStack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ const stories: Array<{title: string; id: string}> = [
title: 'With Link Wrappers',
id: 'components-avatarstack-dev--with-link-wrappers',
},
{
title: 'With Square Avatars',
id: 'components-avatarstack-features--with-square-avatars',
},
]

test.describe('AvatarStack', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ export const CustomSizeOnChildren = () => (
</AvatarStack>
)

export const WithSquareAvatars = () => (
<AvatarStack shape="square">
<Avatar alt="Primer logo" src="https://avatars.githubusercontent.com/primer" />
<Avatar alt="GitHub logo" src="https://avatars.githubusercontent.com/github" />
<Avatar alt="Atom logo" src="https://avatars.githubusercontent.com/atom" />
<Avatar alt="GitHub Desktop logo" src="https://avatars.githubusercontent.com/desktop" />
</AvatarStack>
)

// the smallest size of the children avatars will be used at each breakpoint
export const CustomSizeOnChildrenResponsive = () => (
<AvatarStack>
Expand Down
6 changes: 5 additions & 1 deletion packages/react/src/AvatarStack/AvatarStack.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
}

&:where([data-avatar-count='1'][data-shape='circle']) {
.AvatarItem {
.AvatarItem:where([data-component='Avatar']) {
/* stylelint-disable-next-line primer/box-shadow */
box-shadow: 0 0 0 var(--avatar-border-width) var(--avatar-borderColor);
}
Expand Down Expand Up @@ -143,6 +143,10 @@
box-shadow: 0 0 0 var(--avatar-border-width) transparent;
}

&:not([data-component='Avatar']):not(:has([data-square])) {
border-radius: 50%;
}

.AvatarStack:where([data-shape='square']) &:is(img) {
/* stylelint-disable-next-line primer/box-shadow */
box-shadow: 1px 0 rgb(255, 255, 255, 1);
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/AvatarStack/AvatarStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const transformChildren = (children: React.ReactNode, shape: AvatarStackProps['s
if (!React.isValidElement(child)) return child
return React.cloneElement(child, {
...child.props,
square: shape === 'square' ? true : undefined,
square: (shape === 'square' ? true : undefined) || child.props.square,
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logical OR operator (||) will incorrectly handle the case when child.props.square is explicitly false. When shape !== 'square' and child.props.square === false, the expression evaluates to undefined || false = false, which would make the avatar square even though the stack shape is 'circle'.

Consider simplifying to:

square: shape === 'square' ? true : child.props.square,

This correctly:

  • Forces all avatars to be square when shape='square'
  • Preserves the individual avatar's square prop when shape='circle' (including when it's explicitly false)
Suggested change
square: (shape === 'square' ? true : undefined) || child.props.square,
square: shape === 'square' ? true : child.props.square,

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider adding unit tests to verify the square prop behavior that this PR fixes. For example:

  • Test that shape="square" applies square={true} to Avatar children
  • Test that individual Avatar's square prop is respected when stack shape is 'circle'
  • Test that non-Avatar children don't receive the square prop

This would prevent regression of the bugs this PR fixes.

Copilot uses AI. Check for mistakes.
className: clsx(child.props.className, 'pc-AvatarItem', classes.AvatarItem),
})
})
Expand Down
Loading