Skip to content

Commit b4dceab

Browse files
laurkimkyledurand
andauthoredApr 10, 2024
[EmptyState/Image] Fix image loading with ref (Shopify#11874)
### WHY are these changes introduced? Resolves Shopify#11856. EmptyState styles for loaded image were ### WHAT is this pull request doing? Refactors original logic from [Shopify#11804](Shopify#11804) to use an `HTMLImageElement` ref and the [complete attribute](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/complete) to set loaded image styles. <details> <summary>EmptyState — before</summary> <img src="https://github.com/Shopify/polaris/assets/26749317/959a3bc9-d270-44fa-a916-6655532f82e5" alt="EmptyState — before"> </details> <details> <summary>EmptyState — after</summary> <img src="https://github.com/Shopify/polaris/assets/26749317/9304f32d-a95b-41ea-add9-0e37a01a2704" alt="EmptyState — after"> </details> ### How to 🎩 [Storybook](https://5d559397bae39100201eedc1-oumakptmqa.chromatic.com/?path=/story/all-components-emptystate--default) [Spin](https://admin.web.fix-empty-state-2.lo-kim.us.spin.dev/store/shop1/orders) - For testing Spin instance, it helps to throttle the network to ensure there's enough time to see the transition between placeholder and final loaded asset 🖥 [Local development instructions](https://github.com/Shopify/polaris/blob/main/README.md#install-dependencies-and-build-workspaces) 🗒 [General tophatting guidelines](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md) 📄 [Changelog guidelines](https://github.com/Shopify/polaris/blob/main/.github/CONTRIBUTING.md#changelog) ### 🎩 checklist - [x] Tested a [snapshot](https://github.com/Shopify/polaris/blob/main/documentation/Releasing.md#-snapshot-releases) - [x] Tested on [mobile](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting.md#cross-browser-testing) - [x] Tested on [multiple browsers](https://help.shopify.com/en/manual/shopify-admin/supported-browsers) - [ ] Tested for [accessibility](https://github.com/Shopify/polaris/blob/main/documentation/Accessibility%20testing.md) - [ ] Updated the component's `README.md` with documentation changes - [x] [Tophatted documentation](https://github.com/Shopify/polaris/blob/main/documentation/Tophatting%20documentation.md) changes in the style guide --------- Co-authored-by: Kyle Durand <[email protected]>
1 parent 3e0279b commit b4dceab

File tree

3 files changed

+42
-35
lines changed

3 files changed

+42
-35
lines changed
 

‎.changeset/gorgeous-tomatoes-push.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@shopify/polaris': patch
3+
---
4+
5+
Added support for ref to `Image` to handle image load with `EmptyState`

‎polaris-react/src/components/EmptyState/EmptyState.tsx

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useState, useCallback} from 'react';
1+
import React, {useState, useRef, useEffect} from 'react';
22

33
import {classNames} from '../../utilities/css';
44
import type {ComplexAction} from '../../types';
@@ -47,9 +47,10 @@ export function EmptyState({
4747
footerContent,
4848
}: EmptyStateProps) {
4949
const [imageLoaded, setImageLoaded] = useState<boolean>(false);
50+
const imageRef = useRef<HTMLImageElement>(null);
5051

51-
const handleLoad = useCallback(() => {
52-
setImageLoaded(true);
52+
useEffect(() => {
53+
if (imageRef.current?.complete) setImageLoaded(true);
5354
}, []);
5455

5556
const imageClassNames = classNames(
@@ -62,22 +63,24 @@ export function EmptyState({
6263
<Image
6364
alt=""
6465
role="presentation"
66+
ref={imageRef}
6567
source={largeImage}
6668
className={imageClassNames}
6769
sourceSet={[
6870
{source: image, descriptor: '568w'},
6971
{source: largeImage, descriptor: '1136w'},
7072
]}
7173
sizes="(max-width: 568px) 60vw"
72-
onLoad={handleLoad}
74+
onLoad={() => setImageLoaded(true)}
7375
/>
7476
) : (
7577
<Image
7678
alt=""
7779
role="presentation"
80+
ref={imageRef}
7881
className={imageClassNames}
7982
source={image}
80-
onLoad={handleLoad}
83+
onLoad={() => setImageLoaded(true)}
8184
/>
8285
);
8386

+29-30
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useCallback} from 'react';
1+
import React, {useCallback, forwardRef} from 'react';
22

33
interface SourceSet {
44
source: string;
@@ -16,34 +16,33 @@ export interface ImageProps extends React.HTMLProps<HTMLImageElement> {
1616
onError?(): void;
1717
}
1818

19-
export function Image({
20-
alt,
21-
sourceSet,
22-
source,
23-
crossOrigin,
24-
onLoad,
25-
className,
26-
...rest
27-
}: ImageProps) {
28-
const finalSourceSet = sourceSet
29-
? sourceSet
30-
.map(({source: subSource, descriptor}) => `${subSource} ${descriptor}`)
31-
.join(',')
32-
: null;
19+
export const Image = forwardRef<HTMLImageElement, ImageProps>(
20+
({alt, sourceSet, source, crossOrigin, onLoad, className, ...rest}, ref) => {
21+
const finalSourceSet = sourceSet
22+
? sourceSet
23+
.map(
24+
({source: subSource, descriptor}) => `${subSource} ${descriptor}`,
25+
)
26+
.join(',')
27+
: null;
3328

34-
const handleLoad = useCallback(() => {
35-
if (onLoad) onLoad();
36-
}, [onLoad]);
29+
const handleLoad = useCallback(() => {
30+
if (onLoad) onLoad();
31+
}, [onLoad]);
3732

38-
return (
39-
<img
40-
alt={alt}
41-
src={source}
42-
crossOrigin={crossOrigin}
43-
className={className}
44-
onLoad={handleLoad}
45-
{...(finalSourceSet ? {srcSet: finalSourceSet} : {})}
46-
{...rest}
47-
/>
48-
);
49-
}
33+
return (
34+
<img
35+
ref={ref}
36+
alt={alt}
37+
src={source}
38+
crossOrigin={crossOrigin}
39+
className={className}
40+
onLoad={handleLoad}
41+
{...(finalSourceSet ? {srcSet: finalSourceSet} : {})}
42+
{...rest}
43+
/>
44+
);
45+
},
46+
);
47+
48+
Image.displayName = 'Image';

0 commit comments

Comments
 (0)