Skip to content

Commit 0b4584e

Browse files
committed
squash
1 parent 3c370dc commit 0b4584e

26 files changed

+210
-515
lines changed

.changeset/early-balloons-carry.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@primer/react-brand': minor
3+
---
4+
5+
Refactored Image component and simplified its API.
6+
7+
- Removed the `as`, `media`, and `sources` props, as well code paths which render a `<picture>` element. To use a `<picture>` element with the updated `Image` component, wrap the `Image` with a `picture` element, for example:
8+
9+
```jsx
10+
<picture>
11+
<source srcSet="..." media="..." />
12+
<Image src="..." alt="..." />
13+
</picture>
14+
```
15+
16+
- Fixed an edge case with the border radius of the `Card.Image` component. It was previously possible for the div that wraps the image and the image itself to have different border radii.

apps/docs/content/components/Image/react.mdx

+67-69
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ description: Use the image component to display a graphical representation.
77
---
88

99
import ComponentLayout from '../../../src/layouts/component-layout'
10+
import {PropTableValues} from '../../../src/components'
1011
import {ImageBorderRadiusOptions} from '@primer/react-brand'
11-
export default ComponentLayout
1212

1313
import {Label} from '@primer/react'
14+
export default ComponentLayout
1415

1516
```js
1617
import {Image} from '@primer/react-brand'
@@ -20,7 +21,7 @@ import {Image} from '@primer/react-brand'
2021

2122
### Default
2223

23-
This component uses the `img` element by default.
24+
This component renders an `img` element.
2425

2526
```jsx live
2627
<Image
@@ -31,36 +32,36 @@ This component uses the `img` element by default.
3132

3233
### Picture
3334

34-
The `as` prop can be used to set the container of the image to use `picture`.
35+
As the `Image` component always renders an `img` element, you can wrap it with a `picture` element.
3536

3637
```jsx live
37-
<Image
38-
as="picture"
39-
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
40-
alt="placeholder, blank area with an off-white background color"
41-
/>
38+
<picture>
39+
<Image
40+
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
41+
alt="placeholder, blank area with an off-white background color"
42+
/>
43+
</picture>
4244
```
4345

4446
### Picture with sources
4547

46-
The `sources` prop can be used to set the source elements within the `picture` component. This can only be used when `as` is set to `picture`.
48+
Add `source` elements as siblings to the `Image` component inside the `picture` element.
4749

4850
```jsx live
49-
<Image
50-
as="picture"
51-
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
52-
alt="placeholder, blank area with an off-white background color"
53-
sources={[
54-
{
55-
srcset: 'https://via.placeholder.com/600x400/d3d9df/d3d9df.png',
56-
media: '(min-width: 600px)',
57-
},
58-
{
59-
srcset: 'https://via.placeholder.com/900x600/d3d9df/d3d9df.png',
60-
media: '(min-width: 900px)',
61-
},
62-
]}
63-
/>
51+
<picture>
52+
<source
53+
srcset="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
54+
media="(min-width: 600px)"
55+
/>
56+
<source
57+
srcset="https://via.placeholder.com/900x600/d3d9df/d3d9df.png"
58+
media="(min-width: 900px)"
59+
/>
60+
<Image
61+
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
62+
alt="placeholder, blank area with an off-white background color"
63+
/>
64+
</picture>
6465
```
6566

6667
### Image with source set
@@ -77,27 +78,43 @@ The `srcSet` prop can be used to set the srcSet of the image. This can only be u
7778

7879
### Aspect ratio
7980

80-
The `aspectRatio` prop can be used to set the aspect ratio of the image. This is useful when the image is not the same aspect ratio as the container.
81-
82-
```jsx live
83-
<Image
84-
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
85-
alt="placeholder, blank area with an off-white background color"
86-
aspectRatio="16:9"
87-
/>
88-
```
89-
90-
### Height
91-
92-
The `height` prop can be used to set the height of the image. This can be used along side the `aspectRatio` prop to create a responsive image the same size as other images.
81+
The CSS `aspect-ratio` property (or `style.aspectRatio`) can be used to set the aspect ratio of the image. Note that either `width` or `height` must be set for this to take effect.
9382

9483
```jsx live
95-
<Image
96-
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
97-
alt="placeholder, blank area with an off-white background color"
98-
height={200}
99-
aspectRatio="16:9"
100-
/>
84+
<Stack direction="horizontal" alignItems="flex-start">
85+
<Image
86+
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
87+
alt="placeholder, blank area with an off-white background color"
88+
height={100}
89+
style={{
90+
aspectRatio: '1/1',
91+
}}
92+
/>
93+
<Image
94+
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
95+
alt="placeholder, blank area with an off-white background color"
96+
height={100}
97+
style={{
98+
aspectRatio: '4/3',
99+
}}
100+
/>
101+
<Image
102+
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
103+
alt="placeholder, blank area with an off-white background color"
104+
height={100}
105+
style={{
106+
aspectRatio: '16/10',
107+
}}
108+
/>
109+
<Image
110+
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
111+
alt="placeholder, blank area with an off-white background color"
112+
height={100}
113+
style={{
114+
aspectRatio: '16/9',
115+
}}
116+
/>
117+
</Stack>
101118
```
102119

103120
### Border radius
@@ -144,33 +161,14 @@ The `borderRadius` prop can be used to apply rounded corners to images using pre
144161
</Stack>
145162
```
146163

147-
### Width
148-
149-
The `width` prop can be used to set the width of the image. This can be used along side the `aspectRatio` prop to create a responsive image the same size as other images.
150-
151-
```jsx live
152-
<Image
153-
src="https://via.placeholder.com/600x400/d3d9df/d3d9df.png"
154-
alt="placeholder, blank area with an off-white background color"
155-
width={200}
156-
aspectRatio="16:9"
157-
/>
158-
```
159-
160164
## Component props
161165

162166
### Image <Label>Required</Label>
163167

164-
| name | type | default | required | description |
165-
| -------------- | -------------------------------------------------------------------------- | ----------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
166-
| `src` | `string` | | `true` | Specifies the path to the image |
167-
| `alt` | `string` | | `true` | Specifies a text value explaining the nature of the image for users of assistive technology |
168-
| `as` | `img`, `picture` | `img` | `false` | Specification to create a picture component |
169-
| `sources` | `{srcset: string, media: string}[]` | | `false` | When picture is specified in the `as` prop sources allows you to set the source elements. |
170-
| `aspectRatio` | `'1:1'`, `'16:9'`, `'16:10'`, `'4:3'`, `'custom'` | `undefined` | `false` | Sets the image aspect ratio. A custom ratio can be provided in the design tokens. |
171-
| `borderRadius` | <PropTableValues values={[...ImageBorderRadiusOptions]} commaSeparated /> | `undefined` | `false` | Applies a system-level border radius value to the Image. |
172-
| `height` | `number` | | `false` | The height of the image element or its container if it has an aspect ratio |
173-
| `width` | `number` | | `false` | The width of the image element or its container if it has an aspect ratio |
174-
| `loading` | `eager`, `lazy` | `eager` | `false` | The loading attribute specifies whether a browser should load an image immediately or to defer loading of off-screen images until for example the user scrolls near them. |
175-
| `decoding` | `sync`, `async`, `auto` | `sync` | `false` | Sets the image decoding strategy. Representing a hint given to the browser on how it should decode the image. |
176-
| `className` | `string` | | `false` | Sets a custom CSS class |
168+
All standard `img` attributes are supported as defined by `React.ImgHTMLAttributes<HTMLImageElement>` with the following additions.
169+
170+
| name | type | default | required | description |
171+
| -------------- | -------------------------------------------------------------------------- | ----------- | -------- | -------------------------------------------------------------------------------------------- |
172+
| `alt` | `string` | | `true` | Specifies a text value explaining the nature of the image for users of assistive technology. |
173+
| `animate` | `AnimateProps` | `undefined` | `false` | When wrapped in an `<AnimationProvider>`, applies an animation preset. |
174+
| `borderRadius` | <PropTableValues values={[...ImageBorderRadiusOptions]} commaSeparated /> | `undefined` | `false` | Applies a system-level border radius value to the Image. |

packages/react/src/Card/Card.features.stories.tsx

+4-1
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,10 @@ export const ImageAndLabel: StoryFn<typeof Card> = () => {
180180
export const ImageUsingPictureElement: StoryFn<typeof Card> = () => {
181181
return (
182182
<Card href="https://github.com">
183-
<Card.Image as="picture" src={placeholderImage} alt="placeholder, blank area with an gray background color" />
183+
<picture>
184+
<source srcSet={placeholderImage} media="(min-width: 600px)" />
185+
<Card.Image src={placeholderImage} alt="placeholder, blank area with an gray background color" />
186+
</picture>
184187
<Card.Heading>Code search & code view</Card.Heading>
185188
<Card.Description>
186189
Enables you to rapidly search, navigate, and understand code, right from GitHub.com.

packages/react/src/Card/Card.module.css

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
max-width: unset;
2525
}
2626

27+
.Card--fullWidth .Card__image {
28+
width: 100%;
29+
}
30+
2731
.Card--variant-minimal {
2832
padding: 0;
2933
}
@@ -96,7 +100,6 @@
96100

97101
.Card__image {
98102
margin-bottom: var(--base-size-28);
99-
border-radius: var(--brand-borderRadius-medium);
100103
overflow: hidden;
101104
grid-area: image;
102105
}

packages/react/src/Card/Card.module.css.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
declare const styles: {
22
readonly "Card": string;
33
readonly "Card--fullWidth": string;
4+
readonly "Card__image": string;
45
readonly "Card--variant-minimal": string;
56
readonly "Card--colorMode-light": string;
67
readonly "Card__link": string;
@@ -12,7 +13,6 @@ declare const styles: {
1213
readonly "Card__icon": string;
1314
readonly "Card--variant-default": string;
1415
readonly "Card--colorMode-dark": string;
15-
readonly "Card__image": string;
1616
readonly "Card__icon--badge": string;
1717
readonly "Card__heading": string;
1818
readonly "Card__description": string;

packages/react/src/Card/Card.tsx

+2-6
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,8 @@ function DefaultCardWrapperComponent({children}) {
169169

170170
type CardImageProps = ImageProps
171171

172-
function CardImage({className, ...rest}: CardImageProps) {
173-
return (
174-
<div className={styles.Card__image}>
175-
<Image className={className} {...rest} />
176-
</div>
177-
)
172+
function CardImage({borderRadius = 'medium', className, ...props}: CardImageProps) {
173+
return <Image borderRadius={borderRadius} className={clsx(styles.Card__image, className)} {...props} />
178174
}
179175

180176
type CardIconProps = BaseProps<HTMLSpanElement> & {

packages/react/src/Image/Image.features.stories.tsx

+15-60
Original file line numberDiff line numberDiff line change
@@ -2,77 +2,32 @@ import React from 'react'
22
import {Meta, StoryFn} from '@storybook/react'
33

44
import placeholderImage from '../fixtures/images/placeholder-600x400.png'
5-
import style from './Image.stories.module.css'
65

7-
import {Image, ImageBorderRadiusOptions} from './Image'
6+
import {Image, type ImageAspectRatio, ImageBorderRadiusOptions} from './Image'
87
import {Stack} from '../Stack'
98

109
export default {
1110
title: 'Components/Image/Features',
1211
component: Image,
1312
} as Meta<typeof Image>
1413

15-
export const CustomPictureAspectRatio: StoryFn<typeof Image> = () => (
16-
<Image
17-
src={placeholderImage}
18-
alt="placeholder, blank area with an off-white background color"
19-
aspectRatio="custom"
20-
as="picture"
21-
/>
22-
)
23-
24-
export const CustomImageAspectRatio: StoryFn<typeof Image> = () => (
25-
<Image src={placeholderImage} alt="placeholder, blank area with an off-white background color" aspectRatio="custom" />
26-
)
27-
28-
export const CustomImageHeight: StoryFn<typeof Image> = () => (
29-
<Image src={placeholderImage} alt="placeholder, blank area with an off-white background color" height={200} />
30-
)
31-
32-
export const CustomImageWidth: StoryFn<typeof Image> = () => (
33-
<Image src={placeholderImage} alt="placeholder, blank area with an off-white background color" width={200} />
34-
)
35-
36-
export const CustomImageWidthAndHeight: StoryFn<typeof Image> = () => (
37-
<Image
38-
src={placeholderImage}
39-
alt="placeholder, blank area with an off-white background color"
40-
height={200}
41-
width={200}
42-
/>
43-
)
44-
45-
export const CustomClass: StoryFn<typeof Image> = () => (
46-
<Image
47-
src={placeholderImage}
48-
className={style['custom-image']}
49-
alt="placeholder, blank area with an off-white background color"
50-
height={200}
51-
width={200}
52-
/>
53-
)
54-
55-
export const CustomClassOnPicture: StoryFn<typeof Image> = () => (
56-
<Image
57-
src={placeholderImage}
58-
className={style['custom-image']}
59-
alt="placeholder, blank area with an off-white background color"
60-
height={200}
61-
width={200}
62-
as="picture"
63-
/>
64-
)
14+
const demoAspectRatios: ImageAspectRatio[] = ['16:9', '16:10', '4:3', '1:1']
6515

66-
export const CustomClassWithAspectRatio: StoryFn<typeof Image> = () => (
67-
<Image
68-
src={placeholderImage}
69-
className={style['custom-image']}
70-
alt="placeholder, blank area with an off-white background color"
71-
aspectRatio="custom"
72-
/>
16+
export const AspectRatio: StoryFn<typeof Image> = () => (
17+
<Stack direction="horizontal" alignItems="flex-start">
18+
{demoAspectRatios.map(aspectRatio => (
19+
<Image
20+
key={aspectRatio}
21+
src={placeholderImage}
22+
alt="placeholder, blank area with an off-white background color"
23+
width={200}
24+
aspectRatio={aspectRatio}
25+
/>
26+
))}
27+
</Stack>
7328
)
7429

75-
export const BorderRadiusOptions: StoryFn<typeof Image> = () => (
30+
export const BorderRadius: StoryFn<typeof Image> = () => (
7631
<Stack direction="horizontal">
7732
{ImageBorderRadiusOptions.map(borderRadius => (
7833
<Image

packages/react/src/Image/Image.module.css

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,26 @@
1-
.Image__container {
2-
display: inline-block;
3-
}
4-
51
.Image {
62
object-fit: cover;
73
display: inline-block;
4+
aspect-ratio: var(--brand-image-aspectRatio);
85
}
96

10-
.Image--aspect-ratio-custom {
7+
.Image--aspectRatio-custom {
118
aspect-ratio: var(--brand-image-aspectRatio);
129
}
1310

14-
.Image--aspect-ratio-1-1 {
11+
.Image--aspectRatio-1-1 {
1512
aspect-ratio: 1 / 1;
1613
}
1714

18-
.Image--aspect-ratio-16-9 {
15+
.Image--aspectRatio-16-9 {
1916
aspect-ratio: 16 / 9;
2017
}
2118

22-
.Image--aspect-ratio-16-10 {
19+
.Image--aspectRatio-16-10 {
2320
aspect-ratio: 16 / 10;
2421
}
2522

26-
.Image--aspect-ratio-4-3 {
23+
.Image--aspectRatio-4-3 {
2724
aspect-ratio: 4 / 3;
2825
}
2926

0 commit comments

Comments
 (0)