@shopify/hydrogen-react 2022.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +218 -0
- package/dist/dev/ExternalVideo.cjs +39 -0
- package/dist/dev/ExternalVideo.cjs.map +1 -0
- package/dist/dev/ExternalVideo.js +39 -0
- package/dist/dev/ExternalVideo.js.map +1 -0
- package/dist/dev/Image.cjs +104 -0
- package/dist/dev/Image.cjs.map +1 -0
- package/dist/dev/Image.js +104 -0
- package/dist/dev/Image.js.map +1 -0
- package/dist/dev/MediaFile.cjs +57 -0
- package/dist/dev/MediaFile.cjs.map +1 -0
- package/dist/dev/MediaFile.js +57 -0
- package/dist/dev/MediaFile.js.map +1 -0
- package/dist/dev/Metafield.cjs +295 -0
- package/dist/dev/Metafield.cjs.map +1 -0
- package/dist/dev/Metafield.js +295 -0
- package/dist/dev/Metafield.js.map +1 -0
- package/dist/dev/ModelViewer.cjs +145 -0
- package/dist/dev/ModelViewer.cjs.map +1 -0
- package/dist/dev/ModelViewer.js +145 -0
- package/dist/dev/ModelViewer.js.map +1 -0
- package/dist/dev/Money.cjs +40 -0
- package/dist/dev/Money.cjs.map +1 -0
- package/dist/dev/Money.js +40 -0
- package/dist/dev/Money.js.map +1 -0
- package/dist/dev/ProductPrice.cjs +61 -0
- package/dist/dev/ProductPrice.cjs.map +1 -0
- package/dist/dev/ProductPrice.js +61 -0
- package/dist/dev/ProductPrice.js.map +1 -0
- package/dist/dev/ProductProvider.cjs +161 -0
- package/dist/dev/ProductProvider.cjs.map +1 -0
- package/dist/dev/ProductProvider.js +161 -0
- package/dist/dev/ProductProvider.js.map +1 -0
- package/dist/dev/ShopPayButton.cjs +64 -0
- package/dist/dev/ShopPayButton.cjs.map +1 -0
- package/dist/dev/ShopPayButton.js +64 -0
- package/dist/dev/ShopPayButton.js.map +1 -0
- package/dist/dev/ShopifyProvider.cjs +46 -0
- package/dist/dev/ShopifyProvider.cjs.map +1 -0
- package/dist/dev/ShopifyProvider.js +46 -0
- package/dist/dev/ShopifyProvider.js.map +1 -0
- package/dist/dev/Video.cjs +44 -0
- package/dist/dev/Video.cjs.map +1 -0
- package/dist/dev/Video.js +44 -0
- package/dist/dev/Video.js.map +1 -0
- package/dist/dev/flatten-connection.cjs +23 -0
- package/dist/dev/flatten-connection.cjs.map +1 -0
- package/dist/dev/flatten-connection.js +23 -0
- package/dist/dev/flatten-connection.js.map +1 -0
- package/dist/dev/image-size.cjs +80 -0
- package/dist/dev/image-size.cjs.map +1 -0
- package/dist/dev/image-size.js +80 -0
- package/dist/dev/image-size.js.map +1 -0
- package/dist/dev/index.cjs +35 -0
- package/dist/dev/index.cjs.map +1 -0
- package/dist/dev/index.js +35 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/dev/load-script.cjs +52 -0
- package/dist/dev/load-script.cjs.map +1 -0
- package/dist/dev/load-script.js +52 -0
- package/dist/dev/load-script.js.map +1 -0
- package/dist/dev/storefront-api-constants.cjs +5 -0
- package/dist/dev/storefront-api-constants.cjs.map +1 -0
- package/dist/dev/storefront-api-constants.js +5 -0
- package/dist/dev/storefront-api-constants.js.map +1 -0
- package/dist/dev/storefront-client.cjs +72 -0
- package/dist/dev/storefront-client.cjs.map +1 -0
- package/dist/dev/storefront-client.js +72 -0
- package/dist/dev/storefront-client.js.map +1 -0
- package/dist/dev/useMoney.cjs +72 -0
- package/dist/dev/useMoney.cjs.map +1 -0
- package/dist/dev/useMoney.js +72 -0
- package/dist/dev/useMoney.js.map +1 -0
- package/dist/prod/ExternalVideo.cjs +39 -0
- package/dist/prod/ExternalVideo.cjs.map +1 -0
- package/dist/prod/ExternalVideo.js +39 -0
- package/dist/prod/ExternalVideo.js.map +1 -0
- package/dist/prod/Image.cjs +99 -0
- package/dist/prod/Image.cjs.map +1 -0
- package/dist/prod/Image.js +99 -0
- package/dist/prod/Image.js.map +1 -0
- package/dist/prod/MediaFile.cjs +59 -0
- package/dist/prod/MediaFile.cjs.map +1 -0
- package/dist/prod/MediaFile.js +59 -0
- package/dist/prod/MediaFile.js.map +1 -0
- package/dist/prod/Metafield.cjs +288 -0
- package/dist/prod/Metafield.cjs.map +1 -0
- package/dist/prod/Metafield.js +288 -0
- package/dist/prod/Metafield.js.map +1 -0
- package/dist/prod/ModelViewer.cjs +143 -0
- package/dist/prod/ModelViewer.cjs.map +1 -0
- package/dist/prod/ModelViewer.js +143 -0
- package/dist/prod/ModelViewer.js.map +1 -0
- package/dist/prod/Money.cjs +40 -0
- package/dist/prod/Money.cjs.map +1 -0
- package/dist/prod/Money.js +40 -0
- package/dist/prod/Money.js.map +1 -0
- package/dist/prod/ProductPrice.cjs +61 -0
- package/dist/prod/ProductPrice.cjs.map +1 -0
- package/dist/prod/ProductPrice.js +61 -0
- package/dist/prod/ProductPrice.js.map +1 -0
- package/dist/prod/ProductProvider.cjs +161 -0
- package/dist/prod/ProductProvider.cjs.map +1 -0
- package/dist/prod/ProductProvider.js +161 -0
- package/dist/prod/ProductProvider.js.map +1 -0
- package/dist/prod/ShopPayButton.cjs +64 -0
- package/dist/prod/ShopPayButton.cjs.map +1 -0
- package/dist/prod/ShopPayButton.js +64 -0
- package/dist/prod/ShopPayButton.js.map +1 -0
- package/dist/prod/ShopifyProvider.cjs +46 -0
- package/dist/prod/ShopifyProvider.cjs.map +1 -0
- package/dist/prod/ShopifyProvider.js +46 -0
- package/dist/prod/ShopifyProvider.js.map +1 -0
- package/dist/prod/Video.cjs +44 -0
- package/dist/prod/Video.cjs.map +1 -0
- package/dist/prod/Video.js +44 -0
- package/dist/prod/Video.js.map +1 -0
- package/dist/prod/flatten-connection.cjs +18 -0
- package/dist/prod/flatten-connection.cjs.map +1 -0
- package/dist/prod/flatten-connection.js +18 -0
- package/dist/prod/flatten-connection.js.map +1 -0
- package/dist/prod/image-size.cjs +80 -0
- package/dist/prod/image-size.cjs.map +1 -0
- package/dist/prod/image-size.js +80 -0
- package/dist/prod/image-size.js.map +1 -0
- package/dist/prod/index.cjs +35 -0
- package/dist/prod/index.cjs.map +1 -0
- package/dist/prod/index.js +35 -0
- package/dist/prod/index.js.map +1 -0
- package/dist/prod/load-script.cjs +52 -0
- package/dist/prod/load-script.cjs.map +1 -0
- package/dist/prod/load-script.js +52 -0
- package/dist/prod/load-script.js.map +1 -0
- package/dist/prod/storefront-api-constants.cjs +5 -0
- package/dist/prod/storefront-api-constants.cjs.map +1 -0
- package/dist/prod/storefront-api-constants.js +5 -0
- package/dist/prod/storefront-api-constants.js.map +1 -0
- package/dist/prod/storefront-client.cjs +57 -0
- package/dist/prod/storefront-client.cjs.map +1 -0
- package/dist/prod/storefront-client.js +57 -0
- package/dist/prod/storefront-client.js.map +1 -0
- package/dist/prod/useMoney.cjs +72 -0
- package/dist/prod/useMoney.cjs.map +1 -0
- package/dist/prod/useMoney.js +72 -0
- package/dist/prod/useMoney.js.map +1 -0
- package/dist/types/ExternalVideo.d.ts +67 -0
- package/dist/types/Image.d.ts +54 -0
- package/dist/types/MediaFile.d.ts +31 -0
- package/dist/types/Metafield.d.ts +58 -0
- package/dist/types/ModelViewer.d.ts +57 -0
- package/dist/types/Money.d.ts +29 -0
- package/dist/types/ProductPrice.d.ts +22 -0
- package/dist/types/ProductProvider.d.ts +74 -0
- package/dist/types/ShopPayButton.d.ts +42 -0
- package/dist/types/ShopifyProvider.d.ts +42 -0
- package/dist/types/Video.d.ts +20 -0
- package/dist/types/flatten-connection.d.ts +17 -0
- package/dist/types/image-size.d.ts +36 -0
- package/dist/types/index.d.cts +15 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/load-script.d.ts +11 -0
- package/dist/types/storefront-api-constants.d.ts +1 -0
- package/dist/types/storefront-api-response.types.d.ts +68 -0
- package/dist/types/storefront-api-types.d.ts +6537 -0
- package/dist/types/storefront-client.d.ts +63 -0
- package/dist/types/useMoney.d.ts +55 -0
- package/dist/umd/hydrogen-react.dev.js +1472 -0
- package/dist/umd/hydrogen-react.dev.js.map +1 -0
- package/dist/umd/hydrogen-react.prod.js +3 -0
- package/dist/umd/hydrogen-react.prod.js.map +1 -0
- package/package.json +106 -0
- package/storefront.schema.json +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# @shopify/hydrogen-react
|
|
2
|
+
|
|
3
|
+
## IMPORTANT
|
|
4
|
+
|
|
5
|
+
This is an beta version of `@shopify/hydrogen-react`.
|
|
6
|
+
|
|
7
|
+
Refer to how this package is [versioned](../../README.md#versioning).
|
|
8
|
+
|
|
9
|
+
This document contains the following topics:
|
|
10
|
+
|
|
11
|
+
- [Getting started with Hydrogen UI](#getting-started)
|
|
12
|
+
- [Authenticating the Storefront API client](#authenticating-the-storefront-client)
|
|
13
|
+
- [Development and production bundles](#development-and-production-bundles)
|
|
14
|
+
- [Hydrogen UI in the browser](#hydrogen-ui-in-the-browser)
|
|
15
|
+
- [Enabling autocompletion for the Storefront API](#enable-storefront-api-graphql-autocompletion)
|
|
16
|
+
- [Setting TypeScript types for Storefront API objects](#set-typescript-types)
|
|
17
|
+
- [Troubleshooting](#troubleshooting)
|
|
18
|
+
|
|
19
|
+
## Getting started
|
|
20
|
+
|
|
21
|
+
- Run one of the following commands:
|
|
22
|
+
|
|
23
|
+
npm:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm i --save @shopify/hydrogen-react
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Yarn:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
yarn add @shopify/hydrogen-react
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Authenticating the Storefront client
|
|
36
|
+
|
|
37
|
+
To make it easier to query the Storefront API, Hydrogen UI exposes a helper function called `createStorefrontClient()`.
|
|
38
|
+
|
|
39
|
+
The client can take in the following tokens:
|
|
40
|
+
|
|
41
|
+
- **[Delegate access](https://shopify.dev/api/usage/authentication#getting-started-with-authenticated-access)**: Used for requests from a server or other private context. Set as `privateStorefrontToken`.
|
|
42
|
+
|
|
43
|
+
- **[Public](https://shopify.dev/api/usage/authentication#getting-started-with-public-access)**: Used for requests from a browser or other public context. Set as `publicAccessToken`.
|
|
44
|
+
|
|
45
|
+
The following is an example:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// Filename: '/shopify-client.js'
|
|
49
|
+
|
|
50
|
+
import {createStorefrontClient} from '@shopify/hydrogen-react';
|
|
51
|
+
|
|
52
|
+
const client = createStorefrontClient({
|
|
53
|
+
privateStorefrontToken: '...',
|
|
54
|
+
storeDomain: 'myshop',
|
|
55
|
+
storefrontApiVersion: '2022-07',
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
export const getStorefrontApiUrl = client.getStorefrontApiUrl;
|
|
59
|
+
export const getPrivateTokenHeaders = client.getPrivateTokenHeaders;
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
You can then use this in your server-side queries. Here's an example of using it for [NextJS's `getServerSideProps`](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props):
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
// Filename: '/pages/index.js'
|
|
66
|
+
|
|
67
|
+
import {
|
|
68
|
+
getStorefrontApiUrl,
|
|
69
|
+
getPrivateTokenHeaders,
|
|
70
|
+
} from '../shopify-client.js';
|
|
71
|
+
|
|
72
|
+
export async function getServerSideProps() {
|
|
73
|
+
const response = await fetch(getStorefrontApiUrl(), {
|
|
74
|
+
body: GRAPHQL_QUERY,
|
|
75
|
+
headers: getPrivateTokenHeaders({buyerIp: '...'}),
|
|
76
|
+
method: 'POST',
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const json = await response.json();
|
|
80
|
+
|
|
81
|
+
return {props: json};
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### (Optional) Set the content type for the Storefront client
|
|
86
|
+
|
|
87
|
+
By default, the Storefront client sends the `"content-type": "application/json"` header. Use the `json` content type when you have GraphQL variables and when the body is an object with the following shape:
|
|
88
|
+
|
|
89
|
+
```json
|
|
90
|
+
{
|
|
91
|
+
"query": "...",
|
|
92
|
+
"operationName": "...",
|
|
93
|
+
"variables": { "myVariable": "someValue", ... }
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
However, when the body is only a query string, such as `{"..."}`, you can optionally change the default header to `application/graphql`:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
createStorefrontClient({contentType: 'graphql', ...})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Alternatively, each time you get the headers you can customize which `"content-type"` you want, for only that one invocation:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
getPrivateTokenHeaders({contentType: 'graphql'});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Note:** If you're using TypeScript, then you can [improve the typing experience](#set-typescript-types).
|
|
110
|
+
|
|
111
|
+
## Development and production bundles
|
|
112
|
+
|
|
113
|
+
Hydrogen UI has a development bundle and a production bundle. The development bundle has warnings and messages that the production bundle doesn't.
|
|
114
|
+
|
|
115
|
+
Depending on the bundler or runtime that you're using, the correct bundle might be automatically chosen following the `package.json#exports` of Hydrogen UI. If not, then you might need to configure your bundler / runtime to use the `development` and `production` conditions.
|
|
116
|
+
|
|
117
|
+
**Note:** The production bundle is used by default if your bundler / runtime doesn't understand the export conditions.
|
|
118
|
+
|
|
119
|
+
## Hydrogen UI in the browser
|
|
120
|
+
|
|
121
|
+
Hydrogen UI has a development `umd` build and a production `umd` build. Both are meant to be used directly either by `<script src=""></script>` tags in HTML or by `AMD`-compatible loaders.
|
|
122
|
+
|
|
123
|
+
If you're using Hydrogen UI as a global through the `<script>` tag, then the components can be accessed through the `hydrogenreact` global variable.
|
|
124
|
+
|
|
125
|
+
## Enable Storefront API GraphQL autocompletion
|
|
126
|
+
|
|
127
|
+
To improve your development experience, enable GraphQL autocompletion for the Storefront API in your integrated development environment (IDE).
|
|
128
|
+
|
|
129
|
+
1. Add [`graphql`](https://www.npmjs.com/package/graphql) and [GraphQL-config](https://www.graphql-config.com/docs/user/user-installation) with the following command:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
yarn add --dev graphql graphql-config
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
1. Create a [GraphQL config file](https://www.graphql-config.com/docs/user/user-usage) at the root of your code. For example, `.graphqlrc.yml`.
|
|
136
|
+
1. Add a [`schema`](https://www.graphql-config.com/docs/user/user-schema) and point it to Hydrogen UI's bundled schema for the Storefront API.
|
|
137
|
+
|
|
138
|
+
For example:
|
|
139
|
+
|
|
140
|
+
```yml
|
|
141
|
+
# Filename: .graphqlrc.yml
|
|
142
|
+
schema: node_modules/@shopify/hydrogen-react/storefront.schema.json
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
1. Install a GraphQL extension in your IDE, such as the [GraphQL extension for VSCode](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql).
|
|
146
|
+
|
|
147
|
+
GraphQL autocompletion and validation will now work in `.graphql` files and in [`gql`](https://github.com/apollographql/graphql-tag) template literals!
|
|
148
|
+
|
|
149
|
+
If you're having trouble getting it to work, then consult our [troubleshooting section](#graphql-autocompletion).
|
|
150
|
+
|
|
151
|
+
## Set TypeScript types
|
|
152
|
+
|
|
153
|
+
Improve your development experience by adding strong typing to Storefront API responses. The following are some options for doing this.
|
|
154
|
+
|
|
155
|
+
### Use the `StorefrontApiResponseError` and `StorefrontApiResponseOk` helpers
|
|
156
|
+
|
|
157
|
+
The following is an example:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import {
|
|
161
|
+
type StorefrontApiResponseError,
|
|
162
|
+
type StorefrontApiResponseOk,
|
|
163
|
+
} from '@shopify/hydrogen-react';
|
|
164
|
+
|
|
165
|
+
async function FetchApi<DataGeneric>() {
|
|
166
|
+
const apiResponse = await fetch('...');
|
|
167
|
+
|
|
168
|
+
if (!apiResponse.ok) {
|
|
169
|
+
// 400 or 500 level error
|
|
170
|
+
return (await apiResponse.text()) as StorefrontApiResponseError; // or apiResponse.json()
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const graphqlResponse: StorefrontApiResponseOk<DataGeneric> =
|
|
174
|
+
await apiResponse.json();
|
|
175
|
+
|
|
176
|
+
// You can now access 'graphqlResponse.data' and 'graphqlResponse.errors'
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Use the `StorefrontApiResponse` helper
|
|
181
|
+
|
|
182
|
+
If you're using a library that handles 400/500 level errors for you, then you can use `StorefrontApiResponse`. To add typing to objects that are trying to match a Storefront API object shape, you can import the shape.
|
|
183
|
+
|
|
184
|
+
The following is an example:
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import type {Product} from '@shopify/hydrogen-react/storefront-api-types';
|
|
188
|
+
|
|
189
|
+
const product: Product = {};
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Use TypeScript's helpers
|
|
193
|
+
|
|
194
|
+
To create your own object shapes, you can use TypeScript's built-in helpers.
|
|
195
|
+
|
|
196
|
+
The following is an example:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const partialProduct: Partial<Product> = {};
|
|
200
|
+
|
|
201
|
+
const productTitle: Pick<Product, 'title'> = '';
|
|
202
|
+
|
|
203
|
+
const productExceptTitle: Omit<Product, 'title'> = {};
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Troubleshooting
|
|
207
|
+
|
|
208
|
+
The following will help you troubleshoot common problems in this version of Hydrogen UI.
|
|
209
|
+
|
|
210
|
+
### GraphQL autocompletion
|
|
211
|
+
|
|
212
|
+
If you can't get [GraphQL autocompletion](<(#storefront-api-graphql-autocompletion)>) to work, then try restarting the GraphQL server in your IDE.
|
|
213
|
+
|
|
214
|
+
For example, in VSCode do the following:
|
|
215
|
+
|
|
216
|
+
1. Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).
|
|
217
|
+
1. Type `graphql`.
|
|
218
|
+
1. Select `VSCode GraphQL: Manual Restart`.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
function ExternalVideo(props) {
|
|
5
|
+
var _a, _b;
|
|
6
|
+
const {
|
|
7
|
+
data,
|
|
8
|
+
options,
|
|
9
|
+
id = data.id,
|
|
10
|
+
frameBorder = "0",
|
|
11
|
+
allow = "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture",
|
|
12
|
+
allowFullScreen = true,
|
|
13
|
+
loading = "lazy",
|
|
14
|
+
...passthroughProps
|
|
15
|
+
} = props;
|
|
16
|
+
if (!data.embedUrl) {
|
|
17
|
+
throw new Error(`<ExternalVideo/> requires the 'embedUrl' property`);
|
|
18
|
+
}
|
|
19
|
+
let finalUrl = data.embedUrl;
|
|
20
|
+
if (options) {
|
|
21
|
+
const urlObject = new URL(data.embedUrl);
|
|
22
|
+
for (const key of Object.keys(options)) {
|
|
23
|
+
urlObject.searchParams.set(key, options[key]);
|
|
24
|
+
}
|
|
25
|
+
finalUrl = urlObject.toString();
|
|
26
|
+
}
|
|
27
|
+
return /* @__PURE__ */ jsxRuntime.jsx("iframe", {
|
|
28
|
+
...passthroughProps,
|
|
29
|
+
id: id != null ? id : data.embedUrl,
|
|
30
|
+
title: (_b = (_a = data.alt) != null ? _a : data.id) != null ? _b : "external video",
|
|
31
|
+
frameBorder,
|
|
32
|
+
allow,
|
|
33
|
+
allowFullScreen,
|
|
34
|
+
src: finalUrl,
|
|
35
|
+
loading
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
exports.ExternalVideo = ExternalVideo;
|
|
39
|
+
//# sourceMappingURL=ExternalVideo.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalVideo.cjs","sources":["../../src/ExternalVideo.tsx"],"sourcesContent":["import type {ExternalVideo as ExternalVideoType} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\ninterface BaseProps {\n /**\n * An object with fields that correspond to the Storefront API's [ExternalVideo object](https://shopify.dev/api/storefront/reference/products/externalvideo).\n */\n data: PartialDeep<ExternalVideoType, {recurseIntoArrays: true}>;\n /** An object containing the options available for either\n * [YouTube](https://developers.google.com/youtube/player_parameters#Parameters) or\n * [Vimeo](https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Using-Player-Parameters).\n */\n options?: YouTube | Vimeo;\n}\n\ntype PropsWeControl = 'src';\n\nexport type ExternalVideoProps = Omit<\n JSX.IntrinsicElements['iframe'],\n PropsWeControl\n> &\n BaseProps;\n\n/**\n * The `ExternalVideo` component renders an embedded video for the Storefront\n * API's [ExternalVideo object](https://shopify.dev/api/storefront/reference/products/externalvideo).\n */\nexport function ExternalVideo(props: ExternalVideoProps) {\n const {\n data,\n options,\n id = data.id,\n frameBorder = '0',\n allow = 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',\n allowFullScreen = true,\n loading = 'lazy',\n ...passthroughProps\n } = props;\n\n if (!data.embedUrl) {\n throw new Error(`<ExternalVideo/> requires the 'embedUrl' property`);\n }\n\n let finalUrl: string = data.embedUrl;\n\n if (options) {\n const urlObject = new URL(data.embedUrl);\n for (const key of Object.keys(options)) {\n // @ts-expect-error https://github.com/microsoft/TypeScript/issues/32951\n urlObject.searchParams.set(key, options[key]);\n }\n finalUrl = urlObject.toString();\n }\n\n return (\n <iframe\n {...passthroughProps}\n id={id ?? data.embedUrl}\n title={data.alt ?? data.id ?? 'external video'}\n frameBorder={frameBorder}\n allow={allow}\n allowFullScreen={allowFullScreen}\n src={finalUrl}\n loading={loading}\n ></iframe>\n );\n}\n\ninterface YouTube {\n autoplay?: 0 | 1;\n cc_lang_pref?: string;\n cc_load_policy?: 1;\n color?: 'red' | 'white';\n controls?: 0 | 1;\n disablekb?: 0 | 1;\n enablejsapi?: 0 | 1;\n end?: number;\n fs?: 0 | 1;\n hl?: string;\n iv_load_policy?: 1 | 3;\n list?: string;\n list_type?: 'playlist' | 'user_uploads';\n loop?: 0 | 1;\n modest_branding?: 1;\n origin?: string;\n playlist?: string;\n plays_inline?: 0 | 1;\n rel?: 0 | 1;\n start?: number;\n widget_referrer?: string;\n}\n\ntype VimeoBoolean = 0 | 1 | boolean;\n\ninterface Vimeo {\n autopause?: VimeoBoolean;\n autoplay?: VimeoBoolean;\n background?: VimeoBoolean;\n byline?: VimeoBoolean;\n color?: string;\n controls?: VimeoBoolean;\n dnt?: VimeoBoolean;\n loop?: VimeoBoolean;\n muted?: VimeoBoolean;\n pip?: VimeoBoolean;\n playsinline?: VimeoBoolean;\n portrait?: VimeoBoolean;\n quality?: '240p' | '360p' | '540p' | '720p' | '1080p' | '2k' | '4k';\n speed?: VimeoBoolean;\n '#t'?: string;\n texttrack?: string;\n title?: VimeoBoolean;\n transparent?: VimeoBoolean;\n}\n"],"names":["ExternalVideo","props","data","options","id","frameBorder","allow","allowFullScreen","loading","passthroughProps","embedUrl","Error","finalUrl","urlObject","URL","key","Object","keys","searchParams","set","toString","alt"],"mappings":";;;AA2BO,SAASA,cAAcC,OAA2B;;AACjD,QAAA;AAAA,IACJC;AAAAA,IACAC;AAAAA,IACAC,KAAKF,KAAKE;AAAAA,IACVC,cAAc;AAAA,IACdC,QAAQ;AAAA,IACRC,kBAAkB;AAAA,IAClBC,UAAU;AAAA,OACPC;AAAAA,EACDR,IAAAA;AAEA,MAAA,CAACC,KAAKQ,UAAU;AACZ,UAAA,IAAIC,MAAO,mDAAX;AAAA,EACP;AAED,MAAIC,WAAmBV,KAAKQ;AAE5B,MAAIP,SAAS;AACX,UAAMU,YAAY,IAAIC,IAAIZ,KAAKQ,QAAb;AAClB,eAAWK,OAAOC,OAAOC,KAAKd,OAAZ,GAAsB;AAEtCU,gBAAUK,aAAaC,IAAIJ,KAAKZ,QAAQY,IAAxC;AAAA,IACD;AACDH,eAAWC,UAAUO;EACtB;AAED;OAEQX;AAAAA,IACJ,IAAIL,kBAAMF,KAAKQ;AAAAA,IACf,QAAOR,gBAAKmB,QAALnB,YAAYA,KAAKE,OAAjBF,YAAuB;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAKU;AAAAA,IACL;AAAA,EAAA,CATJ;AAYD;;"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
function ExternalVideo(props) {
|
|
3
|
+
var _a, _b;
|
|
4
|
+
const {
|
|
5
|
+
data,
|
|
6
|
+
options,
|
|
7
|
+
id = data.id,
|
|
8
|
+
frameBorder = "0",
|
|
9
|
+
allow = "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture",
|
|
10
|
+
allowFullScreen = true,
|
|
11
|
+
loading = "lazy",
|
|
12
|
+
...passthroughProps
|
|
13
|
+
} = props;
|
|
14
|
+
if (!data.embedUrl) {
|
|
15
|
+
throw new Error(`<ExternalVideo/> requires the 'embedUrl' property`);
|
|
16
|
+
}
|
|
17
|
+
let finalUrl = data.embedUrl;
|
|
18
|
+
if (options) {
|
|
19
|
+
const urlObject = new URL(data.embedUrl);
|
|
20
|
+
for (const key of Object.keys(options)) {
|
|
21
|
+
urlObject.searchParams.set(key, options[key]);
|
|
22
|
+
}
|
|
23
|
+
finalUrl = urlObject.toString();
|
|
24
|
+
}
|
|
25
|
+
return /* @__PURE__ */ jsx("iframe", {
|
|
26
|
+
...passthroughProps,
|
|
27
|
+
id: id != null ? id : data.embedUrl,
|
|
28
|
+
title: (_b = (_a = data.alt) != null ? _a : data.id) != null ? _b : "external video",
|
|
29
|
+
frameBorder,
|
|
30
|
+
allow,
|
|
31
|
+
allowFullScreen,
|
|
32
|
+
src: finalUrl,
|
|
33
|
+
loading
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
export {
|
|
37
|
+
ExternalVideo
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=ExternalVideo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExternalVideo.js","sources":["../../src/ExternalVideo.tsx"],"sourcesContent":["import type {ExternalVideo as ExternalVideoType} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\ninterface BaseProps {\n /**\n * An object with fields that correspond to the Storefront API's [ExternalVideo object](https://shopify.dev/api/storefront/reference/products/externalvideo).\n */\n data: PartialDeep<ExternalVideoType, {recurseIntoArrays: true}>;\n /** An object containing the options available for either\n * [YouTube](https://developers.google.com/youtube/player_parameters#Parameters) or\n * [Vimeo](https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Using-Player-Parameters).\n */\n options?: YouTube | Vimeo;\n}\n\ntype PropsWeControl = 'src';\n\nexport type ExternalVideoProps = Omit<\n JSX.IntrinsicElements['iframe'],\n PropsWeControl\n> &\n BaseProps;\n\n/**\n * The `ExternalVideo` component renders an embedded video for the Storefront\n * API's [ExternalVideo object](https://shopify.dev/api/storefront/reference/products/externalvideo).\n */\nexport function ExternalVideo(props: ExternalVideoProps) {\n const {\n data,\n options,\n id = data.id,\n frameBorder = '0',\n allow = 'accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture',\n allowFullScreen = true,\n loading = 'lazy',\n ...passthroughProps\n } = props;\n\n if (!data.embedUrl) {\n throw new Error(`<ExternalVideo/> requires the 'embedUrl' property`);\n }\n\n let finalUrl: string = data.embedUrl;\n\n if (options) {\n const urlObject = new URL(data.embedUrl);\n for (const key of Object.keys(options)) {\n // @ts-expect-error https://github.com/microsoft/TypeScript/issues/32951\n urlObject.searchParams.set(key, options[key]);\n }\n finalUrl = urlObject.toString();\n }\n\n return (\n <iframe\n {...passthroughProps}\n id={id ?? data.embedUrl}\n title={data.alt ?? data.id ?? 'external video'}\n frameBorder={frameBorder}\n allow={allow}\n allowFullScreen={allowFullScreen}\n src={finalUrl}\n loading={loading}\n ></iframe>\n );\n}\n\ninterface YouTube {\n autoplay?: 0 | 1;\n cc_lang_pref?: string;\n cc_load_policy?: 1;\n color?: 'red' | 'white';\n controls?: 0 | 1;\n disablekb?: 0 | 1;\n enablejsapi?: 0 | 1;\n end?: number;\n fs?: 0 | 1;\n hl?: string;\n iv_load_policy?: 1 | 3;\n list?: string;\n list_type?: 'playlist' | 'user_uploads';\n loop?: 0 | 1;\n modest_branding?: 1;\n origin?: string;\n playlist?: string;\n plays_inline?: 0 | 1;\n rel?: 0 | 1;\n start?: number;\n widget_referrer?: string;\n}\n\ntype VimeoBoolean = 0 | 1 | boolean;\n\ninterface Vimeo {\n autopause?: VimeoBoolean;\n autoplay?: VimeoBoolean;\n background?: VimeoBoolean;\n byline?: VimeoBoolean;\n color?: string;\n controls?: VimeoBoolean;\n dnt?: VimeoBoolean;\n loop?: VimeoBoolean;\n muted?: VimeoBoolean;\n pip?: VimeoBoolean;\n playsinline?: VimeoBoolean;\n portrait?: VimeoBoolean;\n quality?: '240p' | '360p' | '540p' | '720p' | '1080p' | '2k' | '4k';\n speed?: VimeoBoolean;\n '#t'?: string;\n texttrack?: string;\n title?: VimeoBoolean;\n transparent?: VimeoBoolean;\n}\n"],"names":["ExternalVideo","props","data","options","id","frameBorder","allow","allowFullScreen","loading","passthroughProps","embedUrl","Error","finalUrl","urlObject","URL","key","Object","keys","searchParams","set","toString","alt"],"mappings":";AA2BO,SAASA,cAAcC,OAA2B;;AACjD,QAAA;AAAA,IACJC;AAAAA,IACAC;AAAAA,IACAC,KAAKF,KAAKE;AAAAA,IACVC,cAAc;AAAA,IACdC,QAAQ;AAAA,IACRC,kBAAkB;AAAA,IAClBC,UAAU;AAAA,OACPC;AAAAA,EACDR,IAAAA;AAEA,MAAA,CAACC,KAAKQ,UAAU;AACZ,UAAA,IAAIC,MAAO,mDAAX;AAAA,EACP;AAED,MAAIC,WAAmBV,KAAKQ;AAE5B,MAAIP,SAAS;AACX,UAAMU,YAAY,IAAIC,IAAIZ,KAAKQ,QAAb;AAClB,eAAWK,OAAOC,OAAOC,KAAKd,OAAZ,GAAsB;AAEtCU,gBAAUK,aAAaC,IAAIJ,KAAKZ,QAAQY,IAAxC;AAAA,IACD;AACDH,eAAWC,UAAUO;EACtB;AAED;OAEQX;AAAAA,IACJ,IAAIL,kBAAMF,KAAKQ;AAAAA,IACf,QAAOR,gBAAKmB,QAALnB,YAAYA,KAAKE,OAAjBF,YAAuB;AAAA,IAC9B;AAAA,IACA;AAAA,IACA;AAAA,IACA,KAAKU;AAAAA,IACL;AAAA,EAAA,CATJ;AAYD;"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const imageSize = require("./image-size.cjs");
|
|
4
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
5
|
+
function Image({
|
|
6
|
+
data,
|
|
7
|
+
width,
|
|
8
|
+
height,
|
|
9
|
+
loading,
|
|
10
|
+
loader = imageSize.shopifyImageLoader,
|
|
11
|
+
loaderOptions,
|
|
12
|
+
widths,
|
|
13
|
+
decoding = "async",
|
|
14
|
+
...rest
|
|
15
|
+
}) {
|
|
16
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
17
|
+
if (!data.url) {
|
|
18
|
+
const missingUrlError = `<Image/>: the 'data' prop requires the 'url' property. Image: ${(_a = data.id) != null ? _a : "no ID provided"}`;
|
|
19
|
+
{
|
|
20
|
+
throw new Error(missingUrlError);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (!data.altText && !rest.alt) {
|
|
24
|
+
console.warn(`<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. Image: ${(_b = data.id) != null ? _b : data.url}`);
|
|
25
|
+
}
|
|
26
|
+
const {
|
|
27
|
+
width: imgElementWidth,
|
|
28
|
+
height: imgElementHeight
|
|
29
|
+
} = imageSize.getShopifyImageDimensions({
|
|
30
|
+
data,
|
|
31
|
+
loaderOptions,
|
|
32
|
+
elementProps: {
|
|
33
|
+
width,
|
|
34
|
+
height
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
if (!imgElementWidth || !imgElementHeight) {
|
|
38
|
+
console.warn(`<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties. Image: ${(_c = data.id) != null ? _c : data.url}`);
|
|
39
|
+
}
|
|
40
|
+
let finalSrc = data.url;
|
|
41
|
+
if (loader) {
|
|
42
|
+
finalSrc = loader({
|
|
43
|
+
...loaderOptions,
|
|
44
|
+
src: data.url,
|
|
45
|
+
width: imgElementWidth,
|
|
46
|
+
height: imgElementHeight
|
|
47
|
+
});
|
|
48
|
+
if (typeof finalSrc !== "string" || !finalSrc) {
|
|
49
|
+
throw new Error(`<Image/>: 'loader' did not return a valid string. Image: ${(_d = data.id) != null ? _d : data.url}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const maxWidth = width && imgElementWidth && width < imgElementWidth ? width : imgElementWidth;
|
|
53
|
+
const finalSrcset = (_e = rest.srcSet) != null ? _e : internalImageSrcSet({
|
|
54
|
+
...loaderOptions,
|
|
55
|
+
widths,
|
|
56
|
+
src: data.url,
|
|
57
|
+
width: maxWidth,
|
|
58
|
+
height: imgElementHeight,
|
|
59
|
+
loader
|
|
60
|
+
});
|
|
61
|
+
return /* @__PURE__ */ jsxRuntime.jsx("img", {
|
|
62
|
+
id: (_f = data.id) != null ? _f : "",
|
|
63
|
+
alt: (_h = (_g = data.altText) != null ? _g : rest.alt) != null ? _h : "",
|
|
64
|
+
loading: loading != null ? loading : "lazy",
|
|
65
|
+
...rest,
|
|
66
|
+
src: finalSrc,
|
|
67
|
+
width: imgElementWidth != null ? imgElementWidth : void 0,
|
|
68
|
+
height: imgElementHeight != null ? imgElementHeight : void 0,
|
|
69
|
+
srcSet: finalSrcset,
|
|
70
|
+
decoding
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function internalImageSrcSet({
|
|
74
|
+
src,
|
|
75
|
+
width,
|
|
76
|
+
crop,
|
|
77
|
+
scale,
|
|
78
|
+
widths,
|
|
79
|
+
loader,
|
|
80
|
+
height
|
|
81
|
+
}) {
|
|
82
|
+
const hasCustomWidths = widths && Array.isArray(widths);
|
|
83
|
+
if (hasCustomWidths && widths.some((size) => isNaN(size))) {
|
|
84
|
+
throw new Error(`<Image/>: the 'widths' must be an array of numbers. Image: ${src}`);
|
|
85
|
+
}
|
|
86
|
+
let aspectRatio = 1;
|
|
87
|
+
if (width && height) {
|
|
88
|
+
aspectRatio = Number(height) / Number(width);
|
|
89
|
+
}
|
|
90
|
+
let setSizes = hasCustomWidths ? widths : imageSize.IMG_SRC_SET_SIZES;
|
|
91
|
+
if (!hasCustomWidths && width && width < imageSize.IMG_SRC_SET_SIZES[imageSize.IMG_SRC_SET_SIZES.length - 1]) {
|
|
92
|
+
setSizes = imageSize.IMG_SRC_SET_SIZES.filter((size) => size <= width);
|
|
93
|
+
}
|
|
94
|
+
const srcGenerator = loader ? loader : imageSize.addImageSizeParametersToUrl;
|
|
95
|
+
return setSizes.map((size) => `${srcGenerator({
|
|
96
|
+
src,
|
|
97
|
+
width: size,
|
|
98
|
+
height: crop ? Number(size) * aspectRatio : void 0,
|
|
99
|
+
crop,
|
|
100
|
+
scale
|
|
101
|
+
})} ${size}w`).join(", ");
|
|
102
|
+
}
|
|
103
|
+
exports.Image = Image;
|
|
104
|
+
//# sourceMappingURL=Image.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Image.cjs","sources":["../../src/Image.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n getShopifyImageDimensions,\n shopifyImageLoader,\n addImageSizeParametersToUrl,\n IMG_SRC_SET_SIZES,\n} from './image-size.js';\nimport type {Image as ImageType} from './storefront-api-types.js';\nimport type {PartialDeep, Simplify} from 'type-fest';\n\ntype HtmlImageProps = React.ImgHTMLAttributes<HTMLImageElement>;\n\nexport type ShopifyLoaderOptions = {\n crop?: 'top' | 'bottom' | 'left' | 'right' | 'center';\n scale?: 2 | 3;\n width?: HtmlImageProps['width'] | ImageType['width'];\n height?: HtmlImageProps['height'] | ImageType['height'];\n};\nexport type ShopifyLoaderParams = Simplify<\n ShopifyLoaderOptions & {\n src: ImageType['url'];\n }\n>;\nexport type ShopifyImageProps = Omit<HtmlImageProps, 'src'> & {\n /** An object with fields that correspond to the Storefront API's\n * [Image object](https://shopify.dev/api/storefront/reference/common-objects/image).\n * The `data` prop is required.\n */\n data: PartialDeep<ImageType, {recurseIntoArrays: true}>;\n /** A custom function that generates the image URL. Parameters passed in\n * are `ShopifyLoaderParams`\n */\n loader?: (params: ShopifyLoaderParams) => string;\n /** An object of `loader` function options. For example, if the `loader` function\n * requires a `scale` option, then the value can be a property of the\n * `loaderOptions` object (for example, `{scale: 2}`). The object shape is `ShopifyLoaderOptions`.\n */\n loaderOptions?: ShopifyLoaderOptions;\n /**\n * `src` isn't used, and should instead be passed as part of the `data` object\n */\n src?: never;\n /**\n * An array of pixel widths to overwrite the default generated srcset. For example, `[300, 600, 800]`.\n */\n widths?: (HtmlImageProps['width'] | ImageType['width'])[];\n};\n\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. 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({\n data,\n width,\n height,\n loading,\n loader = shopifyImageLoader,\n loaderOptions,\n widths,\n decoding = 'async',\n ...rest\n}: ShopifyImageProps) {\n if (!data.url) {\n const missingUrlError = `<Image/>: the 'data' prop requires the 'url' property. Image: ${\n data.id ?? 'no ID provided'\n }`;\n\n if (__HYDROGEN_DEV__) {\n throw new Error(missingUrlError);\n } else {\n console.error(missingUrlError);\n }\n\n return null;\n }\n\n if (__HYDROGEN_DEV__ && !data.altText && !rest.alt) {\n console.warn(\n `<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. Image: ${\n data.id ?? data.url\n }`\n );\n }\n\n const {width: imgElementWidth, height: imgElementHeight} =\n getShopifyImageDimensions({\n data,\n loaderOptions,\n elementProps: {\n width,\n height,\n },\n });\n\n if (__HYDROGEN_DEV__ && (!imgElementWidth || !imgElementHeight)) {\n console.warn(\n `<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties. Image: ${\n data.id ?? data.url\n }`\n );\n }\n\n let finalSrc = data.url;\n\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(\n `<Image/>: 'loader' did not return a valid string. Image: ${\n data.id ?? data.url\n }`\n );\n }\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 =\n width && imgElementWidth && width < imgElementWidth\n ? width\n : imgElementWidth;\n const finalSrcset =\n rest.srcSet ??\n internalImageSrcSet({\n ...loaderOptions,\n widths,\n src: data.url,\n width: maxWidth,\n height: imgElementHeight,\n loader,\n });\n\n /* eslint-disable hydrogen/prefer-image-component */\n return (\n <img\n id={data.id ?? ''}\n alt={data.altText ?? rest.alt ?? ''}\n loading={loading ?? 'lazy'}\n {...rest}\n src={finalSrc}\n width={imgElementWidth ?? undefined}\n height={imgElementHeight ?? undefined}\n srcSet={finalSrcset}\n decoding={decoding}\n />\n );\n /* eslint-enable hydrogen/prefer-image-component */\n}\n\ntype InternalShopifySrcSetGeneratorsParams = Simplify<\n ShopifyLoaderOptions & {\n src: ImageType['url'];\n widths?: (HtmlImageProps['width'] | ImageType['width'])[];\n loader?: (params: ShopifyLoaderParams) => string;\n }\n>;\nfunction internalImageSrcSet({\n src,\n width,\n crop,\n scale,\n widths,\n loader,\n height,\n}: InternalShopifySrcSetGeneratorsParams) {\n const hasCustomWidths = widths && Array.isArray(widths);\n if (hasCustomWidths && widths.some((size) => isNaN(size as number))) {\n throw new Error(\n `<Image/>: the 'widths' must be an array of numbers. Image: ${src}`\n );\n }\n\n let aspectRatio = 1;\n if (width && height) {\n aspectRatio = Number(height) / Number(width);\n }\n\n let setSizes = hasCustomWidths ? widths : IMG_SRC_SET_SIZES;\n if (\n !hasCustomWidths &&\n width &&\n width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1]\n ) {\n setSizes = IMG_SRC_SET_SIZES.filter((size) => size <= width);\n }\n const srcGenerator = loader ? loader : addImageSizeParametersToUrl;\n return setSizes\n .map(\n (size) =>\n `${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 )\n .join(', ');\n}\n"],"names":["Image","data","width","height","loading","loader","shopifyImageLoader","loaderOptions","widths","decoding","rest","url","missingUrlError","id","Error","altText","alt","console","warn","imgElementWidth","imgElementHeight","getShopifyImageDimensions","elementProps","finalSrc","src","maxWidth","finalSrcset","srcSet","internalImageSrcSet","undefined","crop","scale","hasCustomWidths","Array","isArray","some","size","isNaN","aspectRatio","Number","setSizes","IMG_SRC_SET_SIZES","length","filter","srcGenerator","addImageSizeParametersToUrl","map","join"],"mappings":"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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { getShopifyImageDimensions, shopifyImageLoader, IMG_SRC_SET_SIZES, addImageSizeParametersToUrl } from "./image-size.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
function Image({
|
|
4
|
+
data,
|
|
5
|
+
width,
|
|
6
|
+
height,
|
|
7
|
+
loading,
|
|
8
|
+
loader = shopifyImageLoader,
|
|
9
|
+
loaderOptions,
|
|
10
|
+
widths,
|
|
11
|
+
decoding = "async",
|
|
12
|
+
...rest
|
|
13
|
+
}) {
|
|
14
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
15
|
+
if (!data.url) {
|
|
16
|
+
const missingUrlError = `<Image/>: the 'data' prop requires the 'url' property. Image: ${(_a = data.id) != null ? _a : "no ID provided"}`;
|
|
17
|
+
{
|
|
18
|
+
throw new Error(missingUrlError);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (!data.altText && !rest.alt) {
|
|
22
|
+
console.warn(`<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. Image: ${(_b = data.id) != null ? _b : data.url}`);
|
|
23
|
+
}
|
|
24
|
+
const {
|
|
25
|
+
width: imgElementWidth,
|
|
26
|
+
height: imgElementHeight
|
|
27
|
+
} = getShopifyImageDimensions({
|
|
28
|
+
data,
|
|
29
|
+
loaderOptions,
|
|
30
|
+
elementProps: {
|
|
31
|
+
width,
|
|
32
|
+
height
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
if (!imgElementWidth || !imgElementHeight) {
|
|
36
|
+
console.warn(`<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties. Image: ${(_c = data.id) != null ? _c : data.url}`);
|
|
37
|
+
}
|
|
38
|
+
let finalSrc = data.url;
|
|
39
|
+
if (loader) {
|
|
40
|
+
finalSrc = loader({
|
|
41
|
+
...loaderOptions,
|
|
42
|
+
src: data.url,
|
|
43
|
+
width: imgElementWidth,
|
|
44
|
+
height: imgElementHeight
|
|
45
|
+
});
|
|
46
|
+
if (typeof finalSrc !== "string" || !finalSrc) {
|
|
47
|
+
throw new Error(`<Image/>: 'loader' did not return a valid string. Image: ${(_d = data.id) != null ? _d : data.url}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const maxWidth = width && imgElementWidth && width < imgElementWidth ? width : imgElementWidth;
|
|
51
|
+
const finalSrcset = (_e = rest.srcSet) != null ? _e : internalImageSrcSet({
|
|
52
|
+
...loaderOptions,
|
|
53
|
+
widths,
|
|
54
|
+
src: data.url,
|
|
55
|
+
width: maxWidth,
|
|
56
|
+
height: imgElementHeight,
|
|
57
|
+
loader
|
|
58
|
+
});
|
|
59
|
+
return /* @__PURE__ */ jsx("img", {
|
|
60
|
+
id: (_f = data.id) != null ? _f : "",
|
|
61
|
+
alt: (_h = (_g = data.altText) != null ? _g : rest.alt) != null ? _h : "",
|
|
62
|
+
loading: loading != null ? loading : "lazy",
|
|
63
|
+
...rest,
|
|
64
|
+
src: finalSrc,
|
|
65
|
+
width: imgElementWidth != null ? imgElementWidth : void 0,
|
|
66
|
+
height: imgElementHeight != null ? imgElementHeight : void 0,
|
|
67
|
+
srcSet: finalSrcset,
|
|
68
|
+
decoding
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function internalImageSrcSet({
|
|
72
|
+
src,
|
|
73
|
+
width,
|
|
74
|
+
crop,
|
|
75
|
+
scale,
|
|
76
|
+
widths,
|
|
77
|
+
loader,
|
|
78
|
+
height
|
|
79
|
+
}) {
|
|
80
|
+
const hasCustomWidths = widths && Array.isArray(widths);
|
|
81
|
+
if (hasCustomWidths && widths.some((size) => isNaN(size))) {
|
|
82
|
+
throw new Error(`<Image/>: the 'widths' must be an array of numbers. Image: ${src}`);
|
|
83
|
+
}
|
|
84
|
+
let aspectRatio = 1;
|
|
85
|
+
if (width && height) {
|
|
86
|
+
aspectRatio = Number(height) / Number(width);
|
|
87
|
+
}
|
|
88
|
+
let setSizes = hasCustomWidths ? widths : IMG_SRC_SET_SIZES;
|
|
89
|
+
if (!hasCustomWidths && width && width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1]) {
|
|
90
|
+
setSizes = IMG_SRC_SET_SIZES.filter((size) => size <= width);
|
|
91
|
+
}
|
|
92
|
+
const srcGenerator = loader ? loader : addImageSizeParametersToUrl;
|
|
93
|
+
return setSizes.map((size) => `${srcGenerator({
|
|
94
|
+
src,
|
|
95
|
+
width: size,
|
|
96
|
+
height: crop ? Number(size) * aspectRatio : void 0,
|
|
97
|
+
crop,
|
|
98
|
+
scale
|
|
99
|
+
})} ${size}w`).join(", ");
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
Image
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=Image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Image.js","sources":["../../src/Image.tsx"],"sourcesContent":["import * as React from 'react';\nimport {\n getShopifyImageDimensions,\n shopifyImageLoader,\n addImageSizeParametersToUrl,\n IMG_SRC_SET_SIZES,\n} from './image-size.js';\nimport type {Image as ImageType} from './storefront-api-types.js';\nimport type {PartialDeep, Simplify} from 'type-fest';\n\ntype HtmlImageProps = React.ImgHTMLAttributes<HTMLImageElement>;\n\nexport type ShopifyLoaderOptions = {\n crop?: 'top' | 'bottom' | 'left' | 'right' | 'center';\n scale?: 2 | 3;\n width?: HtmlImageProps['width'] | ImageType['width'];\n height?: HtmlImageProps['height'] | ImageType['height'];\n};\nexport type ShopifyLoaderParams = Simplify<\n ShopifyLoaderOptions & {\n src: ImageType['url'];\n }\n>;\nexport type ShopifyImageProps = Omit<HtmlImageProps, 'src'> & {\n /** An object with fields that correspond to the Storefront API's\n * [Image object](https://shopify.dev/api/storefront/reference/common-objects/image).\n * The `data` prop is required.\n */\n data: PartialDeep<ImageType, {recurseIntoArrays: true}>;\n /** A custom function that generates the image URL. Parameters passed in\n * are `ShopifyLoaderParams`\n */\n loader?: (params: ShopifyLoaderParams) => string;\n /** An object of `loader` function options. For example, if the `loader` function\n * requires a `scale` option, then the value can be a property of the\n * `loaderOptions` object (for example, `{scale: 2}`). The object shape is `ShopifyLoaderOptions`.\n */\n loaderOptions?: ShopifyLoaderOptions;\n /**\n * `src` isn't used, and should instead be passed as part of the `data` object\n */\n src?: never;\n /**\n * An array of pixel widths to overwrite the default generated srcset. For example, `[300, 600, 800]`.\n */\n widths?: (HtmlImageProps['width'] | ImageType['width'])[];\n};\n\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. 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({\n data,\n width,\n height,\n loading,\n loader = shopifyImageLoader,\n loaderOptions,\n widths,\n decoding = 'async',\n ...rest\n}: ShopifyImageProps) {\n if (!data.url) {\n const missingUrlError = `<Image/>: the 'data' prop requires the 'url' property. Image: ${\n data.id ?? 'no ID provided'\n }`;\n\n if (__HYDROGEN_DEV__) {\n throw new Error(missingUrlError);\n } else {\n console.error(missingUrlError);\n }\n\n return null;\n }\n\n if (__HYDROGEN_DEV__ && !data.altText && !rest.alt) {\n console.warn(\n `<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. Image: ${\n data.id ?? data.url\n }`\n );\n }\n\n const {width: imgElementWidth, height: imgElementHeight} =\n getShopifyImageDimensions({\n data,\n loaderOptions,\n elementProps: {\n width,\n height,\n },\n });\n\n if (__HYDROGEN_DEV__ && (!imgElementWidth || !imgElementHeight)) {\n console.warn(\n `<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties. Image: ${\n data.id ?? data.url\n }`\n );\n }\n\n let finalSrc = data.url;\n\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(\n `<Image/>: 'loader' did not return a valid string. Image: ${\n data.id ?? data.url\n }`\n );\n }\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 =\n width && imgElementWidth && width < imgElementWidth\n ? width\n : imgElementWidth;\n const finalSrcset =\n rest.srcSet ??\n internalImageSrcSet({\n ...loaderOptions,\n widths,\n src: data.url,\n width: maxWidth,\n height: imgElementHeight,\n loader,\n });\n\n /* eslint-disable hydrogen/prefer-image-component */\n return (\n <img\n id={data.id ?? ''}\n alt={data.altText ?? rest.alt ?? ''}\n loading={loading ?? 'lazy'}\n {...rest}\n src={finalSrc}\n width={imgElementWidth ?? undefined}\n height={imgElementHeight ?? undefined}\n srcSet={finalSrcset}\n decoding={decoding}\n />\n );\n /* eslint-enable hydrogen/prefer-image-component */\n}\n\ntype InternalShopifySrcSetGeneratorsParams = Simplify<\n ShopifyLoaderOptions & {\n src: ImageType['url'];\n widths?: (HtmlImageProps['width'] | ImageType['width'])[];\n loader?: (params: ShopifyLoaderParams) => string;\n }\n>;\nfunction internalImageSrcSet({\n src,\n width,\n crop,\n scale,\n widths,\n loader,\n height,\n}: InternalShopifySrcSetGeneratorsParams) {\n const hasCustomWidths = widths && Array.isArray(widths);\n if (hasCustomWidths && widths.some((size) => isNaN(size as number))) {\n throw new Error(\n `<Image/>: the 'widths' must be an array of numbers. Image: ${src}`\n );\n }\n\n let aspectRatio = 1;\n if (width && height) {\n aspectRatio = Number(height) / Number(width);\n }\n\n let setSizes = hasCustomWidths ? widths : IMG_SRC_SET_SIZES;\n if (\n !hasCustomWidths &&\n width &&\n width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1]\n ) {\n setSizes = IMG_SRC_SET_SIZES.filter((size) => size <= width);\n }\n const srcGenerator = loader ? loader : addImageSizeParametersToUrl;\n return setSizes\n .map(\n (size) =>\n `${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 )\n .join(', ');\n}\n"],"names":["Image","data","width","height","loading","loader","shopifyImageLoader","loaderOptions","widths","decoding","rest","url","missingUrlError","id","Error","altText","alt","console","warn","imgElementWidth","imgElementHeight","getShopifyImageDimensions","elementProps","finalSrc","src","maxWidth","finalSrcset","srcSet","internalImageSrcSet","undefined","crop","scale","hasCustomWidths","Array","isArray","some","size","isNaN","aspectRatio","Number","setSizes","IMG_SRC_SET_SIZES","length","filter","srcGenerator","addImageSizeParametersToUrl","map","join"],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const Image = require("./Image.cjs");
|
|
4
|
+
const Video = require("./Video.cjs");
|
|
5
|
+
const ExternalVideo = require("./ExternalVideo.cjs");
|
|
6
|
+
const ModelViewer = require("./ModelViewer.cjs");
|
|
7
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
8
|
+
function MediaFile({
|
|
9
|
+
data,
|
|
10
|
+
mediaOptions,
|
|
11
|
+
...passthroughProps
|
|
12
|
+
}) {
|
|
13
|
+
switch (data.__typename) {
|
|
14
|
+
case "MediaImage": {
|
|
15
|
+
if (!data.image) {
|
|
16
|
+
const noDataImage = `<MediaFile/>: 'data.image' does not exist for __typename of 'MediaImage'; rendering 'null' by default.`;
|
|
17
|
+
{
|
|
18
|
+
throw new Error(noDataImage);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Image.Image, {
|
|
22
|
+
...passthroughProps,
|
|
23
|
+
...mediaOptions == null ? void 0 : mediaOptions.image,
|
|
24
|
+
data: data.image
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
case "Video": {
|
|
28
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Video.Video, {
|
|
29
|
+
...passthroughProps,
|
|
30
|
+
...mediaOptions == null ? void 0 : mediaOptions.video,
|
|
31
|
+
data
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
case "ExternalVideo": {
|
|
35
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ExternalVideo.ExternalVideo, {
|
|
36
|
+
...passthroughProps,
|
|
37
|
+
...mediaOptions == null ? void 0 : mediaOptions.externalVideo,
|
|
38
|
+
data
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
case "Model3d": {
|
|
42
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ModelViewer.ModelViewer, {
|
|
43
|
+
...passthroughProps,
|
|
44
|
+
...mediaOptions == null ? void 0 : mediaOptions.modelViewer,
|
|
45
|
+
data
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
default: {
|
|
49
|
+
const typenameMissingMessage = `<MediaFile /> requires the '__typename' property to exist on the 'data' prop in order to correctly render the correct component for this media. Rendering 'null' by default`;
|
|
50
|
+
{
|
|
51
|
+
throw new Error(typenameMissingMessage);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.MediaFile = MediaFile;
|
|
57
|
+
//# sourceMappingURL=MediaFile.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MediaFile.cjs","sources":["../../src/MediaFile.tsx"],"sourcesContent":["import React from 'react';\nimport {Image, type ShopifyImageProps} from './Image.js';\nimport {Video} from './Video.js';\nimport {ExternalVideo} from './ExternalVideo.js';\nimport {ModelViewer} from './ModelViewer.js';\nimport type {MediaEdge as MediaEdgeType} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\ninterface MediaFileProps {\n /** An object with fields that correspond to the Storefront API's [Media object](https://shopify.dev/api/storefront/reference/products/media). */\n data: PartialDeep<MediaEdgeType['node'], {recurseIntoArrays: true}>;\n /** The options for the `Image`, `Video`, or `ExternalVideo` components. */\n mediaOptions?: {\n /** Props that will only apply when an `<Image />` is rendered */\n image: Omit<ShopifyImageProps, 'data'>;\n /** Props that will only apply when a `<Video />` is rendered */\n video: Omit<React.ComponentProps<typeof Video>, 'data'>;\n /** Props that will only apply when an `<ExternalVideo />` is rendered */\n externalVideo: Omit<\n React.ComponentProps<typeof ExternalVideo>['options'],\n 'data'\n >;\n /** Props that will only apply when a `<ModelViewer />` is rendered */\n modelViewer: Omit<typeof ModelViewer, 'data'>;\n };\n}\n\n/**\n * The `MediaFile` component renders the media for the Storefront API's\n * [Media object](https://shopify.dev/api/storefront/reference/products/media). It renders an `Image`, a\n * `Video`, an `ExternalVideo`, or a `ModelViewer` depending on the `__typename` of the `data` prop.\n */\nexport function MediaFile({\n data,\n mediaOptions,\n ...passthroughProps\n}: MediaFileProps) {\n switch (data.__typename) {\n case 'MediaImage': {\n if (!data.image) {\n const noDataImage = `<MediaFile/>: 'data.image' does not exist for __typename of 'MediaImage'; rendering 'null' by default.`;\n if (__HYDROGEN_DEV__) {\n throw new Error(noDataImage);\n } else {\n console.warn(noDataImage);\n return null;\n }\n }\n\n return (\n <Image\n {...passthroughProps}\n {...mediaOptions?.image}\n data={data.image}\n />\n );\n }\n case 'Video': {\n return (\n <Video {...passthroughProps} {...mediaOptions?.video} data={data} />\n );\n }\n case 'ExternalVideo': {\n return (\n <ExternalVideo\n {...passthroughProps}\n {...mediaOptions?.externalVideo}\n data={data}\n />\n );\n }\n case 'Model3d': {\n return (\n <ModelViewer\n {...passthroughProps}\n {...mediaOptions?.modelViewer}\n data={data}\n />\n );\n }\n default: {\n const typenameMissingMessage = `<MediaFile /> requires the '__typename' property to exist on the 'data' prop in order to correctly render the correct component for this media. Rendering 'null' by default`;\n if (__HYDROGEN_DEV__) {\n throw new Error(typenameMissingMessage);\n } else {\n console.error(typenameMissingMessage);\n return null;\n }\n }\n }\n}\n"],"names":["MediaFile","data","mediaOptions","passthroughProps","__typename","image","noDataImage","Error","Image","Video","video","ExternalVideo","externalVideo","ModelViewer","modelViewer","typenameMissingMessage"],"mappings":";;;;;;;AAgCO,SAASA,UAAU;AAAA,EACxBC;AAAAA,EACAC;AAAAA,KACGC;AAHqB,GAIP;AACjB,UAAQF,KAAKG,YAAb;AAAA,IACE,KAAK,cAAc;AACb,UAAA,CAACH,KAAKI,OAAO;AACf,cAAMC,cAAe;AACC;AACd,gBAAA,IAAIC,MAAMD,WAAV;AAAA,QAIP;AAAA,MACF;AAED,4CACGE,MAAAA,OAAD;AAAA,QAAA,GACML;AAAAA,QADN,GAEMD,6CAAcG;AAAAA,QAClB,MAAMJ,KAAKI;AAAAA,MAAAA,CAJf;AAAA,IAOD;AAAA,IACD,KAAK,SAAS;AACZ,4CACGI,MAAAA,OAAD;AAAA,QAAA,GAAWN;AAAAA,QAAX,GAAiCD,6CAAcQ;AAAAA,QAAO;AAAA,MAAA,CADxD;AAAA,IAGD;AAAA,IACD,KAAK,iBAAiB;AACpB,4CACGC,cAAAA,eAAD;AAAA,QAAA,GACMR;AAAAA,QADN,GAEMD,6CAAcU;AAAAA,QAClB;AAAA,MAAA,CAJJ;AAAA,IAOD;AAAA,IACD,KAAK,WAAW;AACd,4CACGC,YAAAA,aAAD;AAAA,QAAA,GACMV;AAAAA,QADN,GAEMD,6CAAcY;AAAAA,QAClB;AAAA,MAAA,CAJJ;AAAA,IAOD;AAAA,IACD,SAAS;AACP,YAAMC,yBAA0B;AACV;AACd,cAAA,IAAIR,MAAMQ,sBAAV;AAAA,MAIP;AAAA,IACF;AAAA,EAnDH;AAqDD;;"}
|