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
4 changes: 4 additions & 0 deletions packages/react/src/Avatar/Avatar.module.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
:where(.Avatar) {
display: inline-block;
width: var(--avatarSize-regular);
min-width: var(--avatarSize-regular);
height: var(--avatarSize-regular);
overflow: hidden; /* Ensure page layout in Firefox should images fail to load */
/* stylelint-disable-next-line primer/typography */
Expand All @@ -18,16 +19,19 @@
&:where([data-responsive]) {
@media screen and (--viewportRange-narrow) {
width: var(--avatarSize-narrow);
min-width: var(--avatarSize-narrow);
height: var(--avatarSize-narrow);
}

@media screen and (--viewportRange-regular) {
width: var(--avatarSize-regular);
min-width: var(--avatarSize-regular);
height: var(--avatarSize-regular);
}

@media screen and (--viewportRange-wide) {
width: var(--avatarSize-wide);
min-width: var(--avatarSize-wide);
height: var(--avatarSize-wide);
}
}
Expand Down
6 changes: 6 additions & 0 deletions packages/react/src/Avatar/Avatar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ describe('Avatar', () => {
expect(avatar).toHaveAttribute('src', 'primer.png')
})

it('applies min-width matching size to prevent collapsing', () => {
render(<Avatar size={32} src="primer.png" alt="github" data-testid="avatar" />)
const avatar = screen.getByTestId('avatar')
expect(window.getComputedStyle(avatar).minWidth).toBe('32px')
})

it('should support the `style` prop without overriding internal styles', () => {
render(
<Avatar
Expand Down
7 changes: 7 additions & 0 deletions packages/react/src/Button/Button.features.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from '@primer/octicons-react'
import {useState} from 'react'
import {Button, IconButton} from '.'
import Avatar from '../Avatar'
import {Stack} from '../Stack/Stack'
import {announce} from '@primer/live-region-element'
import {Tooltip} from '../TooltipV2/Tooltip'
Expand All @@ -30,6 +31,12 @@ export const Link = () => <Button variant="link">Button that looks like a link</

export const LeadingVisual = () => <Button leadingVisual={HeartIcon}>Leading visual</Button>

export const LeadingVisualAvatar = () => (
<Button leadingVisual={() => <Avatar src="https://avatars.githubusercontent.com/primer" alt="Primer" size={16} />}>
Button with Avatar
</Button>
)

export const TrailingVisual = () => <Button trailingVisual={EyeIcon}>Trailing visual</Button>

export const NotificationIndicator = () => (
Expand Down
43 changes: 43 additions & 0 deletions packages/react/src/Button/__tests__/Button.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {render, fireEvent} from '@testing-library/react'
import {describe, it, expect, vi} from 'vitest'
import React from 'react'
import {IconButton, Button, LinkButton} from '../../Button'
import Avatar from '../../Avatar'
import classes from '../ButtonBase.module.css'
import {implementsClassName} from '../../utils/testing'
import {FeatureFlags} from '../../FeatureFlags'
Expand Down Expand Up @@ -236,6 +237,48 @@ describe('Button', () => {
expect(position).toBe(Node.DOCUMENT_POSITION_PRECEDING)
})

it('renders Avatar in leadingVisual without collapsing when img has max-width: 100%', async () => {
const style = document.createElement('style')
style.textContent = 'img { max-width: 100%; }'
document.head.appendChild(style)

try {
const {rerender} = render(
<Button
leadingVisual={() => (
<Avatar data-testid="avatar-in-button" src="https://avatars.githubusercontent.com/primer" size={16} />
)}
>
Button with Avatar
</Button>,
)

const avatar = page.getByTestId('avatar-in-button').element()
expect(avatar.getBoundingClientRect().width).toBe(16)
expect(window.getComputedStyle(avatar).minWidth).toBe('16px')

// Spacing between leadingVisual and label should remain intact
const leadingVisual = avatar.parentElement
expect(window.getComputedStyle(leadingVisual!).marginRight).toBe('8px')

// Other Avatar sizes should also behave correctly
rerender(
<Button
leadingVisual={() => (
<Avatar data-testid="avatar-in-button" src="https://avatars.githubusercontent.com/primer" size={24} />
)}
>
Button with Avatar
</Button>,
)
const updatedAvatar = page.getByTestId('avatar-in-button').element()
expect(updatedAvatar.getBoundingClientRect().width).toBe(24)
expect(window.getComputedStyle(updatedAvatar).minWidth).toBe('24px')
} finally {
document.head.removeChild(style)
}
})

it('should render the trailingVisual prop after the button content', async () => {
render(
<Button trailingVisual={() => <span data-testid="trailingVisual" />}>
Expand Down
Loading