Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a52f736
New Image PR
benjaminsehl Mar 6, 2023
c0cfbe0
Make existing tests pass
cartogram Mar 7, 2023
b1110fa
Remove missing sizes warning if fixed width
benjaminsehl Mar 7, 2023
e33681f
Add tests for warnings and fix bug when getting normalizedWidth
cartogram Mar 7, 2023
ca6fa6f
Change multiline log style
cartogram Mar 7, 2023
694cc48
test missing src value
cartogram Mar 8, 2023
e49968e
Enable restrict template literal rule
cartogram Mar 9, 2023
c3f102a
More tests
cartogram Mar 9, 2023
e6f21f9
more tests
cartogram Mar 9, 2023
2039367
Pass custom loader to srcSet
cartogram Mar 13, 2023
daa0b59
Adds width and height prop to the image
benjaminsehl Mar 13, 2023
9bf619d
Improve default width and height props on rendered HTML
benjaminsehl Mar 13, 2023
0f34b1d
Only console warn in dev
benjaminsehl Mar 13, 2023
3c5cb24
Intellisense improvements
benjaminsehl Mar 13, 2023
bd82a80
Comment out console warning tests
benjaminsehl Mar 13, 2023
981ba48
Updates Demo Store images
benjaminsehl Mar 13, 2023
010be7d
Adds docs and examples, updates demo store implementation
benjaminsehl Mar 14, 2023
21cb8ae
Update generated docs data
benjaminsehl Mar 14, 2023
2108d73
Export IMAGE_FRAGMENT from Image component
benjaminsehl Mar 14, 2023
9fcc242
Merge branch '2023-01' into new-image
benjaminsehl Mar 14, 2023
e5e8b84
Update Demo Store
benjaminsehl Mar 14, 2023
a754e2b
Fix image sizing demo store
benjaminsehl Mar 14, 2023
5c22196
Update product card size
benjaminsehl Mar 14, 2023
a812593
Update demo store, improve image srcset for fixed width
benjaminsehl Mar 14, 2023
133433b
Updates tests and starting config
benjaminsehl Mar 14, 2023
0975081
Add crop to placeholder image
benjaminsehl Mar 14, 2023
c0b539d
remove sizes from fixed width image
benjaminsehl Mar 14, 2023
c73adeb
adds changesets
benjaminsehl Mar 14, 2023
90c4de4
fix development env only tests
cartogram Mar 14, 2023
68a09c5
Fixes __HYDROGEN_DEV__
benjaminsehl Mar 15, 2023
1aef9e6
Use Component notation instead of React.createElement
benjaminsehl Mar 15, 2023
d06c228
Tries to fix TS stuff
benjaminsehl Mar 15, 2023
1ec83dd
Tries to fix TS stuff, part 2
benjaminsehl Mar 16, 2023
8172bf1
Refactor
benjaminsehl Mar 17, 2023
0ccc4dc
Fix checks
benjaminsehl Mar 17, 2023
3956df7
Merge branch '2023-04-POC' into new-image
benjaminsehl Apr 6, 2023
566ef57
Delete ImageLegacy and remove old references
benjaminsehl Apr 6, 2023
4227e72
Remove test utils
benjaminsehl Apr 12, 2023
d001ad9
Fixes errors with test-utils
benjaminsehl Apr 12, 2023
4df5c29
Static ProcessEnv type, and adds details to changeset
benjaminsehl Apr 12, 2023
8f8dec7
Removes node types from devDependencies
benjaminsehl Apr 12, 2023
7170955
Remove test utils
benjaminsehl Apr 12, 2023
d11da0a
Removes unneeded prop, updates package lock file
benjaminsehl Apr 12, 2023
e83d11a
Change to work off 2023-04
benjaminsehl Apr 12, 2023
3b32aa8
Removes width and height as specified inline styles
benjaminsehl Apr 12, 2023
6fc38a0
Updates changeset
benjaminsehl Apr 12, 2023
eada9a3
Update image size on demo store cart line item
benjaminsehl Apr 12, 2023
a648c50
PDP css fix
benjaminsehl Apr 12, 2023
0a051e3
Merge branch '2023-04-POC' into new-image
lordofthecactus Apr 13, 2023
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
193 changes: 193 additions & 0 deletions .changeset/five-chefs-heal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
---
'@shopify/hydrogen-react': patch
---

Adds a new `Image` component, replacing the existing one. The new component is backwards compatible, but deprecates some props and benefits from some breaking changes.

### Migrating to the new `Image`

The new `Image` component is responsive by default, and requires less configuration to ensure the right image size is being rendered on all screen sizes.

**Before**

```jsx
<Image
data={image}
widths={[400, 800, 1200]}
width="100px"
sizes="90vw"
loaderOptions={{
scale: 2,
crop: 'left',
}}
/>
```

**After**

```jsx
<Image data={image} sizes="90vw" crop="left" aspectRatio="3/2" />
```

Note that `widths` and `loaderOptions` have now been deprecated, declaring `width` is no longer necessary, and we’ve added an `aspectRatio` prop:

- `widths` is now calculated automatically based on a new `srcSetOptions` prop (see below for details).
- `loaderOptions` has been removed in favour of declaring `crop` and `src` as props. `width` and `height` should only be set as props if rendered a fixed image size, and otherwise default to `100%` and `auto` respectively, with the loader calculating each dynamically.
- `aspectRatio` is calculated automatically using `data.width` and `data.height` (if available) — but if you want to present an image with an aspect ratio other than what was uploaded, you can set using the format `Int/Int` (e.g. `3/2`, [see MDN docs for more info](https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio)); if you've set an `aspectRatio`, we will default the crop to be `crop: center` (in the example above we've specified this to use `left` instead).

### Examples

<!-- Simplest possible usage -->

#### Basic Usage

```jsx
<Image data={data} />
```

This would use all default props, which if exhaustively declared would be the same as typing:

```jsx
<Image
data={data}
crop="center"
decoding="async"
loading="lazy"
width="100%"
height="auto"
sizes="100vw"
srcSetOptions={{
interval: 15,
startingWidth: 200,
incrementSize: 200,
placeholderWidth: 100,
}}
/>
```

An alternative way to write this without using `data` would be to use the `src`, `alt`, and `aspectRatio` props. For example:

```jsx
<Image
src={data.url}
alt={data.altText}
aspectRatio={`${data.width}/${data.height}`}
/>
```

Assuming `data` had the following shape:

```json
{
url: "https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg",
altText: "alt text",
width: "4000"
height: "4000"
}
```

All three above examples would result in the following HTML:

```html
<img
srcset="https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=300&height=300&crop=center 300w, … *13 additional sizes* … https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=3000&height=3000&crop=center 3000w"
src="https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=100&height=100&crop=center"
alt="alt text"
sizes="100vw"
loading="lazy"
decoding="async"
width="100px"
height="100px"
style="aspect-ratio: 4000 / 4000;"
/>
```

#### Fixed-size Images

When using images that are meant to be a fixed size, like showing a preview image of a product in the cart, instead of using `aspectRatio`, you'll instead declare `width` and `height` manually with fixed values. For example:

```jsx
<Image data={data} width={80} height={80} />
```

Instead of generating 15 images for a broad range of screen sizes, `Image` will instead only generate 3, for various screen pixel densities. The above example would result in the following HTML:

```html
<img
srcset="
https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=80&height=80&crop=center 1x,
https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=160&height=160&crop=center 2x,
https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=240&height=240&crop=center 3x
"
src="https://cdn.shopify.com/s/files/1/0551/4566/0472/products/Main.jpg?width=80&height=80"
alt="alt text"
loading="lazy"
width="80px"
height="80px"
style="aspect-ratio: 80 / 80;"
/>
```

If you don't want to have a fixed aspect ratio, and instead respect whatever is returned from your query, the following syntax can also be used:

```jsx
<Image data={data} width="5rem" />
```

Which would result in the same HTML as above, however the generated URLs would not have `height` or `crop` parameters appended to them, and the generated `aspect-ratio` in `style` would be `4000 / 4000` (if using the same `data` values as our original example).

#### Custom Loaders

If your image isn't coming from the Storefront API, but you still want to take advantage of the `Image` component, you can pass a custom `loader` prop, provided the CDN you're working with supports URL-based transformations.

The `loader` is a function which expects a `params` argument of the following type:

```ts
type LoaderParams = {
/** The base URL of the image */
src?: ImageType['url'];
/** The URL param that controls width */
width?: number;
/** The URL param that controls height */
height?: number;
/** The URL param that controls the cropping region */
crop?: Crop;
};
```

Here is an example of using `Image` with a custom loader function:

```jsx
const customLoader = ({src, width, height, crop}) => {
return `${src}?w=${width}&h=${height}&gravity=${crop}`;
};

export default function CustomImage(props) {
<Image loader={customLoader} {...props} />;
}

// In Use:

<CustomImage data={customCDNImageData} />;
```

If your CDN happens to support the same semantics as Shopify (URL params of `width`, `height`, and `crop`) — the default loader will work a non-Shopify `src` attribute.

An example output might look like: `https://mycdn.com/image.jpeg?width=100&height=100&crop=center`

### Additional changes

- Added the `srcSetOptions` prop used to create the image URLs used in `srcset`. It’s an object with the following keys and defaults:

```js
srcSetOptions = {
intervals: 15, // The number of sizes to generate
startingWidth: 200, // The smalles image size
incrementSize: 200, // The increment by to increase for each size, in pixesl
placeholderWidth: 100, // The size used for placeholder fallback images
};
```

- Added an export for `IMAGE_FRAGMENT`, which can be imported from Hydrogen and used in any Storefront API query, which will fetch the required fields needed by the component.

- Added an export for `shopifyLoader` for using Storefront API responses in conjunction with alternative frameworks that already have their own `Image` component, like Next.js
Loading