diff --git a/.changeset/tough-jars-walk.md b/.changeset/tough-jars-walk.md new file mode 100644 index 0000000000..0a7883ecca --- /dev/null +++ b/.changeset/tough-jars-walk.md @@ -0,0 +1,5 @@ +--- +'@shopify/hydrogen-react': patch +--- + +Fix passing `ref` to the `` component. diff --git a/packages/hydrogen-react/src/Image.tsx b/packages/hydrogen-react/src/Image.tsx index 5b71ef738d..704e04c923 100644 --- a/packages/hydrogen-react/src/Image.tsx +++ b/packages/hydrogen-react/src/Image.tsx @@ -389,87 +389,102 @@ type FixedWidthImageProps = Omit & { ref: React.Ref; }; -function FixedWidthImage({ - aspectRatio, - crop, - decoding, - height, - imageWidths, - loader = shopifyLoader, - loading, - normalizedProps, - passthroughProps, - ref, - width, -}: FixedWidthImageProps) { - const fixed = React.useMemo(() => { - const intWidth: number | undefined = getNormalizedFixedUnit(width); - const intHeight: number | undefined = getNormalizedFixedUnit(height); +const FixedWidthImage = React.forwardRef< + HTMLImageElement, + FixedWidthImageProps +>( + ( + { + aspectRatio, + crop, + decoding, + height, + imageWidths, + loader = shopifyLoader, + loading, + normalizedProps, + passthroughProps, + width, + }, + ref, + ) => { + const fixed = React.useMemo(() => { + const intWidth: number | undefined = getNormalizedFixedUnit(width); + const intHeight: number | undefined = getNormalizedFixedUnit(height); + + /* + * The aspect ratio for fixed width images is taken from the explicitly + * set prop, but if that's not present, and both width and height are + * set, we calculate the aspect ratio from the width and height—as + * long as they share the same unit type (e.g. both are 'px'). + */ + const fixedAspectRatio = aspectRatio + ? aspectRatio + : unitsMatch(normalizedProps.width, normalizedProps.height) + ? [intWidth, intHeight].join('/') + : normalizedProps.aspectRatio + ? normalizedProps.aspectRatio + : undefined; - /* - * The aspect ratio for fixed width images is taken from the explicitly - * set prop, but if that's not present, and both width and height are - * set, we calculate the aspect ratio from the width and height—as - * long as they share the same unit type (e.g. both are 'px'). - */ - const fixedAspectRatio = aspectRatio - ? aspectRatio - : unitsMatch(normalizedProps.width, normalizedProps.height) - ? [intWidth, intHeight].join('/') - : normalizedProps.aspectRatio - ? normalizedProps.aspectRatio - : undefined; + /* + * The Sizes Array generates an array of all of the parts + * that make up the srcSet, including the width, height, and crop + */ + const sizesArray = + imageWidths === undefined + ? undefined + : generateSizes(imageWidths, fixedAspectRatio, crop); + + const fixedHeight = intHeight + ? intHeight + : fixedAspectRatio && intWidth + ? intWidth * (parseAspectRatio(fixedAspectRatio) ?? 1) + : undefined; - /* - * The Sizes Array generates an array of all of the parts - * that make up the srcSet, including the width, height, and crop - */ - const sizesArray = - imageWidths === undefined - ? undefined - : generateSizes(imageWidths, fixedAspectRatio, crop); - - const fixedHeight = intHeight - ? intHeight - : fixedAspectRatio && intWidth - ? intWidth * (parseAspectRatio(fixedAspectRatio) ?? 1) - : undefined; - - const srcSet = generateSrcSet(normalizedProps.src, sizesArray, loader); - const src = loader({ - src: normalizedProps.src, - width: intWidth, - height: fixedHeight, - crop: normalizedProps.height === 'auto' ? undefined : crop, - }); + const srcSet = generateSrcSet(normalizedProps.src, sizesArray, loader); + const src = loader({ + src: normalizedProps.src, + width: intWidth, + height: fixedHeight, + crop: normalizedProps.height === 'auto' ? undefined : crop, + }); - return { - width: intWidth, - aspectRatio: fixedAspectRatio, - height: fixedHeight, - srcSet, - src, - }; - }, [aspectRatio, crop, height, imageWidths, loader, normalizedProps, width]); + return { + width: intWidth, + aspectRatio: fixedAspectRatio, + height: fixedHeight, + srcSet, + src, + }; + }, [ + aspectRatio, + crop, + height, + imageWidths, + loader, + normalizedProps, + width, + ]); - return ( - {normalizedProps.alt} - ); -} + return ( + {normalizedProps.alt} + ); + }, +); type FluidImageExcludedProps = | 'data' @@ -488,66 +503,70 @@ type FluidImageProps = Omit & { ref: React.Ref; }; -function FluidImage({ - crop, - decoding, - imageWidths, - loader = shopifyLoader, - loading, - normalizedProps, - passthroughProps, - placeholderWidth, - ref, - sizes, -}: FluidImageProps) { - const fluid = React.useMemo(() => { - const sizesArray = - imageWidths === undefined - ? undefined - : generateSizes(imageWidths, normalizedProps.aspectRatio, crop); - - const placeholderHeight = - normalizedProps.aspectRatio && placeholderWidth - ? placeholderWidth * - (parseAspectRatio(normalizedProps.aspectRatio) ?? 1) - : undefined; - - const srcSet = generateSrcSet(normalizedProps.src, sizesArray, loader); - - const src = loader({ - src: normalizedProps.src, - width: placeholderWidth, - height: placeholderHeight, +const FluidImage = React.forwardRef( + ( + { crop, - }); - - return { - placeholderHeight, - srcSet, - src, - }; - }, [crop, imageWidths, loader, normalizedProps, placeholderWidth]); + decoding, + imageWidths, + loader = shopifyLoader, + loading, + normalizedProps, + passthroughProps, + placeholderWidth, + sizes, + }, + ref, + ) => { + const fluid = React.useMemo(() => { + const sizesArray = + imageWidths === undefined + ? undefined + : generateSizes(imageWidths, normalizedProps.aspectRatio, crop); + + const placeholderHeight = + normalizedProps.aspectRatio && placeholderWidth + ? placeholderWidth * + (parseAspectRatio(normalizedProps.aspectRatio) ?? 1) + : undefined; + + const srcSet = generateSrcSet(normalizedProps.src, sizesArray, loader); + + const src = loader({ + src: normalizedProps.src, + width: placeholderWidth, + height: placeholderHeight, + crop, + }); - return ( - {normalizedProps.alt} - ); -} + return { + placeholderHeight, + srcSet, + src, + }; + }, [crop, imageWidths, loader, normalizedProps, placeholderWidth]); + + return ( + {normalizedProps.alt} + ); + }, +); /** * The shopifyLoader function is a simple utility function that takes a src, width,