@shopify/hydrogen 0.17.3 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/CHANGELOG.md +259 -0
  2. package/config.d.ts +1 -0
  3. package/config.js +1 -0
  4. package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +2 -2
  5. package/dist/esnext/components/CartLineImage/CartLineImage.client.d.ts +4 -7
  6. package/dist/esnext/components/CartLineImage/CartLineImage.client.js +1 -2
  7. package/dist/esnext/components/CartProvider/CartProvider.client.d.ts +3 -1
  8. package/dist/esnext/components/CartProvider/CartProvider.client.js +37 -34
  9. package/dist/esnext/components/CartProvider/cart-queries.d.ts +10 -9
  10. package/dist/esnext/components/CartProvider/cart-queries.js +58 -743
  11. package/dist/esnext/components/CartProvider/{hooks.d.ts → hooks.client.d.ts} +0 -0
  12. package/dist/esnext/components/CartProvider/{hooks.js → hooks.client.js} +4 -2
  13. package/dist/esnext/components/CartProvider/index.d.ts +1 -1
  14. package/dist/esnext/components/CartProvider/index.js +1 -1
  15. package/dist/esnext/components/CartProvider/types.d.ts +2 -0
  16. package/dist/esnext/components/{DevTools.d.ts → DevTools.client.d.ts} +0 -0
  17. package/dist/esnext/components/{DevTools.js → DevTools.client.js} +3 -2
  18. package/dist/esnext/components/Image/Image.d.ts +78 -34
  19. package/dist/esnext/components/Image/Image.js +56 -51
  20. package/dist/esnext/components/Image/index.d.ts +1 -0
  21. package/dist/esnext/components/Link/Link.client.js +11 -2
  22. package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +2 -15
  23. package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -1
  24. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +2 -6
  25. package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +11 -5
  26. package/dist/esnext/components/MediaFile/MediaFile.d.ts +2 -2
  27. package/dist/esnext/components/MediaFile/MediaFile.js +2 -2
  28. package/dist/esnext/components/Metafield/Metafield.client.js +4 -5
  29. package/dist/esnext/components/ModelViewer/ModelViewer.client.js +1 -1
  30. package/dist/esnext/components/Money/Money.client.d.ts +5 -1
  31. package/dist/esnext/components/Money/Money.client.js +16 -3
  32. package/dist/esnext/components/ProductMetafield/ProductMetafield.client.js +1 -1
  33. package/dist/esnext/components/ProductProvider/ProductOptionsProvider.client.js +1 -1
  34. package/dist/esnext/components/ProductProvider/ProductProvider.client.d.ts +7 -3
  35. package/dist/esnext/components/ShopPayButton/ShopPayButton.client.js +6 -2
  36. package/dist/esnext/components/Video/Video.d.ts +3 -3
  37. package/dist/esnext/components/Video/Video.js +10 -5
  38. package/dist/esnext/config.d.ts +3 -0
  39. package/dist/esnext/config.js +1 -0
  40. package/dist/esnext/constants.js +1 -1
  41. package/dist/esnext/entry-client.js +3 -1
  42. package/dist/esnext/entry-server.d.ts +14 -2
  43. package/dist/esnext/entry-server.js +56 -82
  44. package/dist/esnext/foundation/Cookie/Cookie.js +2 -1
  45. package/dist/esnext/foundation/FileRoutes/FileRoutes.server.d.ts +4 -4
  46. package/dist/esnext/foundation/FileRoutes/FileRoutes.server.js +17 -4
  47. package/dist/esnext/foundation/FileSessionStorage/FileSessionStorage.js +2 -1
  48. package/dist/esnext/foundation/Redirect/Redirect.client.js +1 -0
  49. package/dist/esnext/foundation/Router/BrowserRouter.client.js +10 -1
  50. package/dist/esnext/foundation/ServerPropsProvider/ServerPropsProvider.js +5 -3
  51. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +2 -2
  52. package/dist/esnext/foundation/ServerRequestProvider/ServerRequestProvider.js +7 -2
  53. package/dist/esnext/foundation/ServerStateProvider/ServerStateProvider.js +8 -1
  54. package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.d.ts +8 -1
  55. package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +31 -5
  56. package/dist/esnext/foundation/ShopifyProvider/types.d.ts +3 -4
  57. package/dist/esnext/foundation/fetchSync/client/fetchSync.js +2 -1
  58. package/dist/esnext/foundation/fetchSync/server/fetchSync.d.ts +1 -1
  59. package/dist/esnext/foundation/fetchSync/server/fetchSync.js +5 -3
  60. package/dist/esnext/foundation/ssr-interop.js +1 -1
  61. package/dist/esnext/foundation/useQuery/hooks.d.ts +1 -1
  62. package/dist/esnext/foundation/useQuery/hooks.js +2 -2
  63. package/dist/esnext/foundation/useSession/useSession.d.ts +1 -1
  64. package/dist/esnext/foundation/useSession/useSession.js +1 -1
  65. package/dist/esnext/foundation/useShop/use-shop.d.ts +3 -1
  66. package/dist/esnext/foundation/useShop/use-shop.js +3 -1
  67. package/dist/esnext/foundation/useUrl/useUrl.js +7 -4
  68. package/dist/esnext/framework/Hydration/Html.js +4 -2
  69. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.d.ts +3 -2
  70. package/dist/esnext/framework/Hydration/ServerComponentRequest.server.js +16 -7
  71. package/dist/esnext/framework/Hydration/rsc.d.ts +0 -3
  72. package/dist/esnext/framework/Hydration/rsc.js +0 -20
  73. package/dist/esnext/framework/middleware.d.ts +3 -4
  74. package/dist/esnext/framework/middleware.js +4 -4
  75. package/dist/esnext/framework/plugin.d.ts +2 -2
  76. package/dist/esnext/framework/plugin.js +5 -32
  77. package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.d.ts +1 -1
  78. package/dist/esnext/framework/plugins/vite-plugin-css-modules-rsc.js +68 -3
  79. package/dist/esnext/framework/plugins/vite-plugin-hydration-auto-import.js +1 -4
  80. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +6 -5
  81. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +3 -3
  82. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +61 -7
  83. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +1 -0
  84. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-rsc.js +35 -0
  85. package/dist/esnext/framework/plugins/vite-plugin-platform-entry.js +1 -1
  86. package/dist/esnext/framework/plugins/vite-plugin-ssr-interop.js +6 -3
  87. package/dist/esnext/hooks/useCountry/useCountry.d.ts +1 -11
  88. package/dist/esnext/hooks/useCountry/useCountry.js +1 -1
  89. package/dist/esnext/hooks/useLoadScript/index.d.ts +1 -1
  90. package/dist/esnext/hooks/useLoadScript/index.js +1 -1
  91. package/dist/esnext/hooks/useLoadScript/{useLoadScript.d.ts → useLoadScript.client.d.ts} +0 -0
  92. package/dist/esnext/hooks/useLoadScript/{useLoadScript.js → useLoadScript.client.js} +2 -1
  93. package/dist/esnext/hooks/useMoney/hooks.d.ts +13 -1
  94. package/dist/esnext/hooks/useMoney/hooks.js +25 -1
  95. package/dist/esnext/hooks/useProduct/useProduct.js +1 -1
  96. package/dist/esnext/hooks/useProductOptions/index.d.ts +1 -1
  97. package/dist/esnext/hooks/useProductOptions/index.js +1 -1
  98. package/dist/esnext/hooks/useProductOptions/{useProductOptions.d.ts → useProductOptions.client.d.ts} +0 -0
  99. package/dist/esnext/hooks/useProductOptions/{useProductOptions.js → useProductOptions.client.js} +6 -23
  100. package/dist/esnext/hooks/useShopQuery/hooks.js +15 -4
  101. package/dist/esnext/node.d.ts +1 -0
  102. package/dist/esnext/node.js +1 -0
  103. package/dist/esnext/storefront-api-types.d.ts +65 -9
  104. package/dist/esnext/storefront-api-types.js +11 -5
  105. package/dist/esnext/types.d.ts +11 -4
  106. package/dist/esnext/utilities/apiRoutes.d.ts +4 -4
  107. package/dist/esnext/utilities/apiRoutes.js +29 -16
  108. package/dist/esnext/utilities/bot-ua.js +4 -0
  109. package/dist/esnext/utilities/empty-hydrogen-config.d.ts +2 -0
  110. package/dist/esnext/utilities/empty-hydrogen-config.js +2 -0
  111. package/dist/esnext/utilities/findRoutePrefix.d.ts +1 -0
  112. package/dist/esnext/utilities/findRoutePrefix.js +17 -0
  113. package/dist/esnext/utilities/image_size.d.ts +4 -22
  114. package/dist/esnext/utilities/image_size.js +15 -33
  115. package/dist/esnext/utilities/index.d.ts +1 -1
  116. package/dist/esnext/utilities/index.js +1 -1
  117. package/dist/esnext/utilities/log/utils.js +1 -1
  118. package/dist/esnext/utilities/parse.d.ts +1 -0
  119. package/dist/esnext/utilities/parse.js +9 -0
  120. package/dist/esnext/utilities/parseMetafieldValue/parseMetafieldValue.js +2 -1
  121. package/dist/esnext/utilities/storefrontApi.js +1 -0
  122. package/dist/esnext/version.d.ts +1 -1
  123. package/dist/esnext/version.js +1 -1
  124. package/dist/node/components/Image/Image.d.ts +84 -0
  125. package/dist/node/components/Image/Image.js +86 -0
  126. package/dist/node/components/Image/index.d.ts +2 -0
  127. package/dist/node/components/Image/index.js +5 -0
  128. package/dist/node/constants.js +1 -1
  129. package/dist/node/entry-server.d.ts +14 -2
  130. package/dist/node/entry-server.js +56 -82
  131. package/dist/node/foundation/Redirect/Redirect.client.js +1 -0
  132. package/dist/node/foundation/Router/BrowserRouter.client.js +10 -1
  133. package/dist/node/foundation/ServerPropsProvider/ServerPropsProvider.js +5 -3
  134. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +2 -2
  135. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +7 -2
  136. package/dist/node/foundation/ShopifyProvider/types.d.ts +3 -4
  137. package/dist/node/foundation/ssr-interop.js +1 -1
  138. package/dist/node/framework/Hydration/Html.js +4 -2
  139. package/dist/node/framework/Hydration/ServerComponentRequest.server.d.ts +3 -2
  140. package/dist/node/framework/Hydration/ServerComponentRequest.server.js +16 -7
  141. package/dist/node/framework/Hydration/rsc.d.ts +0 -3
  142. package/dist/node/framework/Hydration/rsc.js +0 -20
  143. package/dist/node/framework/middleware.d.ts +3 -4
  144. package/dist/node/framework/middleware.js +4 -4
  145. package/dist/node/framework/plugin.d.ts +2 -2
  146. package/dist/node/framework/plugin.js +5 -55
  147. package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.d.ts +1 -1
  148. package/dist/node/framework/plugins/vite-plugin-css-modules-rsc.js +71 -3
  149. package/dist/node/framework/plugins/vite-plugin-hydration-auto-import.js +1 -4
  150. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +6 -5
  151. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.d.ts +3 -3
  152. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +60 -6
  153. package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.d.ts +1 -0
  154. package/dist/node/framework/plugins/vite-plugin-hydrogen-rsc.js +41 -0
  155. package/dist/node/framework/plugins/vite-plugin-platform-entry.js +1 -1
  156. package/dist/node/framework/plugins/vite-plugin-ssr-interop.js +6 -3
  157. package/dist/node/storefront-api-types.d.ts +65 -9
  158. package/dist/node/storefront-api-types.js +11 -5
  159. package/dist/node/types.d.ts +11 -4
  160. package/dist/node/utilities/apiRoutes.d.ts +4 -4
  161. package/dist/node/utilities/apiRoutes.js +29 -16
  162. package/dist/node/utilities/bot-ua.js +4 -0
  163. package/dist/node/utilities/findRoutePrefix.d.ts +1 -0
  164. package/dist/node/utilities/findRoutePrefix.js +21 -0
  165. package/dist/node/utilities/image_size.d.ts +4 -22
  166. package/dist/node/utilities/image_size.js +16 -58
  167. package/dist/node/utilities/index.d.ts +1 -1
  168. package/dist/node/utilities/index.js +1 -2
  169. package/dist/node/utilities/log/utils.js +1 -1
  170. package/dist/node/utilities/parse.d.ts +1 -0
  171. package/dist/node/utilities/parse.js +13 -0
  172. package/dist/node/utilities/parseMetafieldValue/parseMetafieldValue.js +2 -1
  173. package/dist/node/utilities/storefrontApi.js +1 -0
  174. package/dist/node/version.d.ts +1 -1
  175. package/dist/node/version.js +1 -1
  176. package/entry-server.d.ts +1 -1
  177. package/package.json +8 -6
  178. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +173 -29
  179. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-client-proxy.js +2 -0
  180. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +173 -29
@@ -2,6 +2,7 @@ import React, { useState } from 'react';
2
2
  import { useShop } from '../../foundation';
3
3
  import { flattenConnection } from '../../utilities';
4
4
  import { CartCreate } from './cart-queries';
5
+ import { useCart } from '../../hooks/useCart';
5
6
  export function useCartFetch() {
6
7
  const { storeDomain, storefrontApiVersion, storefrontToken } = useShop();
7
8
  return React.useCallback(({ query, variables, }) => {
@@ -28,6 +29,7 @@ export function useCartFetch() {
28
29
  }, [storeDomain, storefrontApiVersion, storefrontToken]);
29
30
  }
30
31
  export function useInstantCheckout() {
32
+ const { cartFragment } = useCart();
31
33
  const [cart, updateCart] = useState();
32
34
  const [checkoutUrl, updateCheckoutUrl] = useState();
33
35
  const [error, updateError] = useState();
@@ -35,7 +37,7 @@ export function useInstantCheckout() {
35
37
  const createInstantCheckout = React.useCallback(async (cartInput) => {
36
38
  var _a, _b;
37
39
  const { data, error } = await fetch({
38
- query: CartCreate,
40
+ query: CartCreate(cartFragment),
39
41
  variables: {
40
42
  input: cartInput,
41
43
  },
@@ -55,6 +57,6 @@ export function useInstantCheckout() {
55
57
  });
56
58
  updateCheckoutUrl(dataCart.checkoutUrl);
57
59
  }
58
- }, [fetch]);
60
+ }, [cartFragment, fetch]);
59
61
  return { cart, checkoutUrl, error, createInstantCheckout };
60
62
  }
@@ -1,4 +1,4 @@
1
1
  export { CartProvider } from './CartProvider.client';
2
- export { useCartFetch, useInstantCheckout } from './hooks';
2
+ export { useCartFetch, useInstantCheckout } from './hooks.client';
3
3
  export { useCart } from '../../hooks/useCart';
4
4
  export type { State, Status, Cart, CartWithActions, CartAction } from './types';
@@ -1,3 +1,3 @@
1
1
  export { CartProvider } from './CartProvider.client';
2
- export { useCartFetch, useInstantCheckout } from './hooks';
2
+ export { useCartFetch, useInstantCheckout } from './hooks.client';
3
3
  export { useCart } from '../../hooks/useCart';
@@ -42,6 +42,8 @@ export interface CartWithActions extends Cart {
42
42
  discountCodesUpdate: (discountCodes: string[]) => void;
43
43
  /** The total number of items in the cart, across all lines. If there are no lines, then the value is 0. */
44
44
  totalQuantity: number;
45
+ /** The fragment used to query the cart object for all queries and mutations. */
46
+ cartFragment: string;
45
47
  }
46
48
  export declare type State =
47
49
  /** A cart has not been created yet, or an error occurred when a cart was attempting to be created or fetched. */
@@ -19,9 +19,9 @@ export default function DevTools() {
19
19
  const entry = perfData[0];
20
20
  let activePanelContent = null;
21
21
  switch (activePanel) {
22
- case 'warnings':
22
+ case 'warnings': {
23
23
  const warningsMarkup = warnings
24
- ? warnings.map((war, i) => React.createElement("li", { key: war + i }, war))
24
+ ? warnings.map((war, i) => React.createElement("li", { key: war + i }, war)) // eslint-disable-line react/no-array-index-key
25
25
  : null;
26
26
  activePanelContent = (React.createElement(React.Fragment, null,
27
27
  React.createElement(PanelHeading, null, "Overfetched graphQL fields"),
@@ -31,6 +31,7 @@ export default function DevTools() {
31
31
  fontSize: '0.9em',
32
32
  } }, warningsMarkup)));
33
33
  break;
34
+ }
34
35
  case 'network':
35
36
  activePanelContent = (React.createElement(React.Fragment, null,
36
37
  React.createElement(PanelHeading, null, "Metrics"),
@@ -1,40 +1,84 @@
1
- import React from 'react';
2
- import { ImageSizeOptions, ImageLoaderOptions } from '../../utilities';
1
+ import * as React from 'react';
3
2
  import type { Image as ImageType } from '../../storefront-api-types';
4
- import type { PartialDeep, Merge, MergeExclusive } from 'type-fest';
5
- export interface BaseImageProps {
6
- /** A custom function that generates the image URL. Parameters passed into this function includes
7
- * `src` and an `options` object that contains the provided `width`, `height` and `loaderOptions` values.
8
- */
9
- loader?(props: ImageLoaderOptions): string;
10
- /** An object of `loader` function options. For example, if the `loader` function requires a `scale` option,
11
- * then the value can be a property of the `loaderOptions` object (for example, `{scale: 2}`).
12
- */
13
- loaderOptions?: ImageLoaderOptions['options'];
14
- }
15
- interface MediaImagePropsBase extends BaseImageProps {
3
+ import type { PartialDeep, Simplify, SetRequired } from 'type-fest';
4
+ declare type HtmlImageProps = React.ImgHTMLAttributes<HTMLImageElement>;
5
+ declare type ImageProps<GenericLoaderOpts> = Simplify<ShopifyImageProps | ExternalImageProps<GenericLoaderOpts>>;
6
+ export declare function Image<GenericLoaderOpts>(props: ImageProps<GenericLoaderOpts>): JSX.Element;
7
+ export declare type ShopifyLoaderOptions = {
8
+ crop?: 'top' | 'bottom' | 'left' | 'right' | 'center';
9
+ scale?: 2 | 3;
10
+ width?: HtmlImageProps['width'] | ImageType['width'];
11
+ height?: HtmlImageProps['height'] | ImageType['height'];
12
+ };
13
+ export declare type ShopifyLoaderParams = Simplify<ShopifyLoaderOptions & {
14
+ src: ImageType['url'];
15
+ }>;
16
+ export declare type ShopifyImageProps = Omit<HtmlImageProps, 'src'> & {
16
17
  /** An object with fields that correspond to the Storefront API's
17
18
  * [Image object](https://shopify.dev/api/storefront/reference/common-objects/image).
19
+ * The `data` prop is required if `src` isn't used, but both props shouldn't be used
20
+ * at the same time. If both `src` and `data` are passed, then `data` takes priority.
18
21
  */
19
22
  data: PartialDeep<ImageType>;
20
- /** An object of image size options for Shopify CDN images. */
21
- options?: ImageSizeOptions;
22
- }
23
- interface ExternalImagePropsBase extends BaseImageProps {
24
- /** A URL string. This string can be an absolute path or a relative path depending on the `loader`. */
25
- src: string;
26
- /** The integer value for the width of the image. This is a required prop when `src` is present. */
27
- width: number;
28
- /** The integer value for the height of the image. This is a required prop when `src` is present. */
29
- height: number;
30
- }
31
- declare type BaseElementProps = React.ImgHTMLAttributes<HTMLImageElement>;
32
- declare type MediaImageProps = Merge<BaseElementProps, MediaImagePropsBase>;
33
- declare type ExternalImageProps = Merge<BaseElementProps, ExternalImagePropsBase>;
34
- declare type ImageProps = MergeExclusive<MediaImageProps, ExternalImageProps>;
35
- /**
36
- * The `Image` component renders an image for the Storefront API's
37
- * [Image object](https://shopify.dev/api/storefront/reference/common-objects/image).
38
- */
39
- export declare function Image(props: ImageProps): JSX.Element;
23
+ /** A custom function that generates the image URL. Parameters passed in
24
+ * are either `ShopifyLoaderParams` if using the `data` prop, or the
25
+ * `LoaderOptions` object that you pass to `loaderOptions`.
26
+ */
27
+ loader?: (params: ShopifyLoaderParams) => string;
28
+ /** An object of `loader` function options. For example, if the `loader` function
29
+ * requires a `scale` option, then the value can be a property of the
30
+ * `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
31
+ * is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
32
+ * prop is used, the data shape is whatever you define it to be, and this shape
33
+ * will be passed to `loader`.
34
+ */
35
+ loaderOptions?: ShopifyLoaderOptions;
36
+ /**
37
+ * 'src' shouldn't be passed when 'data' is used.
38
+ */
39
+ src?: never;
40
+ };
41
+ declare type LoaderProps<GenericLoaderOpts> = {
42
+ /** A URL string. This string can be an absolute path or a relative path depending
43
+ * on the `loader`. The `src` prop is required if `data` isn't used, but both
44
+ * props shouldn't be used at the same time. If both `src` and `data` are passed,
45
+ * then `data` takes priority.
46
+ */
47
+ src: HtmlImageProps['src'];
48
+ /** The integer or string value for the width of the image. This is a required prop
49
+ * when `src` is present.
50
+ */
51
+ width: HtmlImageProps['width'];
52
+ /** The integer or string value for the height of the image. This is a required prop
53
+ * when `src` is present.
54
+ */
55
+ height: HtmlImageProps['height'];
56
+ /** An object of `loader` function options. For example, if the `loader` function
57
+ * requires a `scale` option, then the value can be a property of the
58
+ * `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
59
+ * is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
60
+ * prop is used, the data shape is whatever you define it to be, and this shape
61
+ * will be passed to `loader`.
62
+ */
63
+ loaderOptions?: GenericLoaderOpts;
64
+ };
65
+ declare type ExternalImageProps<GenericLoaderOpts> = SetRequired<HtmlImageProps, 'src' | 'width' | 'height'> & {
66
+ /** A custom function that generates the image URL. Parameters passed in
67
+ * are either `ShopifyLoaderParams` if using the `data` prop, or the
68
+ * `LoaderOptions` object that you pass to `loaderOptions`.
69
+ */
70
+ loader?: (params: LoaderProps<GenericLoaderOpts>) => string;
71
+ /** An object of `loader` function options. For example, if the `loader` function
72
+ * requires a `scale` option, then the value can be a property of the
73
+ * `loaderOptions` object (for example, `{scale: 2}`). When the `data` prop
74
+ * is used, the object shape will be `ShopifyLoaderOptions`. When the `src`
75
+ * prop is used, the data shape is whatever you define it to be, and this shape
76
+ * will be passed to `loader`.
77
+ */
78
+ loaderOptions?: GenericLoaderOpts;
79
+ /**
80
+ * 'data' shouldn't be passed when 'src' is used.
81
+ */
82
+ data?: never;
83
+ };
40
84
  export {};
@@ -1,54 +1,59 @@
1
- import React from 'react';
2
- import { shopifyImageLoader, getShopifyImageDimensions, } from '../../utilities';
3
- /**
4
- * The `Image` component renders an image for the Storefront API's
5
- * [Image object](https://shopify.dev/api/storefront/reference/common-objects/image).
6
- */
1
+ import * as React from 'react';
2
+ import { getShopifyImageDimensions, shopifyImageLoader } from '../../utilities';
7
3
  export function Image(props) {
8
- var _a, _b, _c, _d;
9
- const { data, options, src, id, alt, width, height, loader, loaderOptions, ...passthroughProps } = props;
10
- if (!data && !src) {
11
- throw new Error('Image component: requires either an `data` or `src` prop.');
12
- }
13
- if (!data && src && (!width || !height)) {
14
- throw new Error(`Image component: when 'src' is provided, 'width' and 'height' are required and needs to be valid values (i.e. greater than zero). Provided values: 'src': ${src}, 'width': ${width}, 'height': ${height}`);
15
- }
16
- const imgProps = data
17
- ? convertShopifyImageData({
18
- data,
19
- options,
20
- loader,
21
- loaderOptions,
22
- id,
23
- alt,
24
- })
25
- : {
26
- src,
27
- id,
28
- alt,
29
- width,
30
- height,
31
- loader,
32
- loaderOptions: { width, height, ...loaderOptions },
33
- };
34
- const srcPath = imgProps.loader
35
- ? imgProps.loader({ src: imgProps.src, options: imgProps.loaderOptions })
36
- : imgProps.src;
37
- return (React.createElement("img", { id: (_a = imgProps.id) !== null && _a !== void 0 ? _a : '', loading: "lazy", alt: (_b = imgProps.alt) !== null && _b !== void 0 ? _b : '', ...passthroughProps, src: srcPath, width: (_c = imgProps.width) !== null && _c !== void 0 ? _c : undefined, height: (_d = imgProps.height) !== null && _d !== void 0 ? _d : undefined }));
4
+ if (!props.data && !props.src) {
5
+ throw new Error(`<Image/>: requires either a 'data' or 'src' prop.`);
6
+ }
7
+ if (props.data && props.src) {
8
+ console.warn(`<Image/>: using both 'data' and 'src' props is not supported; using the 'data' prop by default`);
9
+ }
10
+ if (props.data) {
11
+ return React.createElement(ShopifyImage, { ...props });
12
+ }
13
+ else {
14
+ return React.createElement(ExternalImage, { ...props });
15
+ }
16
+ }
17
+ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoader, loaderOptions, ...rest }) {
18
+ var _a, _b, _c;
19
+ if (!data.url) {
20
+ throw new Error(`<Image/>: the 'data' prop requires the 'url' property`);
21
+ }
22
+ if (!data.altText && !rest.alt) {
23
+ console.warn(`<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. ${data.id ? `Image ID: ${data.id}` : ''}`);
24
+ }
25
+ const { width: finalWidth, height: finalHeight } = getShopifyImageDimensions(data, loaderOptions);
26
+ if (!finalWidth || !finalHeight) {
27
+ console.warn(`<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties`);
28
+ }
29
+ let finalSrc = data.url;
30
+ if (loader) {
31
+ finalSrc = loader({
32
+ ...loaderOptions,
33
+ src: data.url,
34
+ width: finalWidth,
35
+ height: finalHeight,
36
+ });
37
+ }
38
+ /* eslint-disable hydrogen/prefer-image-component */
39
+ return (React.createElement("img", { id: (_a = data.id) !== null && _a !== void 0 ? _a : '', alt: (_c = (_b = data.altText) !== null && _b !== void 0 ? _b : rest.alt) !== null && _c !== void 0 ? _c : '', loading: loading !== null && loading !== void 0 ? loading : 'lazy', ...rest, src: finalSrc, width: finalWidth !== null && finalWidth !== void 0 ? finalWidth : undefined, height: finalHeight !== null && finalHeight !== void 0 ? finalHeight : undefined }));
40
+ /* eslint-enable hydrogen/prefer-image-component */
38
41
  }
39
- function convertShopifyImageData({ data, options, loader, loaderOptions, id: propId, alt, }) {
40
- const { url: src, altText, id } = data;
41
- if (!src) {
42
- throw new Error(`<Image/> requires 'data.url' when using the 'data' prop`);
43
- }
44
- const { width, height } = getShopifyImageDimensions(data, options);
45
- return {
46
- src,
47
- id: propId ? propId : id,
48
- alt: alt ? alt : altText,
49
- width,
50
- height,
51
- loader: loader ? loader : shopifyImageLoader,
52
- loaderOptions: { ...options, ...loaderOptions },
53
- };
42
+ function ExternalImage({ src, width, height, alt, loader, loaderOptions, loading, ...rest }) {
43
+ if (!width || !height) {
44
+ throw new Error(`<Image/>: when 'src' is provided, 'width' and 'height' are required and need to be valid values (i.e. greater than zero). Provided values: 'src': ${src}, 'width': ${width}, 'height': ${height}`);
45
+ }
46
+ if (!alt) {
47
+ console.warn(`<Image/>: when 'src' is provided, 'alt' should also be provided`);
48
+ }
49
+ let finalSrc = src;
50
+ if (loader) {
51
+ finalSrc = loader({ src, width, height, ...loaderOptions });
52
+ if (typeof finalSrc !== 'string' || !finalSrc) {
53
+ throw new Error(`<Image/>: 'loader' did not return a valid string`);
54
+ }
55
+ }
56
+ /* eslint-disable hydrogen/prefer-image-component */
57
+ return (React.createElement("img", { ...rest, src: finalSrc, width: width, height: height, alt: alt !== null && alt !== void 0 ? alt : '', loading: loading !== null && loading !== void 0 ? loading : 'lazy' }));
58
+ /* eslint-enable hydrogen/prefer-image-component */
54
59
  }
@@ -1 +1,2 @@
1
1
  export { Image } from './Image';
2
+ export type { ShopifyLoaderParams, ShopifyLoaderOptions, ShopifyImageProps, } from './Image';
@@ -30,12 +30,21 @@ export const Link = React.forwardRef(function Link(props, ref) {
30
30
  e.preventDefault();
31
31
  // If the URL hasn't changed, the regular <a> will do a replace
32
32
  const replace = !!_replace || createPath(location) === createPath({ pathname: to });
33
- navigate(props.to, {
33
+ navigate(to, {
34
34
  replace,
35
35
  clientState,
36
36
  });
37
37
  }
38
- }, [reloadDocument, target, _replace, to, clientState, onClick, location]);
38
+ }, [
39
+ reloadDocument,
40
+ target,
41
+ _replace,
42
+ to,
43
+ clientState,
44
+ onClick,
45
+ location,
46
+ navigate,
47
+ ]);
39
48
  const signalPrefetchIntent = () => {
40
49
  /**
41
50
  * startTransition to yield to more important updates
@@ -1,18 +1,5 @@
1
- import React, { useMemo, useState, useCallback } from 'react';
1
+ import React from 'react';
2
2
  import { LocalizationContext } from './LocalizationContext.client';
3
- import { useServerProps } from '../../foundation/useServerProps';
4
3
  export default function LocalizationClientProvider({ localization, children, }) {
5
- const { setServerProps } = useServerProps();
6
- const [country, setCountry] = useState(localization.country);
7
- const setter = useCallback((country) => {
8
- setCountry(country);
9
- setServerProps('country', country);
10
- }, [setServerProps]);
11
- const contextValue = useMemo(() => {
12
- return {
13
- country,
14
- setCountry: setter,
15
- };
16
- }, [country, setter]);
17
- return (React.createElement(LocalizationContext.Provider, { value: contextValue }, children));
4
+ return (React.createElement(LocalizationContext.Provider, { value: localization }, children));
18
5
  }
@@ -2,6 +2,5 @@ import type { LocalizationQuery } from './LocalizationProvider.server';
2
2
  export declare type Localization = LocalizationQuery['localization'];
3
3
  export interface LocalizationContextValue {
4
4
  country?: Localization['country'];
5
- setCountry(country: Localization['country']): void;
6
5
  }
7
6
  export declare const LocalizationContext: import("react").Context<LocalizationContextValue | null>;
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { PreloadOptions } from '../../types';
3
- import { Country, Currency } from '../../storefront-api-types';
3
+ import { Country } from '../../storefront-api-types';
4
4
  export interface LocalizationProviderProps {
5
5
  /** A `ReactNode` element. */
6
6
  children: ReactNode;
@@ -28,10 +28,6 @@ export declare type LocalizationQuery = {
28
28
  } & {
29
29
  country: {
30
30
  __typename?: 'Country';
31
- } & Pick<Country, 'isoCode' | 'name'> & {
32
- currency: {
33
- __typename?: 'Currency';
34
- } & Pick<Currency, 'isoCode'>;
35
- };
31
+ } & Pick<Country, 'isoCode' | 'name'>;
36
32
  };
37
33
  };
@@ -3,6 +3,7 @@ import LocalizationClientProvider from './LocalizationClientProvider.client';
3
3
  import { useShop } from '../../foundation/useShop';
4
4
  import { useShopQuery } from '../../hooks/useShopQuery';
5
5
  import { CacheDays } from '../../framework/CachingStrategy';
6
+ import { useSession } from '../../foundation/useSession/useSession';
6
7
  /**
7
8
  * The `LocalizationProvider` component automatically queries the Storefront API's
8
9
  * [`localization`](https://shopify.dev/api/storefront/reference/common-objects/queryroot) field
@@ -14,13 +15,21 @@ import { CacheDays } from '../../framework/CachingStrategy';
14
15
  */
15
16
  export function LocalizationProvider(props) {
16
17
  const { languageCode } = useShop();
18
+ const { countryCode, countryName } = useSession();
17
19
  const { data: { localization }, } = useShopQuery({
18
- query: query,
20
+ query,
19
21
  variables: { language: languageCode },
20
22
  cache: CacheDays(),
21
23
  preload: props.preload,
22
24
  });
23
- return (React.createElement(LocalizationClientProvider, { localization: localization }, props.children));
25
+ return (React.createElement(LocalizationClientProvider, { localization: countryCode
26
+ ? {
27
+ country: {
28
+ name: countryName,
29
+ isoCode: countryCode,
30
+ },
31
+ }
32
+ : localization }, props.children));
24
33
  }
25
34
  const query = `
26
35
  query Localization($language: LanguageCode)
@@ -29,9 +38,6 @@ query Localization($language: LanguageCode)
29
38
  country {
30
39
  isoCode
31
40
  name
32
- currency {
33
- isoCode
34
- }
35
41
  }
36
42
  }
37
43
  }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Image } from '../Image';
2
+ import { type ShopifyImageProps } from '../Image';
3
3
  import { Video } from '../Video';
4
4
  import { ExternalVideo } from '../ExternalVideo';
5
5
  import type { MediaEdge as MediaEdgeType } from '../../storefront-api-types';
@@ -8,7 +8,7 @@ export interface MediaFileProps {
8
8
  /** An object with fields that correspond to the Storefront API's [Media object](https://shopify.dev/api/storefront/reference/products/media). */
9
9
  data: PartialDeep<MediaEdgeType['node']>;
10
10
  /** The options for the `Image`, `Video`, or `ExternalVideo` components. */
11
- options?: React.ComponentProps<typeof Image>['options'] | React.ComponentProps<typeof Video>['options'] | React.ComponentProps<typeof ExternalVideo>['options'];
11
+ options?: ShopifyImageProps | React.ComponentProps<typeof Video>['previewImageOptions'] | React.ComponentProps<typeof ExternalVideo>['options'];
12
12
  }
13
13
  /**
14
14
  * The `MediaFile` component renders the media for the Storefront API's
@@ -17,10 +17,10 @@ export function MediaFile({ data, options, ...passthroughProps }) {
17
17
  console.warn(`No "image" property was found on the "data" prop for <MediaFile/>, for the "type='image'"`);
18
18
  return null;
19
19
  }
20
- return (React.createElement(Image, { ...passthroughProps, data: dataImage, options: options }));
20
+ return (React.createElement(Image, { ...passthroughProps, data: dataImage, loaderOptions: options }));
21
21
  }
22
22
  case 'VIDEO':
23
- return (React.createElement(Video, { ...passthroughProps, data: data, options: options }));
23
+ return (React.createElement(Video, { ...passthroughProps, data: data, previewImageOptions: options }));
24
24
  case 'EXTERNAL_VIDEO':
25
25
  return (React.createElement(ExternalVideo, { ...passthroughProps, data: data, options: options }));
26
26
  case 'MODEL_3D':
@@ -52,18 +52,17 @@ export function Metafield(props) {
52
52
  }
53
53
  case 'url':
54
54
  return (React.createElement("a", { href: data.value, ...passthroughProps }, data.value));
55
- case 'json':
55
+ case 'json': {
56
56
  const Wrapper = as !== null && as !== void 0 ? as : 'span';
57
57
  return (React.createElement(Wrapper, { ...passthroughProps }, JSON.stringify(data.value)));
58
+ }
58
59
  case 'file_reference': {
59
60
  if (((_a = data.reference) === null || _a === void 0 ? void 0 : _a.__typename) === 'MediaImage') {
60
61
  const ref = data.reference;
61
62
  return ref.image ? (React.createElement(Image, { data: ref.image, ...passthroughProps })) : null;
62
63
  }
63
64
  }
64
- default: {
65
- const Wrapper = as !== null && as !== void 0 ? as : 'span';
66
- return React.createElement(Wrapper, { ...passthroughProps }, data.value.toString());
67
- }
68
65
  }
66
+ const Wrapper = as !== null && as !== void 0 ? as : 'span';
67
+ return React.createElement(Wrapper, { ...passthroughProps }, data.value.toString());
69
68
  }
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect, useCallback, } from 'react';
2
- import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript';
2
+ import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript.client';
3
3
  /**
4
4
  * The `ModelViewer` component renders a 3D model (with the `model-viewer` tag) for
5
5
  * the Storefront API's [Model3d object](https://shopify.dev/api/storefront/reference/products/model3d).
@@ -5,11 +5,15 @@ interface MoneyProps<TTag> {
5
5
  as?: TTag;
6
6
  /** An object with fields that correspond to the Storefront API's [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2). */
7
7
  data: PartialDeep<MoneyV2>;
8
+ /** Whether to remove the currency symbol from the output. */
9
+ withoutCurrency?: boolean;
10
+ /** Whether to remove trailing zeros (fractional money) from the output. */
11
+ withoutTrailingZeros?: boolean;
8
12
  }
9
13
  /**
10
14
  * The `Money` component renders a string of the Storefront API's
11
15
  * [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the
12
- * `defaultLocale` in the `shopify.config.js` file.
16
+ * `defaultLocale` in [the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
13
17
  */
14
18
  export declare function Money<TTag extends keyof JSX.IntrinsicElements = 'div'>(props: JSX.IntrinsicElements[TTag] & MoneyProps<TTag>): JSX.Element;
15
19
  export {};
@@ -3,11 +3,24 @@ import { useMoney } from '../../hooks';
3
3
  /**
4
4
  * The `Money` component renders a string of the Storefront API's
5
5
  * [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the
6
- * `defaultLocale` in the `shopify.config.js` file.
6
+ * `defaultLocale` in [the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
7
7
  */
8
8
  export function Money(props) {
9
- const { data, as, ...passthroughProps } = props;
9
+ const { data, as, withoutCurrency, withoutTrailingZeros, ...passthroughProps } = props;
10
10
  const moneyObject = useMoney(data);
11
11
  const Wrapper = as !== null && as !== void 0 ? as : 'div';
12
- return React.createElement(Wrapper, { ...passthroughProps }, moneyObject.localizedString);
12
+ let output = moneyObject.localizedString;
13
+ if (withoutCurrency || withoutTrailingZeros) {
14
+ if (withoutCurrency && !withoutTrailingZeros) {
15
+ output = moneyObject.amount;
16
+ }
17
+ else if (!withoutCurrency && withoutTrailingZeros) {
18
+ output = moneyObject.withoutTrailingZeros;
19
+ }
20
+ else {
21
+ // both
22
+ output = moneyObject.withoutTrailingZerosAndCurrency;
23
+ }
24
+ }
25
+ return React.createElement(Wrapper, { ...passthroughProps }, output);
13
26
  }
@@ -26,7 +26,7 @@ export function ProductMetafield(props) {
26
26
  const message = 'does not have a value for metafield.';
27
27
  const productOrVariant = variantId ? `Variant` : 'Product';
28
28
  const logItems = {
29
- variantId: variantId,
29
+ variantId,
30
30
  ProductId: product.id,
31
31
  namespace,
32
32
  keyName,
@@ -6,7 +6,7 @@ export function ProductOptionsProvider({ children, initialVariantId, }) {
6
6
  const product = useProduct();
7
7
  const productOptions = useProductOptions({
8
8
  variants: product.variantsConnection,
9
- initialVariantId: initialVariantId,
9
+ initialVariantId,
10
10
  });
11
11
  return (React.createElement(ProductOptionsContext.Provider, { value: productOptions }, children));
12
12
  }
@@ -7,9 +7,13 @@ export interface ProductProviderProps {
7
7
  children: ReactNode;
8
8
  /** A [Product object](https://shopify.dev/api/storefront/reference/products/product). */
9
9
  data: PartialDeep<ProductType>;
10
- /** The initially selected variant. If this is missing, then `selectedVariantId`
11
- * in the returned `object` from the `useProduct` hook uses the first available variant
12
- * or the first variant (if none are available).
10
+ /** The initially selected variant.
11
+ * The following logic applies to `initialVariantId`:
12
+ * If `initialVariantId` is provided, then it's used, even if it's out of stock.
13
+ * If `initialVariantId` is provided, but is `null`, then no variant is used.
14
+ * If nothing is passed to `initialVariantId`, and you're in a `ProductProvider`, then `selectedVariant.id` is used.
15
+ * If nothing is passed to `initialVariantId` and you're not in a `ProductProvider`, then the first available or in-stock variant is used.
16
+ * If nothing is passed to `initialVariantId`, you're not in a `ProductProvider`, and no variants are in stock, then the first variant is used.
13
17
  */
14
18
  initialVariantId?: Parameters<typeof useProductOptions>['0']['initialVariantId'];
15
19
  }
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { useShop } from '../../foundation/useShop';
3
- import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript';
3
+ import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript.client';
4
4
  const URL = 'https://cdn.shopify.com/shopifycloud/shop-js/v0.8/client.js';
5
5
  /**
6
6
  * The `ShopPayButton` component renders a button that redirects to the Shop Pay checkout.
@@ -34,7 +34,11 @@ export function ShopPayButton({ variantIds, className, variantIdsAndQuantities,
34
34
  else {
35
35
  throw new Error(MissingPropsErrorMessage);
36
36
  }
37
- return (React.createElement("div", { className: className, tabIndex: 1 }, shopPayLoadedStatus === 'done' && (React.createElement("shop-pay-button", { "store-url": `https://${storeDomain}`, variants: ids.join(',') }))));
37
+ return (
38
+ /* eslint-disable jsx-a11y/no-noninteractive-tabindex */
39
+ React.createElement("div", { className: className, tabIndex: 0 }, shopPayLoadedStatus === 'done' && (React.createElement("shop-pay-button", { "store-url": `https://${storeDomain}`, variants: ids.join(',') })))
40
+ /* eslint-enable jsx-a11y/no-noninteractive-tabindex */
41
+ );
38
42
  }
39
43
  /**
40
44
  * Takes a string in the format of "gid://shopify/ProductVariant/41007289630776" and returns a string of the ID part at the end: "41007289630776"
@@ -1,11 +1,11 @@
1
- import { ImageSizeOptions } from '../../utilities';
1
+ import { shopifyImageLoader } from '../../utilities';
2
2
  import type { Video as VideoType } from '../../storefront-api-types';
3
3
  import type { PartialDeep } from 'type-fest';
4
4
  interface VideoProps {
5
5
  /** An object with fields that correspond to the Storefront API's [Video object](https://shopify.dev/api/storefront/latest/objects/video). */
6
6
  data: PartialDeep<VideoType>;
7
- /** An object of image size options for the video's `previewImage`. */
8
- options?: ImageSizeOptions;
7
+ /** An object of image size options for the video's `previewImage`. Uses `shopifyImageLoader` to generate the `poster` URL. */
8
+ previewImageOptions?: Parameters<typeof shopifyImageLoader>[0];
9
9
  }
10
10
  /**
11
11
  * The `Video` component renders a `video` for the Storefront API's [Video object](https://shopify.dev/api/storefront/reference/products/video).