@shopify/hydrogen-react 2023.1.4 → 2023.1.6
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 +19 -201
- package/dist/browser-dev/AddToCartButton.mjs.map +1 -1
- package/dist/browser-dev/BaseButton.mjs.map +1 -1
- package/dist/browser-dev/BuyNowButton.mjs.map +1 -1
- package/dist/browser-dev/CartCheckoutButton.mjs.map +1 -1
- package/dist/browser-dev/CartCost.mjs.map +1 -1
- package/dist/browser-dev/CartLinePrice.mjs +3 -0
- package/dist/browser-dev/CartLinePrice.mjs.map +1 -1
- package/dist/browser-dev/CartLineProvider.mjs +4 -1
- package/dist/browser-dev/CartLineProvider.mjs.map +1 -1
- package/dist/browser-dev/CartLineQuantity.mjs +12 -0
- package/dist/browser-dev/CartLineQuantity.mjs.map +1 -0
- package/dist/browser-dev/CartLineQuantityAdjustButton.mjs +48 -0
- package/dist/browser-dev/CartLineQuantityAdjustButton.mjs.map +1 -0
- package/dist/browser-dev/CartProvider.mjs +3 -3
- package/dist/browser-dev/CartProvider.mjs.map +1 -1
- package/dist/browser-dev/ExternalVideo.mjs.map +1 -1
- package/dist/browser-dev/Image.mjs +1 -1
- package/dist/browser-dev/Image.mjs.map +1 -1
- package/dist/browser-dev/MediaFile.mjs.map +1 -1
- package/dist/browser-dev/ModelViewer.mjs.map +1 -1
- package/dist/browser-dev/Money.mjs.map +1 -1
- package/dist/browser-dev/ProductPrice.mjs.map +1 -1
- package/dist/browser-dev/ProductProvider.mjs.map +1 -1
- package/dist/browser-dev/ShopPayButton.mjs.map +1 -1
- package/dist/browser-dev/ShopifyProvider.mjs.map +1 -1
- package/dist/browser-dev/Video.mjs.map +1 -1
- package/dist/browser-dev/analytics.mjs.map +1 -1
- package/dist/browser-dev/cart-hooks.mjs +5 -2
- package/dist/browser-dev/cart-hooks.mjs.map +1 -1
- package/dist/browser-dev/cart-queries.mjs.map +1 -1
- package/dist/browser-dev/flatten-connection.mjs +1 -1
- package/dist/browser-dev/flatten-connection.mjs.map +1 -1
- package/dist/browser-dev/image-size.mjs.map +1 -1
- package/dist/browser-dev/index.mjs +4 -0
- package/dist/browser-dev/index.mjs.map +1 -1
- package/dist/browser-dev/load-script.mjs +3 -1
- package/dist/browser-dev/load-script.mjs.map +1 -1
- package/dist/browser-dev/parse-metafield.mjs.map +1 -1
- package/dist/browser-dev/storefront-client.mjs +9 -8
- package/dist/browser-dev/storefront-client.mjs.map +1 -1
- package/dist/browser-dev/useCartAPIStateMachine.mjs +9 -0
- package/dist/browser-dev/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/browser-dev/useCartActions.mjs.map +1 -1
- package/dist/browser-dev/useMoney.mjs +1 -0
- package/dist/browser-dev/useMoney.mjs.map +1 -1
- package/dist/browser-prod/AddToCartButton.mjs.map +1 -1
- package/dist/browser-prod/BaseButton.mjs.map +1 -1
- package/dist/browser-prod/BuyNowButton.mjs.map +1 -1
- package/dist/browser-prod/CartCheckoutButton.mjs.map +1 -1
- package/dist/browser-prod/CartCost.mjs.map +1 -1
- package/dist/browser-prod/CartLinePrice.mjs.map +1 -1
- package/dist/browser-prod/CartLineProvider.mjs +4 -1
- package/dist/browser-prod/CartLineProvider.mjs.map +1 -1
- package/dist/browser-prod/CartLineQuantity.mjs +12 -0
- package/dist/browser-prod/CartLineQuantity.mjs.map +1 -0
- package/dist/browser-prod/CartLineQuantityAdjustButton.mjs +48 -0
- package/dist/browser-prod/CartLineQuantityAdjustButton.mjs.map +1 -0
- package/dist/browser-prod/CartProvider.mjs +3 -3
- package/dist/browser-prod/CartProvider.mjs.map +1 -1
- package/dist/browser-prod/ExternalVideo.mjs.map +1 -1
- package/dist/browser-prod/Image.mjs +1 -1
- package/dist/browser-prod/Image.mjs.map +1 -1
- package/dist/browser-prod/MediaFile.mjs.map +1 -1
- package/dist/browser-prod/ModelViewer.mjs.map +1 -1
- package/dist/browser-prod/Money.mjs.map +1 -1
- package/dist/browser-prod/ProductPrice.mjs.map +1 -1
- package/dist/browser-prod/ProductProvider.mjs.map +1 -1
- package/dist/browser-prod/ShopPayButton.mjs.map +1 -1
- package/dist/browser-prod/ShopifyProvider.mjs.map +1 -1
- package/dist/browser-prod/Video.mjs.map +1 -1
- package/dist/browser-prod/analytics.mjs.map +1 -1
- package/dist/browser-prod/cart-hooks.mjs +5 -2
- package/dist/browser-prod/cart-hooks.mjs.map +1 -1
- package/dist/browser-prod/cart-queries.mjs.map +1 -1
- package/dist/browser-prod/flatten-connection.mjs +1 -1
- package/dist/browser-prod/flatten-connection.mjs.map +1 -1
- package/dist/browser-prod/image-size.mjs.map +1 -1
- package/dist/browser-prod/index.mjs +4 -0
- package/dist/browser-prod/index.mjs.map +1 -1
- package/dist/browser-prod/load-script.mjs +3 -1
- package/dist/browser-prod/load-script.mjs.map +1 -1
- package/dist/browser-prod/parse-metafield.mjs.map +1 -1
- package/dist/browser-prod/storefront-client.mjs +8 -7
- package/dist/browser-prod/storefront-client.mjs.map +1 -1
- package/dist/browser-prod/useCartAPIStateMachine.mjs +9 -0
- package/dist/browser-prod/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/browser-prod/useCartActions.mjs.map +1 -1
- package/dist/browser-prod/useMoney.mjs +1 -0
- package/dist/browser-prod/useMoney.mjs.map +1 -1
- package/dist/node-dev/AddToCartButton.js.map +1 -1
- package/dist/node-dev/AddToCartButton.mjs.map +1 -1
- package/dist/node-dev/BaseButton.js.map +1 -1
- package/dist/node-dev/BaseButton.mjs.map +1 -1
- package/dist/node-dev/BuyNowButton.js.map +1 -1
- package/dist/node-dev/BuyNowButton.mjs.map +1 -1
- package/dist/node-dev/CartCheckoutButton.js.map +1 -1
- package/dist/node-dev/CartCheckoutButton.mjs.map +1 -1
- package/dist/node-dev/CartCost.js.map +1 -1
- package/dist/node-dev/CartCost.mjs.map +1 -1
- package/dist/node-dev/CartLinePrice.js +3 -0
- package/dist/node-dev/CartLinePrice.js.map +1 -1
- package/dist/node-dev/CartLinePrice.mjs +3 -0
- package/dist/node-dev/CartLinePrice.mjs.map +1 -1
- package/dist/node-dev/CartLineProvider.js +4 -1
- package/dist/node-dev/CartLineProvider.js.map +1 -1
- package/dist/node-dev/CartLineProvider.mjs +4 -1
- package/dist/node-dev/CartLineProvider.mjs.map +1 -1
- package/dist/node-dev/CartLineQuantity.js +12 -0
- package/dist/node-dev/CartLineQuantity.js.map +1 -0
- package/dist/node-dev/CartLineQuantity.mjs +12 -0
- package/dist/node-dev/CartLineQuantity.mjs.map +1 -0
- package/dist/node-dev/CartLineQuantityAdjustButton.js +48 -0
- package/dist/node-dev/CartLineQuantityAdjustButton.js.map +1 -0
- package/dist/node-dev/CartLineQuantityAdjustButton.mjs +48 -0
- package/dist/node-dev/CartLineQuantityAdjustButton.mjs.map +1 -0
- package/dist/node-dev/CartProvider.js +3 -3
- package/dist/node-dev/CartProvider.js.map +1 -1
- package/dist/node-dev/CartProvider.mjs +3 -3
- package/dist/node-dev/CartProvider.mjs.map +1 -1
- package/dist/node-dev/ExternalVideo.js.map +1 -1
- package/dist/node-dev/ExternalVideo.mjs.map +1 -1
- package/dist/node-dev/Image.js +1 -1
- package/dist/node-dev/Image.js.map +1 -1
- package/dist/node-dev/Image.mjs +1 -1
- package/dist/node-dev/Image.mjs.map +1 -1
- package/dist/node-dev/MediaFile.js.map +1 -1
- package/dist/node-dev/MediaFile.mjs.map +1 -1
- package/dist/node-dev/ModelViewer.js.map +1 -1
- package/dist/node-dev/ModelViewer.mjs.map +1 -1
- package/dist/node-dev/Money.js.map +1 -1
- package/dist/node-dev/Money.mjs.map +1 -1
- package/dist/node-dev/ProductPrice.js.map +1 -1
- package/dist/node-dev/ProductPrice.mjs.map +1 -1
- package/dist/node-dev/ProductProvider.js.map +1 -1
- package/dist/node-dev/ProductProvider.mjs.map +1 -1
- package/dist/node-dev/ShopPayButton.js.map +1 -1
- package/dist/node-dev/ShopPayButton.mjs.map +1 -1
- package/dist/node-dev/ShopifyProvider.js.map +1 -1
- package/dist/node-dev/ShopifyProvider.mjs.map +1 -1
- package/dist/node-dev/Video.js.map +1 -1
- package/dist/node-dev/Video.mjs.map +1 -1
- package/dist/node-dev/analytics.js.map +1 -1
- package/dist/node-dev/analytics.mjs.map +1 -1
- package/dist/node-dev/cart-hooks.js +5 -2
- package/dist/node-dev/cart-hooks.js.map +1 -1
- package/dist/node-dev/cart-hooks.mjs +5 -2
- package/dist/node-dev/cart-hooks.mjs.map +1 -1
- package/dist/node-dev/cart-queries.js.map +1 -1
- package/dist/node-dev/cart-queries.mjs.map +1 -1
- package/dist/node-dev/flatten-connection.js +1 -1
- package/dist/node-dev/flatten-connection.js.map +1 -1
- package/dist/node-dev/flatten-connection.mjs +1 -1
- package/dist/node-dev/flatten-connection.mjs.map +1 -1
- package/dist/node-dev/image-size.js.map +1 -1
- package/dist/node-dev/image-size.mjs.map +1 -1
- package/dist/node-dev/index.js +4 -0
- package/dist/node-dev/index.js.map +1 -1
- package/dist/node-dev/index.mjs +4 -0
- package/dist/node-dev/index.mjs.map +1 -1
- package/dist/node-dev/load-script.js +3 -1
- package/dist/node-dev/load-script.js.map +1 -1
- package/dist/node-dev/load-script.mjs +3 -1
- package/dist/node-dev/load-script.mjs.map +1 -1
- package/dist/node-dev/parse-metafield.js.map +1 -1
- package/dist/node-dev/parse-metafield.mjs.map +1 -1
- package/dist/node-dev/storefront-client.js +9 -8
- package/dist/node-dev/storefront-client.js.map +1 -1
- package/dist/node-dev/storefront-client.mjs +9 -8
- package/dist/node-dev/storefront-client.mjs.map +1 -1
- package/dist/node-dev/useCartAPIStateMachine.js +9 -0
- package/dist/node-dev/useCartAPIStateMachine.js.map +1 -1
- package/dist/node-dev/useCartAPIStateMachine.mjs +9 -0
- package/dist/node-dev/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/node-dev/useCartActions.js.map +1 -1
- package/dist/node-dev/useCartActions.mjs.map +1 -1
- package/dist/node-dev/useMoney.js +1 -0
- package/dist/node-dev/useMoney.js.map +1 -1
- package/dist/node-dev/useMoney.mjs +1 -0
- package/dist/node-dev/useMoney.mjs.map +1 -1
- package/dist/node-prod/AddToCartButton.js.map +1 -1
- package/dist/node-prod/AddToCartButton.mjs.map +1 -1
- package/dist/node-prod/BaseButton.js.map +1 -1
- package/dist/node-prod/BaseButton.mjs.map +1 -1
- package/dist/node-prod/BuyNowButton.js.map +1 -1
- package/dist/node-prod/BuyNowButton.mjs.map +1 -1
- package/dist/node-prod/CartCheckoutButton.js.map +1 -1
- package/dist/node-prod/CartCheckoutButton.mjs.map +1 -1
- package/dist/node-prod/CartCost.js.map +1 -1
- package/dist/node-prod/CartCost.mjs.map +1 -1
- package/dist/node-prod/CartLinePrice.js.map +1 -1
- package/dist/node-prod/CartLinePrice.mjs.map +1 -1
- package/dist/node-prod/CartLineProvider.js +4 -1
- package/dist/node-prod/CartLineProvider.js.map +1 -1
- package/dist/node-prod/CartLineProvider.mjs +4 -1
- package/dist/node-prod/CartLineProvider.mjs.map +1 -1
- package/dist/node-prod/CartLineQuantity.js +12 -0
- package/dist/node-prod/CartLineQuantity.js.map +1 -0
- package/dist/node-prod/CartLineQuantity.mjs +12 -0
- package/dist/node-prod/CartLineQuantity.mjs.map +1 -0
- package/dist/node-prod/CartLineQuantityAdjustButton.js +48 -0
- package/dist/node-prod/CartLineQuantityAdjustButton.js.map +1 -0
- package/dist/node-prod/CartLineQuantityAdjustButton.mjs +48 -0
- package/dist/node-prod/CartLineQuantityAdjustButton.mjs.map +1 -0
- package/dist/node-prod/CartProvider.js +3 -3
- package/dist/node-prod/CartProvider.js.map +1 -1
- package/dist/node-prod/CartProvider.mjs +3 -3
- package/dist/node-prod/CartProvider.mjs.map +1 -1
- package/dist/node-prod/ExternalVideo.js.map +1 -1
- package/dist/node-prod/ExternalVideo.mjs.map +1 -1
- package/dist/node-prod/Image.js +1 -1
- package/dist/node-prod/Image.js.map +1 -1
- package/dist/node-prod/Image.mjs +1 -1
- package/dist/node-prod/Image.mjs.map +1 -1
- package/dist/node-prod/MediaFile.js.map +1 -1
- package/dist/node-prod/MediaFile.mjs.map +1 -1
- package/dist/node-prod/ModelViewer.js.map +1 -1
- package/dist/node-prod/ModelViewer.mjs.map +1 -1
- package/dist/node-prod/Money.js.map +1 -1
- package/dist/node-prod/Money.mjs.map +1 -1
- package/dist/node-prod/ProductPrice.js.map +1 -1
- package/dist/node-prod/ProductPrice.mjs.map +1 -1
- package/dist/node-prod/ProductProvider.js.map +1 -1
- package/dist/node-prod/ProductProvider.mjs.map +1 -1
- package/dist/node-prod/ShopPayButton.js.map +1 -1
- package/dist/node-prod/ShopPayButton.mjs.map +1 -1
- package/dist/node-prod/ShopifyProvider.js.map +1 -1
- package/dist/node-prod/ShopifyProvider.mjs.map +1 -1
- package/dist/node-prod/Video.js.map +1 -1
- package/dist/node-prod/Video.mjs.map +1 -1
- package/dist/node-prod/analytics.js.map +1 -1
- package/dist/node-prod/analytics.mjs.map +1 -1
- package/dist/node-prod/cart-hooks.js +5 -2
- package/dist/node-prod/cart-hooks.js.map +1 -1
- package/dist/node-prod/cart-hooks.mjs +5 -2
- package/dist/node-prod/cart-hooks.mjs.map +1 -1
- package/dist/node-prod/cart-queries.js.map +1 -1
- package/dist/node-prod/cart-queries.mjs.map +1 -1
- package/dist/node-prod/flatten-connection.js +1 -1
- package/dist/node-prod/flatten-connection.js.map +1 -1
- package/dist/node-prod/flatten-connection.mjs +1 -1
- package/dist/node-prod/flatten-connection.mjs.map +1 -1
- package/dist/node-prod/image-size.js.map +1 -1
- package/dist/node-prod/image-size.mjs.map +1 -1
- package/dist/node-prod/index.js +4 -0
- package/dist/node-prod/index.js.map +1 -1
- package/dist/node-prod/index.mjs +4 -0
- package/dist/node-prod/index.mjs.map +1 -1
- package/dist/node-prod/load-script.js +3 -1
- package/dist/node-prod/load-script.js.map +1 -1
- package/dist/node-prod/load-script.mjs +3 -1
- package/dist/node-prod/load-script.mjs.map +1 -1
- package/dist/node-prod/parse-metafield.js.map +1 -1
- package/dist/node-prod/parse-metafield.mjs.map +1 -1
- package/dist/node-prod/storefront-client.js +8 -7
- package/dist/node-prod/storefront-client.js.map +1 -1
- package/dist/node-prod/storefront-client.mjs +8 -7
- package/dist/node-prod/storefront-client.mjs.map +1 -1
- package/dist/node-prod/useCartAPIStateMachine.js +9 -0
- package/dist/node-prod/useCartAPIStateMachine.js.map +1 -1
- package/dist/node-prod/useCartAPIStateMachine.mjs +9 -0
- package/dist/node-prod/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/node-prod/useCartActions.js.map +1 -1
- package/dist/node-prod/useCartActions.mjs.map +1 -1
- package/dist/node-prod/useMoney.js +1 -0
- package/dist/node-prod/useMoney.js.map +1 -1
- package/dist/node-prod/useMoney.mjs +1 -0
- package/dist/node-prod/useMoney.mjs.map +1 -1
- package/dist/types/AddToCartButton.d.ts +4 -1
- package/dist/types/BaseButton.d.ts +2 -2
- package/dist/types/BuyNowButton.d.ts +3 -1
- package/dist/types/CartCheckoutButton.d.ts +3 -1
- package/dist/types/CartCost.d.ts +3 -1
- package/dist/types/CartLinePrice.d.ts +15 -1
- package/dist/types/CartLineProvider.d.ts +11 -5
- package/dist/types/CartLineQuantity.d.ts +13 -0
- package/dist/types/CartLineQuantityAdjustButton.d.ts +13 -0
- package/dist/types/CartProvider.d.ts +1 -1
- package/dist/types/ExternalVideo.d.ts +2 -2
- package/dist/types/Money.d.ts +2 -3
- package/dist/types/ProductPrice.d.ts +3 -1
- package/dist/types/ShopifyProvider.d.ts +9 -6
- package/dist/types/analytics-types.d.ts +60 -11
- package/dist/types/flatten-connection.d.ts +4 -0
- package/dist/types/image-size.d.ts +1 -1
- package/dist/types/index.d.cts +2 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/parse-metafield.d.ts +1 -1
- package/dist/types/storefront-api-response.types.d.ts +1 -1
- package/dist/types/storefront-api-types.d.ts +2 -1
- package/dist/types/storefront-client.d.ts +1 -1
- package/dist/umd/hydrogen-react.dev.js +271 -346
- package/dist/umd/hydrogen-react.dev.js.map +1 -1
- package/dist/umd/hydrogen-react.prod.js +15 -31
- package/dist/umd/hydrogen-react.prod.js.map +1 -1
- package/package.json +32 -22
- package/storefront.schema.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
# Hydrogen React
|
|
4
4
|
|
|
5
|
-
Hydrogen React
|
|
5
|
+
Hydrogen React is an unopionated and performant library of Shopify-specific commerce components, hooks, and utilities. Bring the best parts of Hydrogen to more React frameworks, like Next.js and Gatsby, and accelerate headless development using Shopify’s pre-built React components including Cart, Shop Pay, and Shopify Analytics.
|
|
6
|
+
|
|
7
|
+
📚 [Overview](https://shopify.dev/custom-storefronts/hydrogen-react) | 🛠️ [Docs](https://shopify.dev/docs/api/hydrogen-react) | 🛍️ [Custom Storefronts at Shopify](https://shopify.dev/custom-storefronts) | 🗣 [Discord](https://discord.gg/Hefq6w5c5d) | 📝 [Changelog](https://github.com/Shopify/hydrogen-react/blob/main/packages/react/CHANGELOG.md)
|
|
6
8
|
|
|
7
9
|
**IMPORTANT:** Refer to how this package is [versioned](../../README.md#versioning).
|
|
8
10
|
|
|
@@ -13,12 +15,11 @@ Hydrogen React provides React components, reusable functions, and utilities for
|
|
|
13
15
|
This document contains the following topics:
|
|
14
16
|
|
|
15
17
|
- [Getting started with Hydrogen React](#getting-started)
|
|
16
|
-
- [
|
|
18
|
+
- [Improving the Developer Experience](#improving-the-developer-experience)
|
|
17
19
|
- [Development and production bundles](#development-and-production-bundles)
|
|
18
20
|
- [Hydrogen React in the browser](#hydrogen-react-in-the-browser)
|
|
19
|
-
- [Enabling autocompletion for the Storefront API](#enable-storefront-api-graphql-autocompletion)
|
|
20
|
-
- [Setting TypeScript types for Storefront API objects](#typescript)
|
|
21
21
|
- [Troubleshooting](#troubleshooting)
|
|
22
|
+
- [Contributing](#contributing)
|
|
22
23
|
|
|
23
24
|
## Getting started
|
|
24
25
|
|
|
@@ -36,107 +37,16 @@ This document contains the following topics:
|
|
|
36
37
|
yarn add @shopify/hydrogen-react
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
To make it easier to query the Storefront API, Hydrogen React exposes a helper function called `createStorefrontClient()`.
|
|
42
|
-
|
|
43
|
-
The client can take in the following tokens:
|
|
44
|
-
|
|
45
|
-
- **[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`.
|
|
46
|
-
|
|
47
|
-
- **[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`.
|
|
48
|
-
|
|
49
|
-
The following is an example:
|
|
50
|
-
|
|
51
|
-
```ts
|
|
52
|
-
// Filename: '/shopify-client.js'
|
|
53
|
-
|
|
54
|
-
import {createStorefrontClient} from '@shopify/hydrogen-react';
|
|
55
|
-
|
|
56
|
-
const client = createStorefrontClient({
|
|
57
|
-
privateStorefrontToken: '...',
|
|
58
|
-
storeDomain: 'myshop',
|
|
59
|
-
storefrontApiVersion: '2023-01',
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
export const getStorefrontApiUrl = client.getStorefrontApiUrl;
|
|
63
|
-
export const getPrivateTokenHeaders = client.getPrivateTokenHeaders;
|
|
64
|
-
export const getShopifyDomain = client.getShopifyDomain;
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
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):
|
|
68
|
-
|
|
69
|
-
```ts
|
|
70
|
-
// Filename: '/pages/index.js'
|
|
71
|
-
|
|
72
|
-
import {
|
|
73
|
-
getStorefrontApiUrl,
|
|
74
|
-
getPrivateTokenHeaders,
|
|
75
|
-
} from '../shopify-client.js';
|
|
76
|
-
|
|
77
|
-
export async function getServerSideProps() {
|
|
78
|
-
const response = await fetch(getStorefrontApiUrl(), {
|
|
79
|
-
body: GRAPHQL_QUERY,
|
|
80
|
-
headers: getPrivateTokenHeaders({buyerIp: '...'}),
|
|
81
|
-
method: 'POST',
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const json = await response.json();
|
|
40
|
+
Browse our [overview](https://shopify.dev/custom-storefronts/hydrogen-react) and [docs](https://shopify.dev/docs/api/hydrogen-react) to learn more.
|
|
85
41
|
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
```
|
|
42
|
+
## Improving the Developer Experience
|
|
89
43
|
|
|
90
|
-
|
|
44
|
+
`hydrogen-react` includes several tools that improve the developer experience, such as:
|
|
91
45
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
export default function handler(req, res) {
|
|
97
|
-
fetch(getShopifyDomain() + '/products', {
|
|
98
|
-
headers: {
|
|
99
|
-
/** forward some of the headers from the original request **/
|
|
100
|
-
},
|
|
101
|
-
})
|
|
102
|
-
.then((resp) => resp.text())
|
|
103
|
-
.then((text) => res.status(200).send(text))
|
|
104
|
-
.catch((error) => {
|
|
105
|
-
console.error(
|
|
106
|
-
`Error proxying the online store: ${
|
|
107
|
-
error instanceof Error ? error.stack : error
|
|
108
|
-
}`
|
|
109
|
-
);
|
|
110
|
-
res.status(500).send('Server error occurred');
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### (Optional) Set the content type for the Storefront client
|
|
116
|
-
|
|
117
|
-
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:
|
|
118
|
-
|
|
119
|
-
```json
|
|
120
|
-
{
|
|
121
|
-
"query": "...",
|
|
122
|
-
"operationName": "...",
|
|
123
|
-
"variables": { "myVariable": "someValue", ... }
|
|
124
|
-
}
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
However, when the body is only a query string, such as `{"..."}`, you can optionally change the default header to `application/graphql`:
|
|
128
|
-
|
|
129
|
-
```ts
|
|
130
|
-
createStorefrontClient({contentType: 'graphql', ...})
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Alternatively, each time you get the headers you can customize which `"content-type"` you want, for only that one invocation:
|
|
134
|
-
|
|
135
|
-
```ts
|
|
136
|
-
getPrivateTokenHeaders({contentType: 'graphql'});
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
**Note:** If you're using TypeScript, then you can [improve the typing experience](#set-typescript-types).
|
|
46
|
+
- Creating a [storefront client](https://shopify.dev/docs/api/hydrogen-react/utilities/createstorefrontclient) to easily make API requests to the Storefront API
|
|
47
|
+
- Enabling [GraphQL validation and autocompletion](https://shopify.dev/docs/api/hydrogen-react/utilities/storefront-schema) for the Storefront API
|
|
48
|
+
- Using the pre-built [TypeScript types for the Storefront API](https://shopify.dev/docs/api/hydrogen-react/utilities/storefront-api-types)
|
|
49
|
+
- Correctly typing the Storefront API's custom scalars [when using GraphQL Codegen](https://shopify.dev/docs/api/hydrogen-react/utilities/storefrontapicustomscalars) and TypeScript
|
|
140
50
|
|
|
141
51
|
## Development and production bundles
|
|
142
52
|
|
|
@@ -150,105 +60,7 @@ Depending on the bundler or runtime that you're using, the correct bundle might
|
|
|
150
60
|
|
|
151
61
|
Hydrogen React 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.
|
|
152
62
|
|
|
153
|
-
If you're using Hydrogen React as a global through the `<script>` tag, then the components can be accessed through the `
|
|
154
|
-
|
|
155
|
-
## Enable Storefront API GraphQL autocompletion
|
|
156
|
-
|
|
157
|
-
To improve your development experience, enable GraphQL autocompletion for the Storefront API in your integrated development environment (IDE).
|
|
158
|
-
|
|
159
|
-
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:
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
yarn add --dev graphql graphql-config
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
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`.
|
|
166
|
-
1. Add a [`schema`](https://www.graphql-config.com/docs/user/user-schema) and point it to Hydrogen React's bundled schema for the Storefront API.
|
|
167
|
-
|
|
168
|
-
For example:
|
|
169
|
-
|
|
170
|
-
```yml
|
|
171
|
-
# Filename: .graphqlrc.yml
|
|
172
|
-
schema: node_modules/@shopify/hydrogen-react/storefront.schema.json
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
1. Install a GraphQL extension in your IDE, such as the [GraphQL extension for VSCode](https://marketplace.visualstudio.com/items?itemName=GraphQL.vscode-graphql).
|
|
176
|
-
|
|
177
|
-
GraphQL autocompletion and validation will now work in `.graphql` files and in [`gql`](https://github.com/apollographql/graphql-tag) template literals!
|
|
178
|
-
|
|
179
|
-
If you're having trouble getting it to work, then consult our [troubleshooting section](#graphql-autocompletion).
|
|
180
|
-
|
|
181
|
-
## TypeScript
|
|
182
|
-
|
|
183
|
-
Improve your development experience by using Hydrogen React's generated Types and helpers.
|
|
184
|
-
|
|
185
|
-
### Storefront API types
|
|
186
|
-
|
|
187
|
-
Hydrogen React ships with generated TypeScript types that match the Storefront API and its objects. Import them from the `/storefront-api-types` package path:
|
|
188
|
-
|
|
189
|
-
```ts
|
|
190
|
-
import type {Product} from '@shopify/hydrogen-react/storefront-api-types';
|
|
191
|
-
|
|
192
|
-
const product = {} satisfies Product;
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
You can also use TypeScript's built-in helpers to create your own Types to fit your needs:
|
|
196
|
-
|
|
197
|
-
```ts
|
|
198
|
-
const partialProduct = {} satisfies Partial<Product>;
|
|
199
|
-
|
|
200
|
-
const productTitle: Pick<Product, 'title'> = '';
|
|
201
|
-
|
|
202
|
-
const productExceptTitle = {} satisfies Omit<Product, 'title'>;
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### GraphQL CodeGen
|
|
206
|
-
|
|
207
|
-
To use GraphQL CodeGen, follow [their guide](https://the-guild.dev/graphql/codegen/docs/getting-started/installation) to get started. Then, when you have a `codegen.ts` file, you can modify the following lines in the codegen object to improve the CodgeGen experience:
|
|
208
|
-
|
|
209
|
-
```ts
|
|
210
|
-
import {storefrontApiCustomScalars} from '@shopify/hydrogen-react';
|
|
211
|
-
|
|
212
|
-
const config: CodegenConfig = {
|
|
213
|
-
// Use the schema that's bundled with @shopify/hydrogen-react
|
|
214
|
-
schema: './node_modules/@shopify/hydrogen-react/storefront.schema.json',
|
|
215
|
-
generates: {
|
|
216
|
-
'./gql/': {
|
|
217
|
-
preset: 'client',
|
|
218
|
-
plugins: [],
|
|
219
|
-
config: {
|
|
220
|
-
// Use the custom scalar definitions that @shopify/hydrogen-react provides to improve the types
|
|
221
|
-
scalars: storefrontApiCustomScalars,
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### The `StorefrontApiResponseError` and `StorefrontApiResponseOk` helpers
|
|
229
|
-
|
|
230
|
-
The following is an example:
|
|
231
|
-
|
|
232
|
-
```tsx
|
|
233
|
-
import {
|
|
234
|
-
type StorefrontApiResponseError,
|
|
235
|
-
type StorefrontApiResponseOk,
|
|
236
|
-
} from '@shopify/hydrogen-react';
|
|
237
|
-
|
|
238
|
-
async function FetchApi<DataGeneric>() {
|
|
239
|
-
const apiResponse = await fetch('...');
|
|
240
|
-
|
|
241
|
-
if (!apiResponse.ok) {
|
|
242
|
-
// 400 or 500 level error
|
|
243
|
-
return (await apiResponse.text()) as StorefrontApiResponseError; // or apiResponse.json()
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const graphqlResponse: StorefrontApiResponseOk<DataGeneric> =
|
|
247
|
-
await apiResponse.json();
|
|
248
|
-
|
|
249
|
-
// You can now access 'graphqlResponse.data' and 'graphqlResponse.errors'
|
|
250
|
-
}
|
|
251
|
-
```
|
|
63
|
+
If you're using Hydrogen React as a global through the `<script>` tag, then the components can be accessed through the `hydrogenreact` global variable.
|
|
252
64
|
|
|
253
65
|
## Troubleshooting
|
|
254
66
|
|
|
@@ -263,3 +75,9 @@ For example, in VSCode do the following:
|
|
|
263
75
|
1. Open the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette).
|
|
264
76
|
1. Type `graphql`.
|
|
265
77
|
1. Select `VSCode GraphQL: Manual Restart`.
|
|
78
|
+
|
|
79
|
+
## Contributing
|
|
80
|
+
|
|
81
|
+
We love contributions! Contributing works best when you first confirm that something needs to be changed or fixed; please open an issue, start a discussion, or talk to us in Discord!
|
|
82
|
+
|
|
83
|
+
PRs are welcome! Be sure to read the [CONTRIBUTING.md](../../CONTRIBUTING.md) for an overview and guidelines to help your PR succeed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddToCartButton.mjs","sources":["../../src/AddToCartButton.tsx"],"sourcesContent":["import {useCallback, useEffect, useState} from 'react';\nimport {useCart} from './CartProvider.js';\nimport {useProduct} from './ProductProvider.js';\nimport {BaseButton
|
|
1
|
+
{"version":3,"file":"AddToCartButton.mjs","sources":["../../src/AddToCartButton.tsx"],"sourcesContent":["import {useCallback, useEffect, useState} from 'react';\nimport {useCart} from './CartProvider.js';\nimport {useProduct} from './ProductProvider.js';\nimport {\n BaseButton,\n type CustomBaseButtonProps,\n type BaseButtonProps,\n} from './BaseButton.js';\nimport * as React from 'react';\n\nexport interface AddToCartButtonPropsBase {\n /** An array of cart line attributes that belong to the item being added to the cart. */\n attributes?: {\n key: string;\n value: string;\n }[];\n /** The ID of the variant. */\n variantId?: string | null;\n /** The item quantity. */\n quantity?: number;\n /** The text that is announced by the screen reader when the item is being added to the cart. Used for accessibility purposes only and not displayed on the page. */\n accessibleAddingToCartLabel?: string;\n /** The selling plan ID of the subscription variant */\n sellingPlanId?: string;\n}\n\nexport type AddToCartButtonProps<AsType extends React.ElementType = 'button'> =\n AddToCartButtonPropsBase & BaseButtonProps<AsType>;\n\n/**\n * The `AddToCartButton` component renders a button that adds an item to the cart when pressed.\n * It must be a descendent of the `CartProvider` component.\n */\nexport function AddToCartButton<AsType extends React.ElementType = 'button'>(\n props: AddToCartButtonProps<AsType>\n): JSX.Element {\n const [addingItem, setAddingItem] = useState<boolean>(false);\n const {\n variantId: explicitVariantId,\n quantity = 1,\n attributes,\n sellingPlanId,\n onClick,\n children,\n accessibleAddingToCartLabel,\n ...passthroughProps\n } = props;\n const {status, linesAdd} = useCart();\n const {selectedVariant} = useProduct();\n const variantId = explicitVariantId ?? selectedVariant?.id ?? '';\n const disabled =\n explicitVariantId === null ||\n variantId === '' ||\n selectedVariant === null ||\n addingItem ||\n passthroughProps.disabled;\n\n useEffect(() => {\n if (addingItem && status === 'idle') {\n setAddingItem(false);\n }\n }, [status, addingItem]);\n\n const handleAddItem = useCallback(() => {\n setAddingItem(true);\n linesAdd([\n {\n quantity,\n merchandiseId: variantId || '',\n attributes,\n sellingPlanId,\n },\n ]);\n }, [linesAdd, quantity, variantId, attributes, sellingPlanId]);\n\n return (\n <>\n <BaseButton\n {...passthroughProps}\n disabled={disabled}\n onClick={onClick}\n defaultOnClick={handleAddItem}\n >\n {children}\n </BaseButton>\n {accessibleAddingToCartLabel ? (\n <p\n style={{\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n borderWidth: '0',\n }}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {addingItem ? accessibleAddingToCartLabel : null}\n </p>\n ) : null}\n </>\n );\n}\n\n// This is only for documenation purposes, and it is not used in the code.\nexport interface AddToCartButtonPropsForDocs<\n AsType extends React.ElementType = 'button'\n> extends AddToCartButtonPropsBase,\n CustomBaseButtonProps<AsType> {}\n"],"names":[],"mappings":";;;;;AAiCO,SAAS,gBACd,OACa;AACb,QAAM,CAAC,YAAY,aAAa,IAAI,SAAkB,KAAK;AACrD,QAAA;AAAA,IACJ,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACD,IAAA;AACJ,QAAM,EAAC,QAAQ,SAAQ,IAAI,QAAQ;AAC7B,QAAA,EAAC,oBAAmB;AACpB,QAAA,YAAY,sBAAqB,mDAAiB,OAAM;AACxD,QAAA,WACJ,sBAAsB,QACtB,cAAc,MACd,oBAAoB,QACpB,cACA,iBAAiB;AAEnB,YAAU,MAAM;AACV,QAAA,cAAc,WAAW,QAAQ;AACnC,oBAAc,KAAK;AAAA,IACrB;AAAA,EAAA,GACC,CAAC,QAAQ,UAAU,CAAC;AAEjB,QAAA,gBAAgB,YAAY,MAAM;AACtC,kBAAc,IAAI;AACT,aAAA;AAAA,MACP;AAAA,QACE;AAAA,QACA,eAAe,aAAa;AAAA,QAC5B;AAAA,QACA;AAAA,MACF;AAAA,IAAA,CACD;AAAA,EAAA,GACA,CAAC,UAAU,UAAU,WAAW,YAAY,aAAa,CAAC;AAE7D,SAEI,qBAAA,UAAA,EAAA,UAAA;AAAA,IAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACE,GAAG;AAAA,QACJ;AAAA,QACA;AAAA,QACA,gBAAgB;AAAA,QAEf;AAAA,MAAA;AAAA,IACH;AAAA,IACC,8BACC;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,OAAO;AAAA,UACL,UAAU;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,aAAa;AAAA,QACf;AAAA,QACA,MAAK;AAAA,QACL,aAAU;AAAA,QAET,uBAAa,8BAA8B;AAAA,MAAA;AAAA,IAAA,IAE5C;AAAA,EACN,EAAA,CAAA;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseButton.mjs","sources":["../../src/BaseButton.tsx"],"sourcesContent":["import {ReactNode, Ref, useCallback} from 'react';\n\nexport interface CustomBaseButtonProps<AsType> {\n /** Provide a React element or component to render as the underlying button. Note: for accessibility compliance, almost always you should use a `button` element, or a component that renders an underlying button. */\n as?: AsType;\n /** Any ReactNode elements. */\n children: ReactNode;\n /** Click event handler. Default behaviour triggers unless prevented */\n onClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A default onClick behavior */\n defaultOnClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A ref to the underlying button */\n buttonRef?: Ref<HTMLButtonElement>;\n}\n\nexport type BaseButtonProps<AsType extends React.ElementType> =\n CustomBaseButtonProps<AsType> &\n Omit<\n React.ComponentPropsWithoutRef<AsType>,\n keyof CustomBaseButtonProps<AsType>\n >;\n\nexport function BaseButton<AsType extends React.ElementType = 'button'>(\n props: BaseButtonProps<AsType>\n) {\n const {\n as,\n onClick,\n defaultOnClick,\n children,\n buttonRef,\n ...passthroughProps\n } = props;\n\n const handleOnClick = useCallback(\n (event?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n if (onClick) {\n const clickShouldContinue = onClick(event);\n if (\n (typeof clickShouldContinue === 'boolean' &&\n clickShouldContinue === false) ||\n event?.defaultPrevented\n )\n return;\n }\n\n defaultOnClick?.(event);\n },\n [defaultOnClick, onClick]\n );\n\n const Component = as || 'button';\n\n return (\n <Component ref={buttonRef} onClick={handleOnClick} {...passthroughProps}>\n {children}\n </Component>\n );\n}\n"],"names":[],"mappings":";;AA0BO,SAAS,WACd,
|
|
1
|
+
{"version":3,"file":"BaseButton.mjs","sources":["../../src/BaseButton.tsx"],"sourcesContent":["import {ReactNode, Ref, useCallback} from 'react';\n\nexport interface CustomBaseButtonProps<AsType> {\n /** Provide a React element or component to render as the underlying button. Note: for accessibility compliance, almost always you should use a `button` element, or a component that renders an underlying button. */\n as?: AsType;\n /** Any ReactNode elements. */\n children: ReactNode;\n /** Click event handler. Default behaviour triggers unless prevented */\n onClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A default `onClick` behavior */\n defaultOnClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A `ref` to the underlying button */\n buttonRef?: Ref<HTMLButtonElement>;\n}\n\nexport type BaseButtonProps<AsType extends React.ElementType> =\n CustomBaseButtonProps<AsType> &\n Omit<\n React.ComponentPropsWithoutRef<AsType>,\n keyof CustomBaseButtonProps<AsType>\n >;\n\nexport function BaseButton<AsType extends React.ElementType = 'button'>(\n props: BaseButtonProps<AsType>\n): JSX.Element {\n const {\n as,\n onClick,\n defaultOnClick,\n children,\n buttonRef,\n ...passthroughProps\n } = props;\n\n const handleOnClick = useCallback(\n (event?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n if (onClick) {\n const clickShouldContinue = onClick(event);\n if (\n (typeof clickShouldContinue === 'boolean' &&\n clickShouldContinue === false) ||\n event?.defaultPrevented\n )\n return;\n }\n\n defaultOnClick?.(event);\n },\n [defaultOnClick, onClick]\n );\n\n const Component = as || 'button';\n\n return (\n <Component ref={buttonRef} onClick={handleOnClick} {...passthroughProps}>\n {children}\n </Component>\n );\n}\n"],"names":[],"mappings":";;AA0BO,SAAS,WACd,OACa;AACP,QAAA;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACD,IAAA;AAEJ,QAAM,gBAAgB;AAAA,IACpB,CAAC,UAA4D;AAC3D,UAAI,SAAS;AACL,cAAA,sBAAsB,QAAQ,KAAK;AACzC,YACG,OAAO,wBAAwB,aAC9B,wBAAwB,UAC1B,+BAAO;AAEP;AAAA,MACJ;AAEA,uDAAiB;AAAA,IACnB;AAAA,IACA,CAAC,gBAAgB,OAAO;AAAA,EAAA;AAG1B,QAAM,YAAY,MAAM;AAGtB,SAAA,oBAAC,aAAU,KAAK,WAAW,SAAS,eAAgB,GAAG,kBACpD,SACH,CAAA;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BuyNowButton.mjs","sources":["../../src/BuyNowButton.tsx"],"sourcesContent":["import {useEffect, useState, useCallback} from 'react';\nimport {useCart} from './CartProvider.js';\nimport {BaseButton
|
|
1
|
+
{"version":3,"file":"BuyNowButton.mjs","sources":["../../src/BuyNowButton.tsx"],"sourcesContent":["import {useEffect, useState, useCallback} from 'react';\nimport {useCart} from './CartProvider.js';\nimport {\n BaseButton,\n type BaseButtonProps,\n type CustomBaseButtonProps,\n} from './BaseButton.js';\n\ninterface BuyNowButtonPropsBase {\n /** The item quantity. Defaults to 1. */\n quantity?: number;\n /** The ID of the variant. */\n variantId: string;\n /** An array of cart line attributes that belong to the item being added to the cart. */\n attributes?: {\n key: string;\n value: string;\n }[];\n}\n\ntype BuyNowButtonProps<AsType extends React.ElementType = 'button'> =\n BuyNowButtonPropsBase & BaseButtonProps<AsType>;\n\n/**\n * The `BuyNowButton` component renders a button that adds an item to the cart and redirects the customer to checkout.\n * Must be a child of a `CartProvider` component.\n */\nexport function BuyNowButton<AsType extends React.ElementType = 'button'>(\n props: BuyNowButtonProps<AsType>\n): JSX.Element {\n const {cartCreate, checkoutUrl} = useCart();\n const [loading, setLoading] = useState<boolean>(false);\n\n const {\n quantity,\n variantId,\n onClick,\n attributes,\n children,\n ...passthroughProps\n } = props;\n\n useEffect(() => {\n if (checkoutUrl) {\n window.location.href = checkoutUrl;\n }\n }, [checkoutUrl]);\n\n const handleBuyNow = useCallback(() => {\n setLoading(true);\n cartCreate({\n lines: [\n {\n quantity: quantity ?? 1,\n merchandiseId: variantId,\n attributes,\n },\n ],\n });\n }, [cartCreate, quantity, variantId, attributes]);\n\n return (\n <BaseButton\n disabled={loading ?? passthroughProps.disabled}\n {...passthroughProps}\n onClick={onClick}\n defaultOnClick={handleBuyNow}\n >\n {children}\n </BaseButton>\n );\n}\n\n// This is only for documenation purposes, and it is not used in the code.\nexport interface BuyNowButtonPropsForDocs<\n AsType extends React.ElementType = 'button'\n> extends BuyNowButtonPropsBase,\n CustomBaseButtonProps<AsType> {}\n"],"names":[],"mappings":";;;;AA2BO,SAAS,aACd,OACa;AACb,QAAM,EAAC,YAAY,YAAW,IAAI,QAAQ;AAC1C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAkB,KAAK;AAE/C,QAAA;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACD,IAAA;AAEJ,YAAU,MAAM;AACd,QAAI,aAAa;AACf,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,EAAA,GACC,CAAC,WAAW,CAAC;AAEV,QAAA,eAAe,YAAY,MAAM;AACrC,eAAW,IAAI;AACJ,eAAA;AAAA,MACT,OAAO;AAAA,QACL;AAAA,UACE,UAAU,YAAY;AAAA,UACtB,eAAe;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,IAAA,CACD;AAAA,KACA,CAAC,YAAY,UAAU,WAAW,UAAU,CAAC;AAG9C,SAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,UAAU,WAAW,iBAAiB;AAAA,MACrC,GAAG;AAAA,MACJ;AAAA,MACA,gBAAgB;AAAA,MAEf;AAAA,IAAA;AAAA,EAAA;AAGP;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartCheckoutButton.mjs","sources":["../../src/CartCheckoutButton.tsx"],"sourcesContent":["import {ReactNode, useEffect, useState} from 'react';\nimport {useCart} from './CartProvider.js';\nimport {BaseButton
|
|
1
|
+
{"version":3,"file":"CartCheckoutButton.mjs","sources":["../../src/CartCheckoutButton.tsx"],"sourcesContent":["import {ReactNode, useEffect, useState} from 'react';\nimport {useCart} from './CartProvider.js';\nimport {\n BaseButton,\n type BaseButtonProps,\n type CustomBaseButtonProps,\n} from './BaseButton.js';\n\ntype ChildrenProps = {\n /** A `ReactNode` element. */\n children: ReactNode;\n};\ntype CartCheckoutButtonProps = Omit<BaseButtonProps<'button'>, 'onClick'> &\n ChildrenProps;\n\n/**\n * The `CartCheckoutButton` component renders a button that redirects to the checkout URL for the cart.\n * It must be a descendent of a `CartProvider` component.\n */\nexport function CartCheckoutButton(\n props: CartCheckoutButtonProps\n): JSX.Element {\n const [requestedCheckout, setRequestedCheckout] = useState(false);\n const {status, checkoutUrl} = useCart();\n const {children, ...passthroughProps} = props;\n\n useEffect(() => {\n if (requestedCheckout && checkoutUrl && status === 'idle') {\n window.location.href = checkoutUrl;\n }\n }, [requestedCheckout, status, checkoutUrl]);\n\n return (\n <BaseButton\n {...passthroughProps}\n disabled={requestedCheckout || passthroughProps.disabled}\n onClick={(): void => setRequestedCheckout(true)}\n >\n {children}\n </BaseButton>\n );\n}\n\n// This is only for documentation purposes, and it is not used in the code.\n// we ignore this issue because it makes the documentation look better than the equivalent `type` that it wants us to convert to\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface CartCheckoutButtonPropsForDocs<\n AsType extends React.ElementType = 'button'\n> extends Omit<CustomBaseButtonProps<AsType>, 'onClick'> {}\n"],"names":[],"mappings":";;;;AAmBO,SAAS,mBACd,OACa;AACb,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,SAAS,KAAK;AAChE,QAAM,EAAC,QAAQ,YAAW,IAAI,QAAQ;AACtC,QAAM,EAAC,UAAU,GAAG,iBAAA,IAAoB;AAExC,YAAU,MAAM;AACV,QAAA,qBAAqB,eAAe,WAAW,QAAQ;AACzD,aAAO,SAAS,OAAO;AAAA,IACzB;AAAA,EACC,GAAA,CAAC,mBAAmB,QAAQ,WAAW,CAAC;AAGzC,SAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ,UAAU,qBAAqB,iBAAiB;AAAA,MAChD,SAAS,MAAY,qBAAqB,IAAI;AAAA,MAE7C;AAAA,IAAA;AAAA,EAAA;AAGP;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartCost.mjs","sources":["../../src/CartCost.tsx"],"sourcesContent":["import {Money} from './Money.js';\nimport {useCart} from './CartProvider.js';\n\ninterface CartCostPropsBase {\n /** A string type that defines the type of cost needed. Valid values: `total`, `subtotal`, `tax`, or `duty`. */\n amountType?: 'total' | 'subtotal' | 'tax' | 'duty';\n /** Any `ReactNode` elements. */\n children?: React.ReactNode;\n}\n\ntype CartCostProps = Omit<React.ComponentProps<typeof Money>, 'data'> &\n CartCostPropsBase;\n\n/**\n * The `CartCost` component renders a `Money` component with the cost associated with the `amountType` prop.\n * If no `amountType` prop is specified, then it defaults to `totalAmount`.\n * Depends on `useCart()` and must be a child of `<CartProvider/>`\n */\nexport function CartCost(props: CartCostProps) {\n const {cost} = useCart();\n const {amountType = 'total', children, ...passthroughProps} = props;\n let amount;\n\n if (amountType == 'total') {\n amount = cost?.totalAmount;\n } else if (amountType == 'subtotal') {\n amount = cost?.subtotalAmount;\n } else if (amountType == 'tax') {\n amount = cost?.totalTaxAmount;\n } else if (amountType == 'duty') {\n amount = cost?.totalDutyAmount;\n }\n\n if (amount == null) {\n return null;\n }\n\n return (\n <Money {...passthroughProps} data={amount}>\n {children}\n </Money>\n );\n}\n"],"names":[],"mappings":";;;AAkBO,SAAS,SAAS,
|
|
1
|
+
{"version":3,"file":"CartCost.mjs","sources":["../../src/CartCost.tsx"],"sourcesContent":["import {Money, type MoneyPropsBase} from './Money.js';\nimport {useCart} from './CartProvider.js';\n\ninterface CartCostPropsBase {\n /** A string type that defines the type of cost needed. Valid values: `total`, `subtotal`, `tax`, or `duty`. */\n amountType?: 'total' | 'subtotal' | 'tax' | 'duty';\n /** Any `ReactNode` elements. */\n children?: React.ReactNode;\n}\n\ntype CartCostProps = Omit<React.ComponentProps<typeof Money>, 'data'> &\n CartCostPropsBase;\n\n/**\n * The `CartCost` component renders a `Money` component with the cost associated with the `amountType` prop.\n * If no `amountType` prop is specified, then it defaults to `totalAmount`.\n * Depends on `useCart()` and must be a child of `<CartProvider/>`\n */\nexport function CartCost(props: CartCostProps): JSX.Element | null {\n const {cost} = useCart();\n const {amountType = 'total', children, ...passthroughProps} = props;\n let amount;\n\n if (amountType == 'total') {\n amount = cost?.totalAmount;\n } else if (amountType == 'subtotal') {\n amount = cost?.subtotalAmount;\n } else if (amountType == 'tax') {\n amount = cost?.totalTaxAmount;\n } else if (amountType == 'duty') {\n amount = cost?.totalDutyAmount;\n }\n\n if (amount == null) {\n return null;\n }\n\n return (\n <Money {...passthroughProps} data={amount}>\n {children}\n </Money>\n );\n}\n\n// This is only for documenation purposes, and it is not used in the code.\nexport interface CartCostPropsForDocs<AsType extends React.ElementType = 'div'>\n extends Omit<MoneyPropsBase<AsType>, 'data'>,\n CartCostPropsBase {}\n"],"names":[],"mappings":";;;AAkBO,SAAS,SAAS,OAA0C;AAC3D,QAAA,EAAC,SAAQ;AACf,QAAM,EAAC,aAAa,SAAS,UAAU,GAAG,iBAAoB,IAAA;AAC1D,MAAA;AAEJ,MAAI,cAAc,SAAS;AACzB,aAAS,6BAAM;AAAA,EAAA,WACN,cAAc,YAAY;AACnC,aAAS,6BAAM;AAAA,EAAA,WACN,cAAc,OAAO;AAC9B,aAAS,6BAAM;AAAA,EAAA,WACN,cAAc,QAAQ;AAC/B,aAAS,6BAAM;AAAA,EACjB;AAEA,MAAI,UAAU,MAAM;AACX,WAAA;AAAA,EACT;AAEA,6BACG,OAAO,EAAA,GAAG,kBAAkB,MAAM,QAChC,SACH,CAAA;AAEJ;"}
|
|
@@ -2,6 +2,9 @@ import { jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { Money } from "./Money.mjs";
|
|
3
3
|
function CartLinePrice(props) {
|
|
4
4
|
var _a, _b;
|
|
5
|
+
{
|
|
6
|
+
console.warn(`<CartLinePrice/> is deprecated; use <Money/> instead.`);
|
|
7
|
+
}
|
|
5
8
|
const { data: cartLine, priceType = "regular", ...passthroughProps } = props;
|
|
6
9
|
if (cartLine == null) {
|
|
7
10
|
throw new Error(`<CartLinePrice/> requires a cart line as the 'data' prop`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartLinePrice.mjs","sources":["../../src/CartLinePrice.tsx"],"sourcesContent":["import {Money} from './Money.js';\nimport {CartLine} from './storefront-api-types.js';\nimport {PartialDeep} from 'type-fest';\n\ninterface CartLinePricePropsBase {\n /** A [CartLine object](https://shopify.dev/api/storefront/reference/objects/CartLine). */\n data: PartialDeep<CartLine, {recurseIntoArrays: true}>;\n /** The type of price. Valid values:`regular` (default) or `compareAt`. */\n priceType?: 'regular' | 'compareAt';\n}\n\ntype CartLinePriceProps = Omit<React.ComponentProps<typeof Money>, 'data'> &\n CartLinePricePropsBase;\n\n/**\n * The `CartLinePrice` component renders a `Money` component for the cart line merchandise's price or compare at price.\n */\nexport function CartLinePrice(props: CartLinePriceProps) {\n const {data: cartLine, priceType = 'regular', ...passthroughProps} = props;\n\n if (cartLine == null) {\n throw new Error(`<CartLinePrice/> requires a cart line as the 'data' prop`);\n }\n\n const moneyV2 =\n priceType === 'regular'\n ? cartLine.cost?.totalAmount\n : cartLine.cost?.compareAtAmountPerQuantity;\n\n if (moneyV2 == null) {\n return null;\n }\n\n return <Money {...passthroughProps} data={moneyV2} />;\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"CartLinePrice.mjs","sources":["../../src/CartLinePrice.tsx"],"sourcesContent":["import {Money, type MoneyPropsBase} from './Money.js';\nimport {CartLine} from './storefront-api-types.js';\nimport {PartialDeep} from 'type-fest';\n\ninterface CartLinePricePropsBase {\n /** A [CartLine object](https://shopify.dev/api/storefront/reference/objects/CartLine). */\n data: PartialDeep<CartLine, {recurseIntoArrays: true}>;\n /** The type of price. Valid values:`regular` (default) or `compareAt`. */\n priceType?: 'regular' | 'compareAt';\n}\n\ntype CartLinePriceProps = Omit<React.ComponentProps<typeof Money>, 'data'> &\n CartLinePricePropsBase;\n\n/**\n * @deprecated Use `Money` instead. To migrate, use the `priceType` prop that matches the corresponding property on the `CartLine` object:\n * - `regular`: `cartLine.cost.totalAmount`\n * - `compareAt`: `cartLine.cost.compareAtAmountPerQuantity`\n *\n * For example:\n * ```\n * // before\n * <CartLinePrice data={cartLine} priceType=\"regular\" />\n * // after\n * <Money data={cartLine.cost.totalAmount} />\n * ```\n *\n * The `CartLinePrice` component renders a `Money` component for the cart line merchandise's price or compare at price.\n */\nexport function CartLinePrice(props: CartLinePriceProps): JSX.Element | null {\n if (__HYDROGEN_DEV__) {\n console.warn(`<CartLinePrice/> is deprecated; use <Money/> instead.`);\n }\n\n const {data: cartLine, priceType = 'regular', ...passthroughProps} = props;\n\n if (cartLine == null) {\n throw new Error(`<CartLinePrice/> requires a cart line as the 'data' prop`);\n }\n\n const moneyV2 =\n priceType === 'regular'\n ? cartLine.cost?.totalAmount\n : cartLine.cost?.compareAtAmountPerQuantity;\n\n if (moneyV2 == null) {\n return null;\n }\n\n return <Money {...passthroughProps} data={moneyV2} />;\n}\n\n// This is only for documenation purposes, and it is not used in the code.\nexport interface CartLinePricePropsForDocs<\n AsType extends React.ElementType = 'div'\n> extends Omit<MoneyPropsBase<AsType>, 'data'>,\n CartLinePricePropsBase {}\n"],"names":[],"mappings":";;AA6BO,SAAS,cAAc,OAA+C;;AACrD;AACpB,YAAQ,KAAK,uDAAuD;AAAA,EACtE;AAEA,QAAM,EAAC,MAAM,UAAU,YAAY,WAAW,GAAG,iBAAoB,IAAA;AAErE,MAAI,YAAY,MAAM;AACd,UAAA,IAAI,MAAM,0DAA0D;AAAA,EAC5E;AAEA,QAAM,UACJ,cAAc,aACV,cAAS,SAAT,mBAAe,eACf,cAAS,SAAT,mBAAe;AAErB,MAAI,WAAW,MAAM;AACZ,WAAA;AAAA,EACT;AAEA,SAAQ,oBAAA,OAAA,EAAO,GAAG,kBAAkB,MAAM,QAAS,CAAA;AACrD;"}
|
|
@@ -8,7 +8,10 @@ function useCartLine() {
|
|
|
8
8
|
}
|
|
9
9
|
return context;
|
|
10
10
|
}
|
|
11
|
-
function CartLineProvider({
|
|
11
|
+
function CartLineProvider({
|
|
12
|
+
children,
|
|
13
|
+
line
|
|
14
|
+
}) {
|
|
12
15
|
return /* @__PURE__ */ jsx(CartLineContext.Provider, { value: line, children });
|
|
13
16
|
}
|
|
14
17
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartLineProvider.mjs","sources":["../../src/CartLineProvider.tsx"],"sourcesContent":["import {useContext, createContext, type ReactNode} from 'react';\nimport type {CartLine} from './storefront-api-types.js';\n\nexport const CartLineContext = createContext<
|
|
1
|
+
{"version":3,"file":"CartLineProvider.mjs","sources":["../../src/CartLineProvider.tsx"],"sourcesContent":["import {useContext, createContext, type ReactNode} from 'react';\nimport type {CartLine} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\ntype CartLinePartialDeep = PartialDeep<CartLine, {recurseIntoArrays: true}>;\n\nexport const CartLineContext = createContext<CartLinePartialDeep | null>(null);\n\n/**\n * The `useCartLine` hook provides access to the [CartLine object](https://shopify.dev/api/storefront/unstable/objects/cartline) from the Storefront API. It must be a descendent of a `CartProvider` component.\n */\nexport function useCartLine(): CartLinePartialDeep {\n const context = useContext(CartLineContext);\n\n if (context == null) {\n throw new Error('Expected a cart line context but none was found');\n }\n\n return context;\n}\n\ntype CartLineProviderProps = {\n /** Any `ReactNode` elements. */\n children: ReactNode;\n /** A cart line object. */\n line: CartLinePartialDeep;\n};\n\n/**\n * The `CartLineProvider` component creates a context for using a cart line.\n */\nexport function CartLineProvider({\n children,\n line,\n}: CartLineProviderProps): JSX.Element {\n return (\n <CartLineContext.Provider value={line}>{children}</CartLineContext.Provider>\n );\n}\n"],"names":[],"mappings":";;AAMa,MAAA,kBAAkB,cAA0C,IAAI;AAKtE,SAAS,cAAmC;AAC3C,QAAA,UAAU,WAAW,eAAe;AAE1C,MAAI,WAAW,MAAM;AACb,UAAA,IAAI,MAAM,iDAAiD;AAAA,EACnE;AAEO,SAAA;AACT;AAYO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AACF,GAAuC;AACrC,6BACG,gBAAgB,UAAhB,EAAyB,OAAO,MAAO,SAAS,CAAA;AAErD;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCartLine } from "./CartLineProvider.mjs";
|
|
3
|
+
function CartLineQuantity(props) {
|
|
4
|
+
const cartLine = useCartLine();
|
|
5
|
+
const { as, ...passthroughProps } = props;
|
|
6
|
+
const Wrapper = as ? as : "span";
|
|
7
|
+
return /* @__PURE__ */ jsx(Wrapper, { ...passthroughProps, children: cartLine.quantity });
|
|
8
|
+
}
|
|
9
|
+
export {
|
|
10
|
+
CartLineQuantity
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=CartLineQuantity.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CartLineQuantity.mjs","sources":["../../src/CartLineQuantity.tsx"],"sourcesContent":["import type {ComponentPropsWithoutRef, ElementType} from 'react';\nimport {useCartLine} from './CartLineProvider.js';\n\ninterface CartLineQuantityBaseProps<\n ComponentGeneric extends ElementType = 'span'\n> {\n /** An HTML tag or React Component to be rendered as the base element wrapper. The default is `span`. */\n as?: ComponentGeneric;\n}\n\nexport type CartLineQuantityProps<ComponentGeneric extends ElementType> =\n CartLineQuantityBaseProps<ComponentGeneric> &\n Omit<\n ComponentPropsWithoutRef<ComponentGeneric>,\n keyof CartLineQuantityBaseProps<ComponentGeneric>\n >;\n\n/**\n * The `<CartLineQuantity/>` component renders a `span` (or another element / component that can be customized by the `as` prop) with the cart line's quantity.\n *\n * It must be a descendent of a `<CartLineProvider/>` component, and uses the `useCartLine()` hook internally.\n */\nexport function CartLineQuantity<ComponentGeneric extends ElementType = 'span'>(\n props: CartLineQuantityProps<ComponentGeneric>\n): JSX.Element {\n const cartLine = useCartLine();\n const {as, ...passthroughProps} = props;\n\n const Wrapper = as ? as : 'span';\n\n return <Wrapper {...passthroughProps}>{cartLine.quantity}</Wrapper>;\n}\n"],"names":[],"mappings":";;AAsBO,SAAS,iBACd,OACa;AACb,QAAM,WAAW;AACjB,QAAM,EAAC,IAAI,GAAG,iBAAA,IAAoB;AAE5B,QAAA,UAAU,KAAK,KAAK;AAE1B,SAAQ,oBAAA,SAAA,EAAS,GAAG,kBAAmB,mBAAS,SAAS,CAAA;AAC3D;"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from "react";
|
|
3
|
+
import { useCart } from "./CartProvider.mjs";
|
|
4
|
+
import { useCartLine } from "./CartLineProvider.mjs";
|
|
5
|
+
import { BaseButton } from "./BaseButton.mjs";
|
|
6
|
+
function CartLineQuantityAdjustButton(props) {
|
|
7
|
+
const { status, linesRemove, linesUpdate } = useCart();
|
|
8
|
+
const cartLine = useCartLine();
|
|
9
|
+
const { children, adjust, onClick, ...passthroughProps } = props;
|
|
10
|
+
const handleAdjust = useCallback(() => {
|
|
11
|
+
if (adjust === "remove") {
|
|
12
|
+
linesRemove([(cartLine == null ? void 0 : cartLine.id) ?? ""]);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const quantity = adjust === "decrease" ? ((cartLine == null ? void 0 : cartLine.quantity) ?? 0) - 1 : ((cartLine == null ? void 0 : cartLine.quantity) ?? 0) + 1;
|
|
16
|
+
if (quantity <= 0) {
|
|
17
|
+
linesRemove([(cartLine == null ? void 0 : cartLine.id) ?? ""]);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const lineUpdate = {
|
|
21
|
+
id: (cartLine == null ? void 0 : cartLine.id) ?? "",
|
|
22
|
+
quantity,
|
|
23
|
+
attributes: (cartLine == null ? void 0 : cartLine.attributes) ?? []
|
|
24
|
+
};
|
|
25
|
+
linesUpdate([lineUpdate]);
|
|
26
|
+
}, [
|
|
27
|
+
adjust,
|
|
28
|
+
cartLine == null ? void 0 : cartLine.attributes,
|
|
29
|
+
cartLine == null ? void 0 : cartLine.id,
|
|
30
|
+
cartLine == null ? void 0 : cartLine.quantity,
|
|
31
|
+
linesRemove,
|
|
32
|
+
linesUpdate
|
|
33
|
+
]);
|
|
34
|
+
return /* @__PURE__ */ jsx(
|
|
35
|
+
BaseButton,
|
|
36
|
+
{
|
|
37
|
+
...passthroughProps,
|
|
38
|
+
onClick,
|
|
39
|
+
defaultOnClick: handleAdjust,
|
|
40
|
+
disabled: typeof passthroughProps.disabled !== "undefined" ? passthroughProps.disabled : status !== "idle",
|
|
41
|
+
children
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
CartLineQuantityAdjustButton
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=CartLineQuantityAdjustButton.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CartLineQuantityAdjustButton.mjs","sources":["../../src/CartLineQuantityAdjustButton.tsx"],"sourcesContent":["import {useCallback} from 'react';\nimport {useCart} from './CartProvider.js';\nimport {useCartLine} from './CartLineProvider.js';\nimport {BaseButton, type BaseButtonProps} from './BaseButton.js';\nimport type {CartLineUpdateInput} from './storefront-api-types.js';\n\ninterface CartLineQuantityAdjustButtonBaseProps {\n /** The adjustment for a cart line's quantity. Valid values: `increase` (default), `decrease`, or `remove`. */\n adjust?: 'increase' | 'decrease' | 'remove';\n}\n\ntype CartLineQuantityAdjustButtonProps<\n AsType extends React.ElementType = 'button'\n> = BaseButtonProps<AsType> & CartLineQuantityAdjustButtonBaseProps;\n\n/**\n * The `<CartLineQuantityAdjustButton />` component renders a button that adjusts the cart line's quantity when pressed.\n *\n * It must be a descendent of `<CartLineProvider/>` and `<CartProvider/>`.\n */\nexport function CartLineQuantityAdjustButton<\n AsType extends React.ElementType = 'button'\n>(props: CartLineQuantityAdjustButtonProps<AsType>): JSX.Element {\n const {status, linesRemove, linesUpdate} = useCart();\n const cartLine = useCartLine();\n const {children, adjust, onClick, ...passthroughProps} = props;\n\n const handleAdjust = useCallback(() => {\n if (adjust === 'remove') {\n linesRemove([cartLine?.id ?? '']);\n return;\n }\n\n const quantity =\n adjust === 'decrease'\n ? (cartLine?.quantity ?? 0) - 1\n : (cartLine?.quantity ?? 0) + 1;\n\n if (quantity <= 0) {\n linesRemove([cartLine?.id ?? '']);\n return;\n }\n\n const lineUpdate = {\n id: cartLine?.id ?? '',\n quantity,\n attributes: (cartLine?.attributes ??\n []) as CartLineUpdateInput['attributes'],\n } satisfies CartLineUpdateInput;\n\n linesUpdate([lineUpdate]);\n }, [\n adjust,\n cartLine?.attributes,\n cartLine?.id,\n cartLine?.quantity,\n linesRemove,\n linesUpdate,\n ]);\n\n return (\n <BaseButton\n {...passthroughProps}\n onClick={onClick}\n defaultOnClick={handleAdjust}\n disabled={\n typeof passthroughProps.disabled !== 'undefined'\n ? passthroughProps.disabled\n : status !== 'idle'\n }\n >\n {children}\n </BaseButton>\n );\n}\n"],"names":[],"mappings":";;;;;AAoBO,SAAS,6BAEd,OAA+D;AAC/D,QAAM,EAAC,QAAQ,aAAa,gBAAe,QAAQ;AACnD,QAAM,WAAW;AACjB,QAAM,EAAC,UAAU,QAAQ,SAAS,GAAG,iBAAoB,IAAA;AAEnD,QAAA,eAAe,YAAY,MAAM;AACrC,QAAI,WAAW,UAAU;AACvB,kBAAY,EAAC,qCAAU,OAAM,EAAE,CAAC;AAChC;AAAA,IACF;AAEM,UAAA,WACJ,WAAW,eACN,qCAAU,aAAY,KAAK,MAC3B,qCAAU,aAAY,KAAK;AAElC,QAAI,YAAY,GAAG;AACjB,kBAAY,EAAC,qCAAU,OAAM,EAAE,CAAC;AAChC;AAAA,IACF;AAEA,UAAM,aAAa;AAAA,MACjB,KAAI,qCAAU,OAAM;AAAA,MACpB;AAAA,MACA,aAAa,qCAAU,eACrB,CAAC;AAAA,IAAA;AAGO,gBAAA,CAAC,UAAU,CAAC;AAAA,EAAA,GACvB;AAAA,IACD;AAAA,IACA,qCAAU;AAAA,IACV,qCAAU;AAAA,IACV,qCAAU;AAAA,IACV;AAAA,IACA;AAAA,EAAA,CACD;AAGC,SAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAG;AAAA,MACJ;AAAA,MACA,gBAAgB;AAAA,MAChB,UACE,OAAO,iBAAiB,aAAa,cACjC,iBAAiB,WACjB,WAAW;AAAA,MAGhB;AAAA,IAAA;AAAA,EAAA;AAGP;"}
|
|
@@ -365,18 +365,18 @@ function storageAvailable(type) {
|
|
|
365
365
|
storage.removeItem(x);
|
|
366
366
|
return true;
|
|
367
367
|
} catch (e) {
|
|
368
|
-
return e instanceof DOMException && // everything except Firefox
|
|
368
|
+
return !!(e instanceof DOMException && // everything except Firefox
|
|
369
369
|
(e.code === 22 || // Firefox
|
|
370
370
|
e.code === 1014 || // test name field too, because code might not be present
|
|
371
371
|
// everything except Firefox
|
|
372
372
|
e.name === "QuotaExceededError" || // Firefox
|
|
373
373
|
e.name === "NS_ERROR_DOM_QUOTA_REACHED") && // acknowledge QuotaExceededError only if there's something already stored
|
|
374
|
-
storage && storage.length !== 0;
|
|
374
|
+
storage && storage.length !== 0);
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
function countryCodeNotUpdated(context, event) {
|
|
378
378
|
var _a, _b;
|
|
379
|
-
return event.payload.buyerIdentity.countryCode && ((_b = (_a = context.cart) == null ? void 0 : _a.buyerIdentity) == null ? void 0 : _b.countryCode) !== event.payload.buyerIdentity.countryCode;
|
|
379
|
+
return !!(event.payload.buyerIdentity.countryCode && ((_b = (_a = context.cart) == null ? void 0 : _a.buyerIdentity) == null ? void 0 : _b.countryCode) !== event.payload.buyerIdentity.countryCode);
|
|
380
380
|
}
|
|
381
381
|
export {
|
|
382
382
|
CartContext,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CartProvider.mjs","sources":["../../src/CartProvider.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useTransition,\n createContext,\n useContext,\n} from 'react';\nimport {\n AttributeInput,\n CartBuyerIdentityInput,\n CartInput,\n CartLineInput,\n CartLineUpdateInput,\n CountryCode,\n Cart as CartType,\n MutationCartNoteUpdateArgs,\n} from './storefront-api-types.js';\nimport {\n BuyerIdentityUpdateEvent,\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState,\n CartWithActions,\n} from './cart-types.js';\nimport {useCartAPIStateMachine} from './useCartAPIStateMachine.js';\nimport {CART_ID_STORAGE_KEY} from './cart-constants.js';\nimport {PartialDeep} from 'type-fest';\nimport {defaultCartFragment} from './cart-queries.js';\n\nexport const CartContext = createContext<CartWithActions | null>(null);\n\n/**\n * The `useCart` hook provides access to the cart object. It must be a descendent of a `CartProvider` component.\n */\nexport function useCart(): CartWithActions {\n const context = useContext(CartContext);\n\n if (!context) {\n throw new Error('Expected a Cart Context, but no Cart Context was found');\n }\n\n return context;\n}\n\ntype CartProviderProps = {\n /** Any `ReactNode` elements. */\n children: React.ReactNode;\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A callback that is invoked when the process to create a cart begins, but before the cart is created in the Storefront API. */\n onCreate?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart begins, but before the line item is added to the Storefront API. */\n onLineAdd?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart begins, but before the line item is removed from the Storefront API. */\n onLineRemove?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart begins, but before the line item is updated in the Storefront API. */\n onLineUpdate?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart begins, but before the note is added or updated in the Storefront API. */\n onNoteUpdate?: () => void;\n /** A callback that is invoked when the process to update the buyer identity begins, but before the buyer identity is updated in the Storefront API. */\n onBuyerIdentityUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart attributes begins, but before the attributes are updated in the Storefront API. */\n onAttributesUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes begins, but before the discount codes are updated in the Storefront API. */\n onDiscountCodesUpdate?: () => void;\n /** A callback that is invoked when the process to create a cart completes */\n onCreateComplete?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart completes */\n onLineAddComplete?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart completes */\n onLineRemoveComplete?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart completes */\n onLineUpdateComplete?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart completes */\n onNoteUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the buyer identity completes */\n onBuyerIdentityUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart attributes completes */\n onAttributesUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes completes */\n onDiscountCodesUpdateComplete?: () => void;\n /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart). */\n data?: PartialDeep<CartType, {recurseIntoArrays: true}>;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment?: string;\n /** A customer access token that's accessible on the server if there's a customer login. */\n customerAccessToken?: CartBuyerIdentityInput['customerAccessToken'];\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n};\n\n/**\n * The `CartProvider` component synchronizes the state of the Storefront API Cart and a customer's cart,\n * and allows you to more easily manipulate the cart by adding, removing, and updating it.\n * It could be placed at the root of your app so that your whole app is able to use the `useCart()` hook anywhere.\n *\n * There are props that trigger when a call to the Storefront API is made, such as `onLineAdd={}` when a line is added to the cart.\n * There are also props that trigger when a call to the Storefront API is completed, such as `onLineAddComplete={}` when the fetch request for adding a line to the cart completes.\n */\nexport function CartProvider({\n children,\n numCartLines,\n onCreate,\n onLineAdd,\n onLineRemove,\n onLineUpdate,\n onNoteUpdate,\n onBuyerIdentityUpdate,\n onAttributesUpdate,\n onDiscountCodesUpdate,\n onCreateComplete,\n onLineAddComplete,\n onLineRemoveComplete,\n onLineUpdateComplete,\n onNoteUpdateComplete,\n onBuyerIdentityUpdateComplete,\n onAttributesUpdateComplete,\n onDiscountCodesUpdateComplete,\n data: cart,\n cartFragment = defaultCartFragment,\n customerAccessToken,\n countryCode = 'US',\n}: CartProviderProps) {\n if (countryCode) countryCode = countryCode.toUpperCase() as CountryCode;\n const [prevCountryCode, setPrevCountryCode] = useState(countryCode);\n const [prevCustomerAccessToken, setPrevCustomerAccessToken] =\n useState(customerAccessToken);\n const customerOverridesCountryCode = useRef(false);\n\n if (\n prevCountryCode !== countryCode ||\n prevCustomerAccessToken !== customerAccessToken\n ) {\n setPrevCountryCode(countryCode);\n setPrevCustomerAccessToken(customerAccessToken);\n customerOverridesCountryCode.current = false;\n }\n\n const [cartState, cartSend] = useCartAPIStateMachine({\n numCartLines,\n data: cart,\n cartFragment,\n countryCode,\n onCartActionEntry(_, event) {\n try {\n switch (event.type) {\n case 'CART_CREATE':\n return onCreate?.();\n case 'CARTLINE_ADD':\n return onLineAdd?.();\n case 'CARTLINE_REMOVE':\n return onLineRemove?.();\n case 'CARTLINE_UPDATE':\n return onLineUpdate?.();\n case 'NOTE_UPDATE':\n return onNoteUpdate?.();\n case 'BUYER_IDENTITY_UPDATE':\n return onBuyerIdentityUpdate?.();\n case 'CART_ATTRIBUTES_UPDATE':\n return onAttributesUpdate?.();\n case 'DISCOUNT_CODES_UPDATE':\n return onDiscountCodesUpdate?.();\n }\n } catch (error) {\n console.error('Cart entry action failed', error);\n }\n },\n onCartActionOptimisticUI(context, event) {\n if (!context.cart) return {...context};\n switch (event.type) {\n case 'CARTLINE_REMOVE':\n return {\n ...context,\n cart: {\n ...context.cart,\n lines: context?.cart?.lines?.filter(\n (line) => line?.id && !event.payload.lines.includes(line?.id)\n ),\n },\n };\n case 'CARTLINE_UPDATE':\n return {\n ...context,\n cart: {\n ...context.cart,\n lines: context?.cart?.lines?.map((line) => {\n const updatedLine = event.payload.lines.find(\n ({id}) => id === line?.id\n );\n\n if (updatedLine && updatedLine.quantity) {\n return {\n ...line,\n quantity: updatedLine.quantity,\n };\n }\n\n return line;\n }),\n },\n };\n }\n return {...context};\n },\n onCartActionComplete(context, event) {\n const cartActionEvent = event.payload.cartActionEvent;\n try {\n switch (event.type) {\n case 'RESOLVE':\n switch (cartActionEvent.type) {\n case 'CART_CREATE':\n return onCreateComplete?.();\n case 'CARTLINE_ADD':\n return onLineAddComplete?.();\n case 'CARTLINE_REMOVE':\n return onLineRemoveComplete?.();\n case 'CARTLINE_UPDATE':\n return onLineUpdateComplete?.();\n case 'NOTE_UPDATE':\n return onNoteUpdateComplete?.();\n case 'BUYER_IDENTITY_UPDATE':\n if (countryCodeNotUpdated(context, cartActionEvent)) {\n customerOverridesCountryCode.current = true;\n }\n return onBuyerIdentityUpdateComplete?.();\n case 'CART_ATTRIBUTES_UPDATE':\n return onAttributesUpdateComplete?.();\n case 'DISCOUNT_CODES_UPDATE':\n return onDiscountCodesUpdateComplete?.();\n }\n }\n } catch (error) {\n console.error('onCartActionComplete failed', error);\n }\n },\n });\n\n const cartReady = useRef(false);\n const cartCompleted = cartState.matches('cartCompleted');\n\n const countryChanged =\n (cartState.value === 'idle' ||\n cartState.value === 'error' ||\n cartState.value === 'cartCompleted') &&\n countryCode !== cartState?.context?.cart?.buyerIdentity?.countryCode &&\n !cartState.context.errors;\n\n const fetchingFromStorage = useRef(false);\n\n /**\n * Initializes cart with priority in this order:\n * 1. cart props\n * 2. localStorage cartId\n */\n useEffect(() => {\n if (!cartReady.current && !fetchingFromStorage.current) {\n if (!cart && storageAvailable('localStorage')) {\n fetchingFromStorage.current = true;\n try {\n const cartId = window.localStorage.getItem(CART_ID_STORAGE_KEY);\n if (cartId) {\n cartSend({type: 'CART_FETCH', payload: {cartId}});\n }\n } catch (error) {\n console.warn('error fetching cartId');\n console.warn(error);\n }\n }\n cartReady.current = true;\n }\n }, [cart, cartReady, cartSend]);\n\n // Update cart country code if cart and props countryCode's as different\n useEffect(() => {\n if (!countryChanged || customerOverridesCountryCode.current) return;\n cartSend({\n type: 'BUYER_IDENTITY_UPDATE',\n payload: {buyerIdentity: {countryCode, customerAccessToken}},\n });\n }, [\n countryCode,\n customerAccessToken,\n countryChanged,\n customerOverridesCountryCode,\n cartSend,\n ]);\n\n // send cart events when ready\n const onCartReadySend = useCallback(\n (cartEvent: CartMachineEvent) => {\n if (!cartReady.current) {\n return console.warn(\"Cart isn't ready yet\");\n }\n cartSend(cartEvent);\n },\n [cartSend]\n );\n\n // save cart id to local storage\n useEffect(() => {\n if (cartState?.context?.cart?.id && storageAvailable('localStorage')) {\n try {\n window.localStorage.setItem(\n CART_ID_STORAGE_KEY,\n cartState.context.cart?.id\n );\n } catch (error) {\n console.warn('Failed to save cartId to localStorage', error);\n }\n }\n }, [cartState?.context?.cart?.id]);\n\n // delete cart from local storage if cart fetched has been completed\n useEffect(() => {\n if (cartCompleted && storageAvailable('localStorage')) {\n try {\n window.localStorage.removeItem(CART_ID_STORAGE_KEY);\n } catch (error) {\n console.warn('Failed to delete cartId from localStorage', error);\n }\n }\n }, [cartCompleted]);\n\n const cartCreate = useCallback(\n (cartInput: CartInput) => {\n if (countryCode && !cartInput.buyerIdentity?.countryCode) {\n if (cartInput.buyerIdentity == null) {\n cartInput.buyerIdentity = {};\n }\n cartInput.buyerIdentity.countryCode = countryCode;\n }\n\n if (\n customerAccessToken &&\n !cartInput.buyerIdentity?.customerAccessToken\n ) {\n if (cartInput.buyerIdentity == null) {\n cartInput.buyerIdentity = {};\n }\n cartInput.buyerIdentity.customerAccessToken = customerAccessToken;\n }\n onCartReadySend({\n type: 'CART_CREATE',\n payload: cartInput,\n });\n },\n [countryCode, customerAccessToken, onCartReadySend]\n );\n\n // Delays the cart state in the context if the page is hydrating\n // preventing suspense boundary errors.\n const cartDisplayState = useDelayedStateUntilHydration(cartState);\n\n const cartContextValue = useMemo<CartWithActions>(() => {\n return {\n ...(cartDisplayState?.context?.cart ?? {lines: [], attributes: []}),\n status: transposeStatus(cartDisplayState.value),\n error: cartDisplayState?.context?.errors,\n totalQuantity: cartDisplayState?.context?.cart?.totalQuantity ?? 0,\n cartCreate,\n linesAdd(lines: CartLineInput[]) {\n if (cartDisplayState?.context?.cart?.id) {\n onCartReadySend({\n type: 'CARTLINE_ADD',\n payload: {lines},\n });\n } else {\n cartCreate({lines});\n }\n },\n linesRemove(lines: string[]) {\n onCartReadySend({\n type: 'CARTLINE_REMOVE',\n payload: {\n lines,\n },\n });\n },\n linesUpdate(lines: CartLineUpdateInput[]) {\n onCartReadySend({\n type: 'CARTLINE_UPDATE',\n payload: {\n lines,\n },\n });\n },\n noteUpdate(note: MutationCartNoteUpdateArgs['note']) {\n onCartReadySend({\n type: 'NOTE_UPDATE',\n payload: {\n note,\n },\n });\n },\n buyerIdentityUpdate(buyerIdentity: CartBuyerIdentityInput) {\n onCartReadySend({\n type: 'BUYER_IDENTITY_UPDATE',\n payload: {\n buyerIdentity,\n },\n });\n },\n cartAttributesUpdate(attributes: AttributeInput[]) {\n onCartReadySend({\n type: 'CART_ATTRIBUTES_UPDATE',\n payload: {\n attributes,\n },\n });\n },\n discountCodesUpdate(discountCodes: string[]) {\n onCartReadySend({\n type: 'DISCOUNT_CODES_UPDATE',\n payload: {\n discountCodes,\n },\n });\n },\n cartFragment,\n };\n }, [\n cartCreate,\n cartDisplayState?.context?.cart,\n cartDisplayState?.context?.errors,\n cartDisplayState.value,\n cartFragment,\n onCartReadySend,\n ]);\n\n return (\n <CartContext.Provider value={cartContextValue}>\n {children}\n </CartContext.Provider>\n );\n}\n\nfunction transposeStatus(\n status: CartMachineTypeState['value']\n): CartWithActions['status'] {\n switch (status) {\n case 'uninitialized':\n case 'initializationError':\n return 'uninitialized';\n case 'idle':\n case 'cartCompleted':\n case 'error':\n return 'idle';\n case 'cartFetching':\n return 'fetching';\n case 'cartCreating':\n return 'creating';\n case 'cartLineAdding':\n case 'cartLineRemoving':\n case 'cartLineUpdating':\n case 'noteUpdating':\n case 'buyerIdentityUpdating':\n case 'cartAttributesUpdating':\n case 'discountCodesUpdating':\n return 'updating';\n }\n}\n\n/**\n * Delays a state update until hydration finishes. Useful for preventing suspense boundaries errors when updating a context\n * @remarks this uses startTransition and waits for it to finish.\n */\nfunction useDelayedStateUntilHydration<T>(state: T) {\n const [isPending, startTransition] = useTransition();\n const [delayedState, setDelayedState] = useState(state);\n\n const firstTimePending = useRef(false);\n if (isPending) {\n firstTimePending.current = true;\n }\n\n const firstTimePendingFinished = useRef(false);\n if (!isPending && firstTimePending.current) {\n firstTimePendingFinished.current = true;\n }\n\n useEffect(() => {\n startTransition(() => {\n if (!firstTimePendingFinished.current) {\n setDelayedState(state);\n }\n });\n }, [state]);\n\n const displayState = firstTimePendingFinished.current ? state : delayedState;\n\n return displayState;\n}\n\n/** Check for storage availability funciton obtained from\n * https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API\n */\nexport function storageAvailable(type: 'localStorage' | 'sessionStorage') {\n let storage;\n try {\n storage = window[type];\n const x = '__storage_test__';\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n } catch (e) {\n return (\n e instanceof DOMException &&\n // everything except Firefox\n (e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === 'QuotaExceededError' ||\n // Firefox\n e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage &&\n storage.length !== 0\n );\n }\n}\n\nfunction countryCodeNotUpdated(\n context: CartMachineContext,\n event: BuyerIdentityUpdateEvent\n) {\n return (\n event.payload.buyerIdentity.countryCode &&\n context.cart?.buyerIdentity?.countryCode !==\n event.payload.buyerIdentity.countryCode\n );\n}\n"],"names":["_b","_a","_d","_c"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CartProvider.mjs","sources":["../../src/CartProvider.tsx"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useTransition,\n createContext,\n useContext,\n} from 'react';\nimport {\n AttributeInput,\n CartBuyerIdentityInput,\n CartInput,\n CartLineInput,\n CartLineUpdateInput,\n CountryCode,\n Cart as CartType,\n MutationCartNoteUpdateArgs,\n} from './storefront-api-types.js';\nimport {\n BuyerIdentityUpdateEvent,\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState,\n CartWithActions,\n} from './cart-types.js';\nimport {useCartAPIStateMachine} from './useCartAPIStateMachine.js';\nimport {CART_ID_STORAGE_KEY} from './cart-constants.js';\nimport {PartialDeep} from 'type-fest';\nimport {defaultCartFragment} from './cart-queries.js';\n\nexport const CartContext = createContext<CartWithActions | null>(null);\n\n/**\n * The `useCart` hook provides access to the cart object. It must be a descendent of a `CartProvider` component.\n */\nexport function useCart(): CartWithActions {\n const context = useContext(CartContext);\n\n if (!context) {\n throw new Error('Expected a Cart Context, but no Cart Context was found');\n }\n\n return context;\n}\n\ntype CartProviderProps = {\n /** Any `ReactNode` elements. */\n children: React.ReactNode;\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A callback that is invoked when the process to create a cart begins, but before the cart is created in the Storefront API. */\n onCreate?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart begins, but before the line item is added to the Storefront API. */\n onLineAdd?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart begins, but before the line item is removed from the Storefront API. */\n onLineRemove?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart begins, but before the line item is updated in the Storefront API. */\n onLineUpdate?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart begins, but before the note is added or updated in the Storefront API. */\n onNoteUpdate?: () => void;\n /** A callback that is invoked when the process to update the buyer identity begins, but before the buyer identity is updated in the Storefront API. */\n onBuyerIdentityUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart attributes begins, but before the attributes are updated in the Storefront API. */\n onAttributesUpdate?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes begins, but before the discount codes are updated in the Storefront API. */\n onDiscountCodesUpdate?: () => void;\n /** A callback that is invoked when the process to create a cart completes */\n onCreateComplete?: () => void;\n /** A callback that is invoked when the process to add a line item to the cart completes */\n onLineAddComplete?: () => void;\n /** A callback that is invoked when the process to remove a line item to the cart completes */\n onLineRemoveComplete?: () => void;\n /** A callback that is invoked when the process to update a line item in the cart completes */\n onLineUpdateComplete?: () => void;\n /** A callback that is invoked when the process to add or update a note in the cart completes */\n onNoteUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the buyer identity completes */\n onBuyerIdentityUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart attributes completes */\n onAttributesUpdateComplete?: () => void;\n /** A callback that is invoked when the process to update the cart discount codes completes */\n onDiscountCodesUpdateComplete?: () => void;\n /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart). */\n data?: PartialDeep<CartType, {recurseIntoArrays: true}>;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment?: string;\n /** A customer access token that's accessible on the server if there's a customer login. */\n customerAccessToken?: CartBuyerIdentityInput['customerAccessToken'];\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n};\n\n/**\n * The `CartProvider` component synchronizes the state of the Storefront API Cart and a customer's cart,\n * and allows you to more easily manipulate the cart by adding, removing, and updating it.\n * It could be placed at the root of your app so that your whole app is able to use the `useCart()` hook anywhere.\n *\n * There are props that trigger when a call to the Storefront API is made, such as `onLineAdd={}` when a line is added to the cart.\n * There are also props that trigger when a call to the Storefront API is completed, such as `onLineAddComplete={}` when the fetch request for adding a line to the cart completes.\n */\nexport function CartProvider({\n children,\n numCartLines,\n onCreate,\n onLineAdd,\n onLineRemove,\n onLineUpdate,\n onNoteUpdate,\n onBuyerIdentityUpdate,\n onAttributesUpdate,\n onDiscountCodesUpdate,\n onCreateComplete,\n onLineAddComplete,\n onLineRemoveComplete,\n onLineUpdateComplete,\n onNoteUpdateComplete,\n onBuyerIdentityUpdateComplete,\n onAttributesUpdateComplete,\n onDiscountCodesUpdateComplete,\n data: cart,\n cartFragment = defaultCartFragment,\n customerAccessToken,\n countryCode = 'US',\n}: CartProviderProps): JSX.Element {\n if (countryCode) countryCode = countryCode.toUpperCase() as CountryCode;\n const [prevCountryCode, setPrevCountryCode] = useState(countryCode);\n const [prevCustomerAccessToken, setPrevCustomerAccessToken] =\n useState(customerAccessToken);\n const customerOverridesCountryCode = useRef(false);\n\n if (\n prevCountryCode !== countryCode ||\n prevCustomerAccessToken !== customerAccessToken\n ) {\n setPrevCountryCode(countryCode);\n setPrevCustomerAccessToken(customerAccessToken);\n customerOverridesCountryCode.current = false;\n }\n\n const [cartState, cartSend] = useCartAPIStateMachine({\n numCartLines,\n data: cart,\n cartFragment,\n countryCode,\n onCartActionEntry(_, event) {\n try {\n switch (event.type) {\n case 'CART_CREATE':\n return onCreate?.();\n case 'CARTLINE_ADD':\n return onLineAdd?.();\n case 'CARTLINE_REMOVE':\n return onLineRemove?.();\n case 'CARTLINE_UPDATE':\n return onLineUpdate?.();\n case 'NOTE_UPDATE':\n return onNoteUpdate?.();\n case 'BUYER_IDENTITY_UPDATE':\n return onBuyerIdentityUpdate?.();\n case 'CART_ATTRIBUTES_UPDATE':\n return onAttributesUpdate?.();\n case 'DISCOUNT_CODES_UPDATE':\n return onDiscountCodesUpdate?.();\n }\n } catch (error) {\n console.error('Cart entry action failed', error);\n }\n },\n onCartActionOptimisticUI(context, event) {\n if (!context.cart) return {...context};\n switch (event.type) {\n case 'CARTLINE_REMOVE':\n return {\n ...context,\n cart: {\n ...context.cart,\n lines: context?.cart?.lines?.filter(\n (line) => line?.id && !event.payload.lines.includes(line?.id)\n ),\n },\n };\n case 'CARTLINE_UPDATE':\n return {\n ...context,\n cart: {\n ...context.cart,\n lines: context?.cart?.lines?.map((line) => {\n const updatedLine = event.payload.lines.find(\n ({id}) => id === line?.id\n );\n\n if (updatedLine && updatedLine.quantity) {\n return {\n ...line,\n quantity: updatedLine.quantity,\n };\n }\n\n return line;\n }),\n },\n };\n }\n return {...context};\n },\n onCartActionComplete(context, event) {\n const cartActionEvent = event.payload.cartActionEvent;\n try {\n switch (event.type) {\n case 'RESOLVE':\n switch (cartActionEvent.type) {\n case 'CART_CREATE':\n return onCreateComplete?.();\n case 'CARTLINE_ADD':\n return onLineAddComplete?.();\n case 'CARTLINE_REMOVE':\n return onLineRemoveComplete?.();\n case 'CARTLINE_UPDATE':\n return onLineUpdateComplete?.();\n case 'NOTE_UPDATE':\n return onNoteUpdateComplete?.();\n case 'BUYER_IDENTITY_UPDATE':\n if (countryCodeNotUpdated(context, cartActionEvent)) {\n customerOverridesCountryCode.current = true;\n }\n return onBuyerIdentityUpdateComplete?.();\n case 'CART_ATTRIBUTES_UPDATE':\n return onAttributesUpdateComplete?.();\n case 'DISCOUNT_CODES_UPDATE':\n return onDiscountCodesUpdateComplete?.();\n }\n }\n } catch (error) {\n console.error('onCartActionComplete failed', error);\n }\n },\n });\n\n const cartReady = useRef(false);\n const cartCompleted = cartState.matches('cartCompleted');\n\n const countryChanged =\n (cartState.value === 'idle' ||\n cartState.value === 'error' ||\n cartState.value === 'cartCompleted') &&\n countryCode !== cartState?.context?.cart?.buyerIdentity?.countryCode &&\n !cartState.context.errors;\n\n const fetchingFromStorage = useRef(false);\n\n /**\n * Initializes cart with priority in this order:\n * 1. cart props\n * 2. localStorage cartId\n */\n useEffect(() => {\n if (!cartReady.current && !fetchingFromStorage.current) {\n if (!cart && storageAvailable('localStorage')) {\n fetchingFromStorage.current = true;\n try {\n const cartId = window.localStorage.getItem(CART_ID_STORAGE_KEY);\n if (cartId) {\n cartSend({type: 'CART_FETCH', payload: {cartId}});\n }\n } catch (error) {\n console.warn('error fetching cartId');\n console.warn(error);\n }\n }\n cartReady.current = true;\n }\n }, [cart, cartReady, cartSend]);\n\n // Update cart country code if cart and props countryCode's as different\n useEffect(() => {\n if (!countryChanged || customerOverridesCountryCode.current) return;\n cartSend({\n type: 'BUYER_IDENTITY_UPDATE',\n payload: {buyerIdentity: {countryCode, customerAccessToken}},\n });\n }, [\n countryCode,\n customerAccessToken,\n countryChanged,\n customerOverridesCountryCode,\n cartSend,\n ]);\n\n // send cart events when ready\n const onCartReadySend = useCallback(\n (cartEvent: CartMachineEvent) => {\n if (!cartReady.current) {\n return console.warn(\"Cart isn't ready yet\");\n }\n cartSend(cartEvent);\n },\n [cartSend]\n );\n\n // save cart id to local storage\n useEffect(() => {\n if (cartState?.context?.cart?.id && storageAvailable('localStorage')) {\n try {\n window.localStorage.setItem(\n CART_ID_STORAGE_KEY,\n cartState.context.cart?.id\n );\n } catch (error) {\n console.warn('Failed to save cartId to localStorage', error);\n }\n }\n }, [cartState?.context?.cart?.id]);\n\n // delete cart from local storage if cart fetched has been completed\n useEffect(() => {\n if (cartCompleted && storageAvailable('localStorage')) {\n try {\n window.localStorage.removeItem(CART_ID_STORAGE_KEY);\n } catch (error) {\n console.warn('Failed to delete cartId from localStorage', error);\n }\n }\n }, [cartCompleted]);\n\n const cartCreate = useCallback(\n (cartInput: CartInput) => {\n if (countryCode && !cartInput.buyerIdentity?.countryCode) {\n if (cartInput.buyerIdentity == null) {\n cartInput.buyerIdentity = {};\n }\n cartInput.buyerIdentity.countryCode = countryCode;\n }\n\n if (\n customerAccessToken &&\n !cartInput.buyerIdentity?.customerAccessToken\n ) {\n if (cartInput.buyerIdentity == null) {\n cartInput.buyerIdentity = {};\n }\n cartInput.buyerIdentity.customerAccessToken = customerAccessToken;\n }\n onCartReadySend({\n type: 'CART_CREATE',\n payload: cartInput,\n });\n },\n [countryCode, customerAccessToken, onCartReadySend]\n );\n\n // Delays the cart state in the context if the page is hydrating\n // preventing suspense boundary errors.\n const cartDisplayState = useDelayedStateUntilHydration(cartState);\n\n const cartContextValue = useMemo<CartWithActions>(() => {\n return {\n ...(cartDisplayState?.context?.cart ?? {lines: [], attributes: []}),\n status: transposeStatus(cartDisplayState.value),\n error: cartDisplayState?.context?.errors,\n totalQuantity: cartDisplayState?.context?.cart?.totalQuantity ?? 0,\n cartCreate,\n linesAdd(lines: CartLineInput[]): void {\n if (cartDisplayState?.context?.cart?.id) {\n onCartReadySend({\n type: 'CARTLINE_ADD',\n payload: {lines},\n });\n } else {\n cartCreate({lines});\n }\n },\n linesRemove(lines: string[]): void {\n onCartReadySend({\n type: 'CARTLINE_REMOVE',\n payload: {\n lines,\n },\n });\n },\n linesUpdate(lines: CartLineUpdateInput[]): void {\n onCartReadySend({\n type: 'CARTLINE_UPDATE',\n payload: {\n lines,\n },\n });\n },\n noteUpdate(note: MutationCartNoteUpdateArgs['note']): void {\n onCartReadySend({\n type: 'NOTE_UPDATE',\n payload: {\n note,\n },\n });\n },\n buyerIdentityUpdate(buyerIdentity: CartBuyerIdentityInput): void {\n onCartReadySend({\n type: 'BUYER_IDENTITY_UPDATE',\n payload: {\n buyerIdentity,\n },\n });\n },\n cartAttributesUpdate(attributes: AttributeInput[]): void {\n onCartReadySend({\n type: 'CART_ATTRIBUTES_UPDATE',\n payload: {\n attributes,\n },\n });\n },\n discountCodesUpdate(discountCodes: string[]): void {\n onCartReadySend({\n type: 'DISCOUNT_CODES_UPDATE',\n payload: {\n discountCodes,\n },\n });\n },\n cartFragment,\n };\n }, [\n cartCreate,\n cartDisplayState?.context?.cart,\n cartDisplayState?.context?.errors,\n cartDisplayState.value,\n cartFragment,\n onCartReadySend,\n ]);\n\n return (\n <CartContext.Provider value={cartContextValue}>\n {children}\n </CartContext.Provider>\n );\n}\n\nfunction transposeStatus(\n status: CartMachineTypeState['value']\n): CartWithActions['status'] {\n switch (status) {\n case 'uninitialized':\n case 'initializationError':\n return 'uninitialized';\n case 'idle':\n case 'cartCompleted':\n case 'error':\n return 'idle';\n case 'cartFetching':\n return 'fetching';\n case 'cartCreating':\n return 'creating';\n case 'cartLineAdding':\n case 'cartLineRemoving':\n case 'cartLineUpdating':\n case 'noteUpdating':\n case 'buyerIdentityUpdating':\n case 'cartAttributesUpdating':\n case 'discountCodesUpdating':\n return 'updating';\n }\n}\n\n/**\n * Delays a state update until hydration finishes. Useful for preventing suspense boundaries errors when updating a context\n * @remarks this uses startTransition and waits for it to finish.\n */\nfunction useDelayedStateUntilHydration<T>(state: T): T {\n const [isPending, startTransition] = useTransition();\n const [delayedState, setDelayedState] = useState(state);\n\n const firstTimePending = useRef(false);\n if (isPending) {\n firstTimePending.current = true;\n }\n\n const firstTimePendingFinished = useRef(false);\n if (!isPending && firstTimePending.current) {\n firstTimePendingFinished.current = true;\n }\n\n useEffect(() => {\n startTransition(() => {\n if (!firstTimePendingFinished.current) {\n setDelayedState(state);\n }\n });\n }, [state]);\n\n const displayState = firstTimePendingFinished.current ? state : delayedState;\n\n return displayState;\n}\n\n/** Check for storage availability funciton obtained from\n * https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API\n */\nexport function storageAvailable(\n type: 'localStorage' | 'sessionStorage'\n): boolean {\n let storage;\n try {\n storage = window[type];\n const x = '__storage_test__';\n storage.setItem(x, x);\n storage.removeItem(x);\n return true;\n } catch (e) {\n return !!(\n e instanceof DOMException &&\n // everything except Firefox\n (e.code === 22 ||\n // Firefox\n e.code === 1014 ||\n // test name field too, because code might not be present\n // everything except Firefox\n e.name === 'QuotaExceededError' ||\n // Firefox\n e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&\n // acknowledge QuotaExceededError only if there's something already stored\n storage &&\n storage.length !== 0\n );\n }\n}\n\nfunction countryCodeNotUpdated(\n context: CartMachineContext,\n event: BuyerIdentityUpdateEvent\n): boolean {\n return !!(\n event.payload.buyerIdentity.countryCode &&\n context.cart?.buyerIdentity?.countryCode !==\n event.payload.buyerIdentity.countryCode\n );\n}\n"],"names":["_b","_a","_d","_c"],"mappings":"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"}
|