{"version":3,"file":"b3692baf.js","sources":["../../../node_modules/@shopify/hydrogen/dist/esnext/utilities/image_size.js","../../../node_modules/@shopify/hydrogen/dist/esnext/components/Image/Image.js"],"sourcesContent":["// TODO: Are there other CDNs missing from here?\nconst PRODUCTION_CDN_HOSTNAMES = [\n 'cdn.shopify.com',\n 'cdn.shopifycdn.net',\n 'shopify-assets.shopifycdn.com',\n 'shopify-assets.shopifycdn.net',\n];\nconst LOCAL_CDN_HOSTNAMES = ['spin.dev'];\nconst ALL_CDN_HOSTNAMES = [...PRODUCTION_CDN_HOSTNAMES, ...LOCAL_CDN_HOSTNAMES];\n// based on the default width sizes used by the Shopify liquid HTML tag img_tag plus a 2560 width to account for 2k resolutions\n// reference: https://shopify.dev/api/liquid/filters/html-filters#image_tag\nexport const IMG_SRC_SET_SIZES = [352, 832, 1200, 1920, 2560];\n/**\n * Adds image size parameters to an image URL hosted by Shopify's CDN\n */\nexport function addImageSizeParametersToUrl({ src, width, height, crop, scale, }) {\n const newUrl = new URL(src);\n const multipliedScale = scale ?? 1;\n if (width) {\n let finalWidth;\n if (typeof width === 'string') {\n finalWidth = (IMG_SRC_SET_SIZES[0] * multipliedScale).toString();\n }\n else {\n finalWidth = (Number(width) * multipliedScale).toString();\n }\n newUrl.searchParams.append('width', finalWidth);\n }\n if (height && typeof height === 'number') {\n newUrl.searchParams.append('height', (height * multipliedScale).toString());\n }\n crop && newUrl.searchParams.append('crop', crop);\n // for now we intentionally leave off the scale param, and instead multiple width & height by scale instead\n // scale && newUrl.searchParams.append('scale', scale.toString());\n return newUrl.toString();\n}\nexport function shopifyImageLoader(params) {\n const newSrc = new URL(params.src);\n const isShopifyServedImage = ALL_CDN_HOSTNAMES.some((allowedHostname) => newSrc.hostname.endsWith(allowedHostname));\n if (!isShopifyServedImage ||\n (!params.width && !params.height && !params.crop && !params.scale)) {\n return params.src;\n }\n return addImageSizeParametersToUrl(params);\n}\n/**\n * Width and height are determined using the followiing priority list:\n * 1. `loaderOptions`'s width/height\n * 2. `elementProps`'s width/height\n * 3. `data`'s width/height\n *\n * If only one of `width` or `height` are defined, then the other will attempt to be calculated based on the Image's aspect ratio,\n * provided that both `data.width` and `data.height` are available. If not, then the aspect ratio cannot be determined and the missing\n * value will reamin as `null`\n */\nexport function getShopifyImageDimensions({ data: sfapiImage, loaderOptions, elementProps, }) {\n let aspectRatio = null;\n if (sfapiImage?.width && sfapiImage?.height) {\n aspectRatio = sfapiImage?.width / sfapiImage?.height;\n }\n // * 1. `loaderOptions`'s width/height\n if (loaderOptions?.width || loaderOptions?.height) {\n return {\n width: loaderOptions?.width ??\n (aspectRatio && typeof loaderOptions.height === 'number'\n ? Math.round(aspectRatio * loaderOptions.height)\n : null),\n height: loaderOptions?.height ??\n (aspectRatio && typeof loaderOptions.width === 'number'\n ? Math.round(aspectRatio * loaderOptions.width)\n : null),\n };\n }\n // * 2. `elementProps`'s width/height\n if (elementProps?.width || elementProps?.height) {\n return {\n width: elementProps?.width ??\n (aspectRatio && typeof elementProps.height === 'number'\n ? Math.round(aspectRatio * elementProps.height)\n : null),\n height: elementProps?.height ??\n (aspectRatio && typeof elementProps.width === 'number'\n ? Math.round(aspectRatio * elementProps.width)\n : null),\n };\n }\n // * 3. `data`'s width/height\n if (sfapiImage?.width || sfapiImage?.height) {\n return {\n // can't calculate the aspect ratio here\n width: sfapiImage?.width ?? null,\n height: sfapiImage?.height ?? null,\n };\n }\n return { width: null, height: null };\n}\n","import * as React from 'react';\nimport { getShopifyImageDimensions, shopifyImageLoader, addImageSizeParametersToUrl, IMG_SRC_SET_SIZES, } from '../../utilities/index.js';\n/**\n * The `Image` component renders an image for the Storefront API's\n * [Image object](https://shopify.dev/api/storefront/reference/common-objects/image) by using the `data` prop, or a custom location by using the `src` prop. You can [customize this component](https://shopify.dev/api/hydrogen/components#customizing-hydrogen-components) using passthrough props.\n *\n * An image's width and height are determined using the following priority list:\n * 1. The width and height values for the `loaderOptions` prop\n * 2. The width and height values for bare props\n * 3. The width and height values for the `data` prop\n *\n * If only one of `width` or `height` are defined, then the other will attempt to be calculated based on the image's aspect ratio,\n * provided that both `data.width` and `data.height` are available. If `data.width` and `data.height` aren't available, then the aspect ratio cannot be determined and the missing\n * value will remain as `null`\n */\nexport function Image(props) {\n if (!props.data && !props.src) {\n throw new Error(`: requires either a 'data' or 'src' prop.`);\n }\n if (__HYDROGEN_DEV__ && props.data && props.src) {\n console.warn(`: using both 'data' and 'src' props is not supported; using the 'data' prop by default`);\n }\n if (props.data) {\n return React.createElement(ShopifyImage, { ...props });\n }\n else {\n return React.createElement(ExternalImage, { ...props });\n }\n}\nfunction ShopifyImage({ data, width, height, loading, loader = shopifyImageLoader, loaderOptions, widths, decoding = 'async', ...rest }) {\n if (!data.url) {\n throw new Error(`: the 'data' prop requires the 'url' property`);\n }\n if (__HYDROGEN_DEV__ && !data.altText && !rest.alt) {\n console.warn(`: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. ${`Image: ${data.id ?? data.url}`}`);\n }\n const { width: imgElementWidth, height: imgElementHeight } = getShopifyImageDimensions({\n data,\n loaderOptions,\n elementProps: {\n width,\n height,\n },\n });\n if (__HYDROGEN_DEV__ && (!imgElementWidth || !imgElementHeight)) {\n console.warn(`: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties. ${`Image: ${data.id ?? data.url}`}`);\n }\n let finalSrc = data.url;\n if (loader) {\n finalSrc = loader({\n ...loaderOptions,\n src: data.url,\n width: imgElementWidth,\n height: imgElementHeight,\n });\n if (typeof finalSrc !== 'string' || !finalSrc) {\n throw new Error(`: 'loader' did not return a valid string. ${`Image: ${data.id ?? data.url}`}`);\n }\n }\n // determining what the intended width of the image is. For example, if the width is specified and lower than the image width, then that is the maximum image width\n // to prevent generating a srcset with widths bigger than needed or to generate images that would distort because of being larger than original\n const maxWidth = width && imgElementWidth && width < imgElementWidth\n ? width\n : imgElementWidth;\n const finalSrcset = rest.srcSet ??\n internalImageSrcSet({\n ...loaderOptions,\n widths,\n src: data.url,\n width: maxWidth,\n height: imgElementHeight,\n loader,\n });\n /* eslint-disable hydrogen/prefer-image-component */\n return (React.createElement(\"img\", { id: data.id ?? '', alt: data.altText ?? rest.alt ?? '', loading: loading ?? 'lazy', ...rest, src: finalSrc, width: imgElementWidth ?? undefined, height: imgElementHeight ?? undefined, srcSet: finalSrcset, decoding: decoding }));\n /* eslint-enable hydrogen/prefer-image-component */\n}\nfunction ExternalImage({ src, width, height, alt, loader, loaderOptions, widths, loading, decoding = 'async', ...rest }) {\n if (!width || !height) {\n throw new Error(`: when 'src' is provided, 'width' and 'height' are required and need to be valid values (i.e. greater than zero). Provided values: 'src': ${src}, 'width': ${width}, 'height': ${height}`);\n }\n if (__HYDROGEN_DEV__ && !alt) {\n console.warn(`: when 'src' is provided, 'alt' should also be provided. ${`Image: ${src}`}`);\n }\n if (widths &&\n Array.isArray(widths) &&\n widths.some((size) => isNaN(size)))\n throw new Error(`: the 'widths' property must be an array of numbers`);\n let finalSrc = src;\n if (loader) {\n finalSrc = loader({ src, width, height, ...loaderOptions });\n if (typeof finalSrc !== 'string' || !finalSrc) {\n throw new Error(`: 'loader' did not return a valid string`);\n }\n }\n let finalSrcset = rest.srcSet ?? undefined;\n if (!finalSrcset && loader && widths) {\n // Height is a requirement in the LoaderProps, so to keep the aspect ratio, we must determine the height based on the default values\n const heightToWidthRatio = parseInt(height.toString()) / parseInt(width.toString());\n finalSrcset = widths\n ?.map((width) => parseInt(width, 10))\n ?.map((width) => `${loader({\n ...loaderOptions,\n src,\n width,\n height: Math.floor(width * heightToWidthRatio),\n })} ${width}w`)\n .join(', ');\n }\n /* eslint-disable hydrogen/prefer-image-component */\n return (React.createElement(\"img\", { ...rest, src: finalSrc, \n // @ts-expect-error TS doesn't understand that it could exist\n width: loaderOptions?.width ?? width, \n // @ts-expect-error TS doesn't understand that it could exist\n height: loaderOptions?.height ?? height, alt: alt ?? '', loading: loading ?? 'lazy', srcSet: finalSrcset, decoding: decoding }));\n /* eslint-enable hydrogen/prefer-image-component */\n}\nfunction internalImageSrcSet({ src, width, crop, scale, widths, loader, height, }) {\n const hasCustomWidths = widths && Array.isArray(widths);\n if (hasCustomWidths && widths.some((size) => isNaN(size))) {\n throw new Error(`: the 'widths' must be an array of numbers`);\n }\n let aspectRatio = 1;\n if (width && height) {\n aspectRatio = Number(height) / Number(width);\n }\n let setSizes = hasCustomWidths ? widths : IMG_SRC_SET_SIZES;\n if (!hasCustomWidths &&\n width &&\n width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1]) {\n setSizes = IMG_SRC_SET_SIZES.filter((size) => size <= width);\n }\n const srcGenerator = loader ? loader : addImageSizeParametersToUrl;\n return setSizes\n .map((size) => `${srcGenerator({\n src,\n width: size,\n // height is not applied if there is no crop\n // if there is crop, then height is applied as a ratio of the original width + height aspect ratio * size\n height: crop ? Number(size) * aspectRatio : undefined,\n crop,\n scale,\n })} ${size}w`)\n .join(', ');\n}\n"],"names":["PRODUCTION_CDN_HOSTNAMES","LOCAL_CDN_HOSTNAMES","ALL_CDN_HOSTNAMES","IMG_SRC_SET_SIZES","addImageSizeParametersToUrl","src","width","height","crop","scale","newUrl","multipliedScale","finalWidth","shopifyImageLoader","params","newSrc","allowedHostname","getShopifyImageDimensions","sfapiImage","loaderOptions","elementProps","aspectRatio","_a","_b","_c","_d","_e","_f","Image","props","React.createElement","ShopifyImage","ExternalImage","data","loading","loader","widths","decoding","rest","imgElementWidth","imgElementHeight","finalSrc","maxWidth","finalSrcset","internalImageSrcSet","alt","size","heightToWidthRatio","hasCustomWidths","setSizes","srcGenerator"],"mappings":"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"}