@shopify/hydrogen 0.11.0-experimental.0 → 0.11.0-experimental.1

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 (99) hide show
  1. package/dist/esnext/client.d.ts +0 -1
  2. package/dist/esnext/client.js +0 -1
  3. package/dist/esnext/components/CartLines/CartLines.d.ts +3 -4
  4. package/dist/esnext/components/CartLines/CartLines.js +3 -5
  5. package/dist/esnext/components/CartShopPayButton/CartShopPayButton.client.js +6 -3
  6. package/dist/esnext/components/Link/Link.client.d.ts +18 -1
  7. package/dist/esnext/components/Link/Link.client.js +42 -4
  8. package/dist/esnext/components/Metafield/Metafield.client.d.ts +1 -1
  9. package/dist/esnext/components/Router/index.d.ts +1 -0
  10. package/dist/esnext/components/Router/index.js +1 -0
  11. package/dist/esnext/components/Seo/CollectionSeo.client.js +2 -2
  12. package/dist/esnext/components/Seo/ProductSeo.client.d.ts +1 -1
  13. package/dist/esnext/components/Seo/ProductSeo.client.js +4 -8
  14. package/dist/esnext/components/Seo/types.d.ts +2 -6
  15. package/dist/esnext/components/ShopPayButton/ShopPayButton.client.d.ts +22 -5
  16. package/dist/esnext/components/ShopPayButton/ShopPayButton.client.js +45 -12
  17. package/dist/esnext/components/UnitPrice/UnitPrice.client.d.ts +1 -6
  18. package/dist/esnext/components/UnitPrice/UnitPrice.client.js +3 -12
  19. package/dist/esnext/components/index.d.ts +2 -2
  20. package/dist/esnext/components/index.js +2 -48
  21. package/dist/esnext/constants.d.ts +1 -0
  22. package/dist/esnext/constants.js +1 -0
  23. package/dist/esnext/entry-client.js +3 -4
  24. package/dist/esnext/entry-server.js +2 -1
  25. package/dist/esnext/foundation/Helmet/Helmet.client.js +2 -6
  26. package/dist/esnext/foundation/Router/Router.client.d.ts +12 -0
  27. package/dist/esnext/foundation/Router/Router.client.js +44 -0
  28. package/dist/esnext/foundation/ssr-interop.d.ts +29 -0
  29. package/dist/esnext/foundation/ssr-interop.js +35 -0
  30. package/dist/esnext/foundation/useQuery/hooks.d.ts +1 -1
  31. package/dist/esnext/foundation/useQuery/hooks.js +1 -1
  32. package/dist/esnext/foundation/useServerState/use-server-state.d.ts +2 -1
  33. package/dist/esnext/foundation/useServerState/use-server-state.js +2 -2
  34. package/dist/esnext/foundation/useShop/use-shop.js +2 -6
  35. package/dist/esnext/foundation/useUrl/useUrl.d.ts +1 -1
  36. package/dist/esnext/foundation/useUrl/useUrl.js +5 -5
  37. package/dist/esnext/framework/Hydration/Html.js +13 -1
  38. package/dist/esnext/framework/Hydration/rsc.d.ts +1 -1
  39. package/dist/esnext/framework/Hydration/rsc.js +4 -4
  40. package/dist/esnext/framework/plugin.js +2 -0
  41. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-config.js +1 -1
  42. package/dist/esnext/framework/plugins/vite-plugin-hydrogen-middleware.js +1 -1
  43. package/dist/esnext/framework/plugins/vite-plugin-ssr-interop.d.ts +3 -0
  44. package/dist/esnext/framework/plugins/vite-plugin-ssr-interop.js +13 -0
  45. package/dist/esnext/handle-event.js +2 -1
  46. package/dist/esnext/hooks/useNavigate/index.d.ts +1 -0
  47. package/dist/esnext/hooks/useNavigate/index.js +1 -0
  48. package/dist/esnext/hooks/useNavigate/useNavigate.d.ts +10 -0
  49. package/dist/esnext/hooks/useNavigate/useNavigate.js +11 -0
  50. package/dist/esnext/utilities/error.js +3 -12
  51. package/dist/esnext/utilities/fetch.js +8 -0
  52. package/dist/esnext/utilities/log/log.d.ts +4 -3
  53. package/dist/esnext/utilities/video_parameters.js +4 -0
  54. package/dist/esnext/version.d.ts +1 -1
  55. package/dist/esnext/version.js +1 -1
  56. package/dist/node/constants.d.ts +1 -0
  57. package/dist/node/constants.js +4 -0
  58. package/dist/node/foundation/Helmet/Helmet.client.js +2 -6
  59. package/dist/node/foundation/ssr-interop.d.ts +29 -0
  60. package/dist/node/foundation/ssr-interop.js +39 -0
  61. package/dist/node/framework/Hydration/Html.js +13 -1
  62. package/dist/node/framework/Hydration/rsc.d.ts +1 -1
  63. package/dist/node/framework/Hydration/rsc.js +4 -4
  64. package/dist/node/framework/plugin.js +2 -0
  65. package/dist/node/framework/plugins/vite-plugin-hydrogen-config.js +1 -1
  66. package/dist/node/framework/plugins/vite-plugin-hydrogen-middleware.js +1 -1
  67. package/dist/node/framework/plugins/vite-plugin-ssr-interop.d.ts +3 -0
  68. package/dist/node/framework/plugins/vite-plugin-ssr-interop.js +15 -0
  69. package/dist/node/handle-event.js +2 -1
  70. package/dist/node/utilities/log/log.d.ts +4 -3
  71. package/dist/worker/constants.d.ts +1 -0
  72. package/dist/worker/constants.js +1 -0
  73. package/dist/worker/foundation/Helmet/Helmet.client.js +2 -6
  74. package/dist/worker/foundation/ssr-interop.d.ts +29 -0
  75. package/dist/worker/foundation/ssr-interop.js +35 -0
  76. package/dist/worker/handle-event.js +2 -1
  77. package/dist/worker/utilities/log/log.d.ts +4 -3
  78. package/package.json +4 -5
  79. package/vendor/react-server-dom-vite/cjs/react-server-dom-vite-plugin.js +1 -5
  80. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-client-proxy.js +1 -0
  81. package/vendor/react-server-dom-vite/esm/react-server-dom-vite-plugin.js +1 -5
  82. package/dist/esnext/foundation/Router/ServerStateRouter.client.d.ts +0 -6
  83. package/dist/esnext/foundation/Router/ServerStateRouter.client.js +0 -30
  84. package/dist/esnext/utilities/meta-env-ssr.d.ts +0 -1
  85. package/dist/esnext/utilities/meta-env-ssr.js +0 -3
  86. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +0 -22
  87. package/dist/node/foundation/ServerRequestProvider/ServerRequestProvider.js +0 -92
  88. package/dist/node/foundation/ServerRequestProvider/index.d.ts +0 -1
  89. package/dist/node/foundation/ServerRequestProvider/index.js +0 -13
  90. package/dist/node/utilities/meta-env-ssr.d.ts +0 -1
  91. package/dist/node/utilities/meta-env-ssr.js +0 -6
  92. package/dist/worker/foundation/ServerRequestProvider/ServerRequestProvider.d.ts +0 -22
  93. package/dist/worker/foundation/ServerRequestProvider/ServerRequestProvider.js +0 -67
  94. package/dist/worker/foundation/ServerRequestProvider/index.d.ts +0 -1
  95. package/dist/worker/foundation/ServerRequestProvider/index.js +0 -1
  96. package/dist/worker/framework/cache.d.ts +0 -26
  97. package/dist/worker/framework/cache.js +0 -101
  98. package/dist/worker/utilities/meta-env-ssr.d.ts +0 -1
  99. package/dist/worker/utilities/meta-env-ssr.js +0 -3
@@ -3,6 +3,5 @@ export * from './hooks';
3
3
  export * from './foundation/useServerState';
4
4
  export * from './foundation/useShop';
5
5
  export * from './foundation/ServerStateProvider';
6
- export { ServerStateRouter } from './foundation/Router/ServerStateRouter.client';
7
6
  export { Helmet } from './foundation/Helmet';
8
7
  export * from './utilities';
@@ -3,6 +3,5 @@ export * from './hooks';
3
3
  export * from './foundation/useServerState';
4
4
  export * from './foundation/useShop';
5
5
  export * from './foundation/ServerStateProvider';
6
- export { ServerStateRouter } from './foundation/Router/ServerStateRouter.client';
7
6
  export { Helmet } from './foundation/Helmet';
8
7
  export * from './utilities';
@@ -1,16 +1,15 @@
1
1
  import { ReactNode, ElementType } from 'react';
2
- import { Cart } from '../CartProvider';
3
2
  import { Props } from '../types';
4
3
  export interface CartLinesProps {
5
4
  /** A `ReactNode` element. Valid values: `ul` or `undefined`. If `ul`, then each child will
6
5
  * be wrapped with a `li` element.
7
6
  */
8
7
  as?: 'ul';
9
- /** A `ReactNode` element or a function that takes a cart line as an argument and returns a `ReactNode`. */
10
- children: ReactNode | ((line: Cart['lines'][1]) => ReactNode);
8
+ /** A `ReactNode` element */
9
+ children: ReactNode;
11
10
  }
12
11
  /**
13
12
  * The `CartLines` component iterates over each cart line and renders its `children` within
14
- * a `CartLineProvider` for each cart line. It also provides render props in the case where `children` is a function.
13
+ * a `CartLineProvider` for each cart line.
15
14
  */
16
15
  export declare function CartLines<TTag extends ElementType>(props: Props<TTag> & CartLinesProps): JSX.Element;
@@ -1,9 +1,9 @@
1
- import React, { cloneElement, Fragment } from 'react';
1
+ import React, { Fragment } from 'react';
2
2
  import { useCart } from '../CartProvider';
3
3
  import { CartLineProvider } from '../CartLineProvider';
4
4
  /**
5
5
  * The `CartLines` component iterates over each cart line and renders its `children` within
6
- * a `CartLineProvider` for each cart line. It also provides render props in the case where `children` is a function.
6
+ * a `CartLineProvider` for each cart line.
7
7
  */
8
8
  export function CartLines(props) {
9
9
  const { lines } = useCart();
@@ -12,8 +12,6 @@ export function CartLines(props) {
12
12
  const ChildWrapper = Wrapper === 'ul' ? 'li' : Fragment;
13
13
  return (React.createElement(Wrapper, { ...passthroughProps }, lines.map((line) => {
14
14
  return (React.createElement(ChildWrapper, { key: line.id },
15
- React.createElement(CartLineProvider, { line: line }, typeof children === 'function'
16
- ? cloneElement(children(line))
17
- : children)));
15
+ React.createElement(CartLineProvider, { line: line }, children)));
18
16
  })));
19
17
  }
@@ -9,8 +9,11 @@ export function CartShopPayButton({
9
9
  /** A string of classes to apply to the `div` that wraps the `shop-pay-button` web component. */
10
10
  className, }) {
11
11
  const { lines } = useCart();
12
- const ids = useMemo(() => {
13
- return lines.map((line) => line.merchandise.id);
12
+ const idsAndQuantities = useMemo(() => {
13
+ return lines.map((line) => ({
14
+ id: line.merchandise.id,
15
+ quantity: line.quantity,
16
+ }));
14
17
  }, [lines]);
15
- return React.createElement(ShopPayButton, { className: className, variantIds: ids });
18
+ return (React.createElement(ShopPayButton, { className: className, variantIdsAndQuantities: idsAndQuantities }));
16
19
  }
@@ -1 +1,18 @@
1
- export declare function Link(props: any): JSX.Element;
1
+ import React from 'react';
2
+ export interface LinkProps
3
+ /** All properties available to an `<a>` element are available. See [anchor element documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attributes).*/
4
+ extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
5
+ /** The destination URL that the link points to. This is the `href` attribute of the underlying `<a>` element. */
6
+ to: string;
7
+ /** Whether to update the state object or URL of the current history entry. Refer to the [history.replaceState documentation](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState). */
8
+ replace?: boolean;
9
+ /** The custom client state with the navigation. */
10
+ clientState?: any;
11
+ /** Whether to reload the whole document on navigation. */
12
+ reloadDocument?: boolean;
13
+ }
14
+ /**
15
+ * The `Link` component lets users navigate from one page to another.
16
+ * It renders an accessible `<a>` element.
17
+ */
18
+ export declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLAnchorElement>>;
@@ -1,5 +1,43 @@
1
- import React from 'react';
2
- import { Link as RRLink } from 'react-router-dom';
3
- export function Link(props) {
4
- return import.meta.env.SSR ? (React.createElement("a", { href: props.to, ...props, to: null })) : (React.createElement(RRLink, { ...props }));
1
+ import React, { useCallback } from 'react';
2
+ import { useRouter } from '../Router';
3
+ import { createPath } from 'history';
4
+ import { useNavigate } from '../../hooks/useNavigate';
5
+ /**
6
+ * The `Link` component lets users navigate from one page to another.
7
+ * It renders an accessible `<a>` element.
8
+ */
9
+ export const Link = React.forwardRef(function Link(props, ref) {
10
+ const navigate = useNavigate();
11
+ const { location } = useRouter();
12
+ const { reloadDocument, target, replace: _replace, to, onClick, clientState, } = props;
13
+ const internalClick = useCallback((e) => {
14
+ if (onClick)
15
+ onClick(e);
16
+ if (!reloadDocument && // do regular browser stuff
17
+ e.button === 0 && // Ignore everything but left clicks
18
+ (!target || target === '_self') && // Let browser handle "target=_blank"
19
+ !isModifiedEvent(e) // Ignore modifier key clicks
20
+ ) {
21
+ e.preventDefault();
22
+ // If the URL hasn't changed, the regular <a> will do a replace
23
+ const replace = !!_replace || createPath(location) === createPath({ pathname: to });
24
+ navigate(props.to, {
25
+ replace,
26
+ clientState,
27
+ });
28
+ }
29
+ }, [reloadDocument, target, _replace, to, clientState, onClick, location]);
30
+ return (React.createElement("a", { ...without(props, ['to', 'replace', 'clientState', 'reloadDocument']), ref: ref, onClick: internalClick, href: props.to }, props.children));
31
+ });
32
+ function isModifiedEvent(event) {
33
+ return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
34
+ }
35
+ function without(obj, props) {
36
+ const newObj = {};
37
+ for (const key of Object.keys(obj)) {
38
+ if (!props.includes(key)) {
39
+ newObj[key] = obj[key];
40
+ }
41
+ }
42
+ return newObj;
5
43
  }
@@ -4,7 +4,7 @@ import { ParsedMetafield } from '../../types';
4
4
  export interface MetafieldProps {
5
5
  /** A [Metafield object](/api/storefront/reference/common-objects/metafield) from the Storefront API. */
6
6
  metafield: ParsedMetafield;
7
- /** An HTML tag to be rendered as the base element wrapper. The default value varies depending on [`metafield.type`](/apps/metafields/definitions/types). */
7
+ /** An HTML tag to be rendered as the base element wrapper. The default value varies depending on [metafield.type](/apps/metafields/types). */
8
8
  as?: ElementType;
9
9
  }
10
10
  /**
@@ -0,0 +1 @@
1
+ export { Router, useRouter, useLocation, } from '../../foundation/Router/Router.client';
@@ -0,0 +1 @@
1
+ export { Router, useRouter, useLocation, } from '../../foundation/Router/Router.client';
@@ -5,8 +5,8 @@ import { TwitterSeo } from './TwitterSeo.client';
5
5
  import { ImageSeo } from './ImageSeo.client';
6
6
  export function CollectionSeo({ title, description, seo, image }) {
7
7
  var _a, _b;
8
- const seoTitle = (_a = (seo && seo.title)) !== null && _a !== void 0 ? _a : title;
9
- const seoDescription = (_b = (seo && seo.description)) !== null && _b !== void 0 ? _b : description;
8
+ const seoTitle = (_a = seo.title) !== null && _a !== void 0 ? _a : title;
9
+ const seoDescription = (_b = seo.description) !== null && _b !== void 0 ? _b : description;
10
10
  return (React.createElement(React.Fragment, null,
11
11
  React.createElement(TitleSeo, { title: seoTitle }),
12
12
  React.createElement(DescriptionSeo, { description: seoDescription }),
@@ -1,2 +1,2 @@
1
1
  import { Product } from './types';
2
- export declare function ProductSeo({ url, title, description, seo, vendor, images, variants, }: Product): JSX.Element;
2
+ export declare function ProductSeo({ url, title, description, seo, vendor, featuredImage, variants, }: Product): JSX.Element;
@@ -4,12 +4,11 @@ import { TitleSeo } from './TitleSeo.client';
4
4
  import { DescriptionSeo } from './DescriptionSeo.client';
5
5
  import { TwitterSeo } from './TwitterSeo.client';
6
6
  import { ImageSeo } from './ImageSeo.client';
7
- export function ProductSeo({ url, title, description, seo, vendor, images, variants, }) {
8
- var _a, _b, _c;
7
+ export function ProductSeo({ url, title, description, seo, vendor, featuredImage, variants, }) {
8
+ var _a, _b;
9
9
  const seoTitle = (_a = seo === null || seo === void 0 ? void 0 : seo.title) !== null && _a !== void 0 ? _a : title;
10
10
  const seoDescription = (_b = seo === null || seo === void 0 ? void 0 : seo.description) !== null && _b !== void 0 ? _b : description;
11
11
  let firstVariantPrice;
12
- let firstImage;
13
12
  const productSchema = {
14
13
  '@context': 'http://schema.org/',
15
14
  '@type': 'Product',
@@ -21,10 +20,7 @@ export function ProductSeo({ url, title, description, seo, vendor, images, varia
21
20
  },
22
21
  url,
23
22
  };
24
- if (images.edges.length > 0) {
25
- firstImage = (_c = images.edges[0]) === null || _c === void 0 ? void 0 : _c.node;
26
- productSchema.image = firstImage.url;
27
- }
23
+ productSchema.image = featuredImage.url;
28
24
  if (variants.edges.length > 0) {
29
25
  const firstVariant = variants.edges[0].node;
30
26
  firstVariantPrice = firstVariant.priceV2;
@@ -56,5 +52,5 @@ export function ProductSeo({ url, title, description, seo, vendor, images, varia
56
52
  React.createElement(TitleSeo, { title: seoTitle }),
57
53
  React.createElement(DescriptionSeo, { description: seoDescription }),
58
54
  React.createElement(TwitterSeo, { title: seoTitle, description: seoDescription }),
59
- firstImage && React.createElement(ImageSeo, { ...firstImage })));
55
+ featuredImage && React.createElement(ImageSeo, { ...featuredImage })));
60
56
  }
@@ -32,11 +32,7 @@ export interface Product {
32
32
  description?: Description;
33
33
  };
34
34
  vendor: string;
35
- images: {
36
- edges: {
37
- node: Image;
38
- }[];
39
- };
35
+ featuredImage: Image;
40
36
  variants: {
41
37
  edges: {
42
38
  node: {
@@ -56,7 +52,7 @@ export interface Product {
56
52
  export interface Collection {
57
53
  title: Title;
58
54
  description: Description;
59
- seo?: {
55
+ seo: {
60
56
  title?: Title;
61
57
  description?: Description;
62
58
  };
@@ -1,9 +1,20 @@
1
- export interface ShopPayButtonProps {
2
- /** An array of IDs of the variants to purchase with Shop Pay. */
3
- variantIds: string[];
1
+ export declare type ShopPayButtonProps = {
4
2
  /** A string of classes to apply to the `div` that wraps the Shop Pay button. */
5
3
  className?: string;
6
- }
4
+ } & ({
5
+ /** An array of IDs of the variants to purchase with Shop Pay. This will only ever have a quantity of 1 for each variant. If you want to use other quantities, then use 'variantIdsAndQuantities'. */
6
+ variantIds: string[];
7
+ /** An array of variant IDs and quantities to purchase with Shop Pay. */
8
+ variantIdsAndQuantities?: never;
9
+ } | {
10
+ /** An array of IDs of the variants to purchase with Shop Pay. This will only ever have a quantity of 1 for each variant. If you want to use other quantities, then use 'variantIdsAndQuantities'. */
11
+ variantIds?: never;
12
+ /** An array of variant IDs and quantities to purchase with Shop Pay. */
13
+ variantIdsAndQuantities: Array<{
14
+ id: string;
15
+ quantity: number;
16
+ }>;
17
+ });
7
18
  declare global {
8
19
  namespace JSX {
9
20
  interface IntrinsicElements {
@@ -17,4 +28,10 @@ declare global {
17
28
  /**
18
29
  * The `ShopPayButton` component renders a button that redirects to the Shop Pay checkout.
19
30
  */
20
- export declare function ShopPayButton({ variantIds, className }: ShopPayButtonProps): JSX.Element;
31
+ export declare function ShopPayButton({ variantIds, className, variantIdsAndQuantities, }: ShopPayButtonProps): JSX.Element;
32
+ /**
33
+ * Takes a string in the format of "gid://shopify/ProductVariant/41007289630776" and returns a string of the ID part at the end: "41007289630776"
34
+ */
35
+ export declare function getIdFromGid(id?: string): string | undefined;
36
+ export declare const MissingPropsErrorMessage = "You must pass in either \"variantIds\" or \"variantIdsAndQuantities\" to ShopPayButton";
37
+ export declare const DoublePropsErrorMessage = "You must provide either a variantIds or variantIdsAndQuantities prop, but not both in the ShopPayButton component";
@@ -1,23 +1,56 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React from 'react';
2
2
  import { useShop } from '../../foundation/useShop';
3
3
  import { useLoadScript } from '../../hooks/useLoadScript/useLoadScript';
4
- const URL = 'https://cdn.shopify.com/shopifycloud/shop-js/v0.1/client.js';
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.
7
7
  */
8
- export function ShopPayButton({ variantIds, className }) {
9
- const [ids, setIds] = useState([]);
8
+ export function ShopPayButton({ variantIds, className, variantIdsAndQuantities, }) {
10
9
  const { storeDomain } = useShop();
11
10
  const shopPayLoadedStatus = useLoadScript(URL);
12
- useEffect(() => {
13
- const ids = variantIds.reduce((accumulator, gid) => {
14
- const id = gid.split('/').pop();
15
- if (id) {
16
- accumulator.push(id);
11
+ let ids;
12
+ if (variantIds && variantIdsAndQuantities) {
13
+ throw new Error(DoublePropsErrorMessage);
14
+ }
15
+ if (variantIds) {
16
+ ids = variantIds.reduce((prev, curr) => {
17
+ const bareId = getIdFromGid(curr);
18
+ if (bareId) {
19
+ prev.push(bareId);
17
20
  }
18
- return accumulator;
21
+ return prev;
19
22
  }, []);
20
- setIds(ids);
21
- }, [variantIds]);
23
+ }
24
+ else if (variantIdsAndQuantities) {
25
+ ids = variantIdsAndQuantities.reduce((prev, curr) => {
26
+ var _a;
27
+ const bareId = getIdFromGid(curr === null || curr === void 0 ? void 0 : curr.id);
28
+ if (bareId) {
29
+ prev.push(`${bareId}:${(_a = curr === null || curr === void 0 ? void 0 : curr.quantity) !== null && _a !== void 0 ? _a : 1}`);
30
+ }
31
+ return prev;
32
+ }, []);
33
+ }
34
+ else {
35
+ throw new Error(MissingPropsErrorMessage);
36
+ }
22
37
  return (React.createElement("div", { className: className, tabIndex: 1 }, shopPayLoadedStatus === 'done' && (React.createElement("shop-pay-button", { "store-url": `https://${storeDomain}`, variants: ids.join(',') }))));
23
38
  }
39
+ /**
40
+ * Takes a string in the format of "gid://shopify/ProductVariant/41007289630776" and returns a string of the ID part at the end: "41007289630776"
41
+ */
42
+ export function getIdFromGid(id) {
43
+ if (!id)
44
+ return;
45
+ let gid;
46
+ // atob() / Buffer required for SFAPI 2022-01. Remove atob() when upgrading to 2022-04
47
+ if (typeof (window === null || window === void 0 ? void 0 : window.atob) !== 'undefined') {
48
+ gid = window.atob(id);
49
+ }
50
+ else {
51
+ gid = Buffer.from(id, 'base64').toString('ascii');
52
+ }
53
+ return gid.split('/').pop();
54
+ }
55
+ export const MissingPropsErrorMessage = `You must pass in either "variantIds" or "variantIdsAndQuantities" to ShopPayButton`;
56
+ export const DoublePropsErrorMessage = `You must provide either a variantIds or variantIdsAndQuantities prop, but not both in the ShopPayButton component`;
@@ -1,4 +1,4 @@
1
- import { ElementType, ReactNode } from 'react';
1
+ import { ElementType } from 'react';
2
2
  import { Props } from '../types';
3
3
  import { UnitPriceMeasurement, MoneyV2 } from '../../graphql/types/types';
4
4
  export interface UnitPriceProps {
@@ -6,17 +6,12 @@ export interface UnitPriceProps {
6
6
  unitPrice: MoneyV2;
7
7
  /** A [`UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement). */
8
8
  unitPriceMeasurement: UnitPriceMeasurement;
9
- /** A function that takes an object returned by the `UnitPrice` component and returns a `ReactNode`. */
10
- children?: ReactNode;
11
9
  /** An HTML tag to be rendered as the base element wrapper. The default is `div`. */
12
10
  as?: ElementType;
13
11
  }
14
12
  /**
15
13
  * The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
16
14
  * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
17
- *
18
- * If `children` is a function, then it will provide render props for the `children` corresponding to the object
19
- * returned by the `useMoney` hook and the `UnitPriceMeasurement` object.
20
15
  */
21
16
  export declare function UnitPrice<TTag extends ElementType>(props: Props<TTag> & UnitPriceProps): JSX.Element;
22
17
  export declare namespace UnitPrice {
@@ -1,26 +1,17 @@
1
1
  import React from 'react';
2
- import { useMoney } from '../../hooks';
3
2
  import { Money } from '../Money';
4
3
  import { UnitPriceFragment as Fragment } from '../../graphql/graphql-constants';
5
4
  /**
6
5
  * The `UnitPrice` component renders a string with a [UnitPrice](/themes/pricing-payments/unit-pricing) as the
7
6
  * [Storefront API's `MoneyV2` object](/api/storefront/reference/common-objects/moneyv2) with a reference unit from the [Storefront API's `UnitPriceMeasurement` object](/api/storefront/reference/products/unitpricemeasurement).
8
- *
9
- * If `children` is a function, then it will provide render props for the `children` corresponding to the object
10
- * returned by the `useMoney` hook and the `UnitPriceMeasurement` object.
11
7
  */
12
8
  export function UnitPrice(props) {
13
- const { unitPrice, unitPriceMeasurement, children, as, ...passthroughProps } = props;
9
+ const { unitPrice, unitPriceMeasurement, as, ...passthroughProps } = props;
14
10
  const Wrapper = as !== null && as !== void 0 ? as : 'div';
15
- const unitPriceMoneyObject = useMoney(unitPrice);
16
- const unitPriceAndMeasurementObject = {
17
- ...unitPriceMoneyObject,
18
- ...unitPriceMeasurement,
19
- };
20
- return (React.createElement(Wrapper, { ...passthroughProps }, typeof children === 'function' ? (children(unitPriceAndMeasurementObject)) : (React.createElement(React.Fragment, null,
11
+ return (React.createElement(Wrapper, { ...passthroughProps },
21
12
  React.createElement(Money, { money: unitPrice }),
22
13
  "/",
23
- unitPriceMeasurement.referenceUnit))));
14
+ unitPriceMeasurement.referenceUnit));
24
15
  }
25
16
  UnitPrice.Fragment = Fragment;
26
17
  export const UnitPriceFragment = Fragment;
@@ -41,12 +41,12 @@ export { SelectedVariantAddToCartButton } from './SelectedVariantAddToCartButton
41
41
  export { SelectedVariantBuyNowButton } from './SelectedVariantBuyNowButton';
42
42
  export { SelectedVariantShopPayButton } from './SelectedVariantShopPayButton';
43
43
  export { SelectedVariantImage } from './SelectedVariantImage';
44
+ export { SelectedVariantUnitPrice } from './SelectedVariantUnitPrice';
44
45
  export type { BuyNowButtonProps, BuyNowButtonPropsWeControl, } from './BuyNowButton';
45
46
  export { BuyNowButton } from './BuyNowButton';
46
47
  export type { ShopPayButtonProps } from './ShopPayButton';
47
48
  export { ShopPayButton } from './ShopPayButton';
48
49
  export { useAvailableCountries } from '../hooks/useAvailableCountries';
49
50
  export { useCountry } from '../hooks/useCountry';
50
- export declare const Product: Function & Record<string, any>;
51
- export declare const CartLine: Function & Record<string, any>;
52
51
  export { Seo } from './Seo';
52
+ export { useNavigate } from '../hooks/useNavigate';
@@ -31,56 +31,10 @@ export { SelectedVariantAddToCartButton } from './SelectedVariantAddToCartButton
31
31
  export { SelectedVariantBuyNowButton } from './SelectedVariantBuyNowButton';
32
32
  export { SelectedVariantShopPayButton } from './SelectedVariantShopPayButton';
33
33
  export { SelectedVariantImage } from './SelectedVariantImage';
34
+ export { SelectedVariantUnitPrice } from './SelectedVariantUnitPrice';
34
35
  export { BuyNowButton } from './BuyNowButton';
35
36
  export { ShopPayButton } from './ShopPayButton';
36
37
  export { useAvailableCountries } from '../hooks/useAvailableCountries';
37
38
  export { useCountry } from '../hooks/useCountry';
38
- /**
39
- * Provide namespaced aliases for the `Product` group.
40
- */
41
- import { ProductProvider } from './ProductProvider';
42
- import { ProductPrice } from './ProductPrice';
43
- import { ProductDescription } from './ProductDescription';
44
- import { ProductTitle } from './ProductTitle';
45
- import { ProductMetafield } from './ProductMetafield';
46
- import { SelectedVariantAddToCartButton } from './SelectedVariantAddToCartButton';
47
- import { SelectedVariantBuyNowButton } from './SelectedVariantBuyNowButton';
48
- import { SelectedVariantShopPayButton } from './SelectedVariantShopPayButton';
49
- import { SelectedVariantImage } from './SelectedVariantImage';
50
- import { SelectedVariantPrice } from './SelectedVariantPrice';
51
- import { SelectedVariantUnitPrice } from './SelectedVariantUnitPrice';
52
- import { SelectedVariantMetafield } from './SelectedVariantMetafield';
53
- export const Product = ProductProvider;
54
- Product.Description = ProductDescription;
55
- Product.Price = ProductPrice;
56
- Product.Title = ProductTitle;
57
- Product.Metafield = ProductMetafield;
58
- Product.SelectedVariant = {
59
- AddToCartButton: SelectedVariantAddToCartButton,
60
- BuyNowButton: SelectedVariantBuyNowButton,
61
- ShopPayButton: SelectedVariantShopPayButton,
62
- Price: SelectedVariantPrice,
63
- Image: SelectedVariantImage,
64
- UnitPrice: SelectedVariantUnitPrice,
65
- Metafield: SelectedVariantMetafield,
66
- };
67
- /**
68
- * Provide namespaced aliases for the `CartLine` group.
69
- */
70
- import { CartLineProvider } from './CartLineProvider';
71
- import { CartLineImage } from './CartLineImage';
72
- import { CartLinePrice } from './CartLinePrice';
73
- import { CartLineProductTitle } from './CartLineProductTitle';
74
- import { CartLineQuantity } from './CartLineQuantity';
75
- import { CartLineQuantityAdjustButton } from './CartLineQuantityAdjustButton';
76
- import { CartLineSelectedOptions } from './CartLineSelectedOptions';
77
- import { CartLineAttributes } from './CartLineAttributes';
78
- export const CartLine = CartLineProvider;
79
- CartLine.Image = CartLineImage;
80
- CartLine.Price = CartLinePrice;
81
- CartLine.ProductTitle = CartLineProductTitle;
82
- CartLine.Quantity = CartLineQuantity;
83
- CartLine.QuantityAdjustButton = CartLineQuantityAdjustButton;
84
- CartLine.SelectedOptions = CartLineSelectedOptions;
85
- CartLine.Attributes = CartLineAttributes;
86
39
  export { Seo } from './Seo';
40
+ export { useNavigate } from '../hooks/useNavigate';
@@ -0,0 +1 @@
1
+ export declare const RSC_PATHNAME = "/__rsc";
@@ -0,0 +1 @@
1
+ export const RSC_PATHNAME = '/__rsc';
@@ -1,10 +1,10 @@
1
1
  import React, { Suspense, useState } from 'react';
2
2
  // @ts-ignore
3
3
  import { hydrateRoot } from 'react-dom';
4
- import { BrowserRouter } from 'react-router-dom';
5
4
  import { ErrorBoundary } from 'react-error-boundary';
6
5
  import { useServerResponse } from './framework/Hydration/rsc';
7
- import { ServerStateProvider, ServerStateRouter } from './client';
6
+ import { ServerStateProvider } from './client';
7
+ import { Router } from './foundation/Router/Router.client';
8
8
  const renderHydrogen = async (ClientWrapper) => {
9
9
  const root = document.getElementById('root');
10
10
  if (!root) {
@@ -23,8 +23,7 @@ function Content({ clientWrapper: ClientWrapper }) {
23
23
  });
24
24
  const response = useServerResponse(serverState);
25
25
  return (React.createElement(ServerStateProvider, { serverState: serverState, setServerState: setServerState },
26
- React.createElement(BrowserRouter, null,
27
- React.createElement(ServerStateRouter, null),
26
+ React.createElement(Router, null,
28
27
  React.createElement(ClientWrapper, null, response.readRoot()))));
29
28
  }
30
29
  function Error({ error }) {
@@ -9,6 +9,7 @@ import { ServerRequestProvider } from './foundation/ServerRequestProvider';
9
9
  import { getApiRouteFromURL, getApiRoutesFromPages } from './utilities/apiRoutes';
10
10
  import { ServerStateProvider } from './foundation/ServerStateProvider';
11
11
  import { ssrRenderToPipeableStream, ssrRenderToReadableStream, rscRenderToReadableStream, createFromReadableStream, } from './streaming.server';
12
+ import { RSC_PATHNAME } from './constants';
12
13
  /**
13
14
  * If a query is taking too long, or something else went wrong,
14
15
  * send back a response containing the Suspense fallback and rely
@@ -528,7 +529,7 @@ async function isStreamingSupported() {
528
529
  }
529
530
  function setupCurrentRequest(url, request) {
530
531
  const log = getLoggerFromContext(request);
531
- const state = url.pathname === '/react'
532
+ const state = url.pathname === RSC_PATHNAME
532
533
  ? JSON.parse(url.searchParams.get('state') || '{}')
533
534
  : { pathname: url.pathname, search: url.search };
534
535
  const componentResponse = new ServerComponentResponse();
@@ -1,13 +1,9 @@
1
1
  import React from 'react';
2
2
  import { Helmet as ActualHelmet, HelmetData, } from 'react-helmet-async';
3
- import { useServerRequest } from '../ServerRequestProvider';
4
- import { META_ENV_SSR } from '../../utilities/meta-env-ssr';
3
+ import { useEnvContext } from '../ssr-interop';
5
4
  const clientHelmetData = new HelmetData({});
6
5
  export function Helmet({ children, ...props }) {
7
- // @ts-ignore
8
- const helmetData = META_ENV_SSR
9
- ? useServerRequest().ctx.helmet
10
- : clientHelmetData;
6
+ const helmetData = useEnvContext((req) => req.ctx.helmet, clientHelmetData);
11
7
  return (
12
8
  // @ts-ignore
13
9
  React.createElement(ActualHelmet, { ...props, helmetData: helmetData }, children));
@@ -0,0 +1,12 @@
1
+ import { BrowserHistory, Location } from 'history';
2
+ import { FC } from 'react';
3
+ declare type RouterContextValue = {
4
+ history: BrowserHistory;
5
+ location: Location;
6
+ };
7
+ export declare const Router: FC<{
8
+ history?: BrowserHistory;
9
+ }>;
10
+ export declare function useRouter(): RouterContextValue;
11
+ export declare function useLocation(): Location;
12
+ export {};
@@ -0,0 +1,44 @@
1
+ import { createBrowserHistory } from 'history';
2
+ import React, { createContext, useContext, useMemo, useState, useEffect, } from 'react';
3
+ import { META_ENV_SSR } from '../ssr-interop';
4
+ import { useServerState } from '../useServerState';
5
+ const RouterContext = createContext({});
6
+ export const Router = ({ history: pHistory, children, }) => {
7
+ const history = useMemo(() => pHistory || createBrowserHistory(), [pHistory]);
8
+ const [firstLoad, setFirstLoad] = useState(true);
9
+ const [location, setLocation] = useState(history.location);
10
+ const { pending, setServerState } = useServerState();
11
+ useEffect(() => {
12
+ // The app has just loaded
13
+ if (firstLoad)
14
+ setFirstLoad(false);
15
+ // A navigation event has just happened
16
+ else if (!pending) {
17
+ window.scrollTo(0, 0);
18
+ }
19
+ }, [pending]);
20
+ useEffect(() => {
21
+ const unlisten = history.listen(({ location: newLocation }) => {
22
+ setServerState({
23
+ pathname: newLocation.pathname,
24
+ search: location.search || undefined,
25
+ });
26
+ setLocation(newLocation);
27
+ });
28
+ return () => unlisten();
29
+ }, [history]);
30
+ return (React.createElement(RouterContext.Provider, { value: {
31
+ history,
32
+ location,
33
+ } }, children));
34
+ };
35
+ export function useRouter() {
36
+ const router = useContext(RouterContext);
37
+ if (!router && META_ENV_SSR) {
38
+ throw new Error('useRouter must be used within a <Router> component');
39
+ }
40
+ return router;
41
+ }
42
+ export function useLocation() {
43
+ return useRouter().location;
44
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * This file is used for compatibility between browser and server environments.
3
+ * The browser loads this file as is, without leaking server logic.
4
+ * In the server, this file is transformed by Vite to inject server logic.
5
+ * NOTE: Do not remove SSR-prefixed comments in this file.
6
+ */
7
+ import type { ServerComponentRequest } from '../framework/Hydration/ServerComponentRequest.server';
8
+ export declare const META_ENV_SSR = false;
9
+ declare type ServerGetter<T> = (request: ServerComponentRequest) => T;
10
+ /**
11
+ * Isomorphic hook to access context data. It gives access to the current request
12
+ * when running on the server, and returns the provided client fallback in the browser.
13
+ * This can be used in server components (RSC) as a Context/Provider replacement. In client
14
+ * components, it uses the server getter in SSR and the client fallback in the browser.
15
+ * @param serverGetter - A function that gets the current server request and returns any
16
+ * desired request property. It only runs in the server (both in RSC and SSR).
17
+ * @param clientFallback - An optional raw value or a React.Context to be consumed that will be
18
+ * returned if the current environment is not the server. Note that, if this is a React.Context,
19
+ * there must be a React.Provider parent in the app tree.
20
+ * @returns A value retrieved from the current server request or a fallback value in the client.
21
+ * The returned type depends on what the server getter returns.
22
+ * @example
23
+ * ```js
24
+ * import {MyClientContext} from './my-client-react-context-provider';
25
+ * useEnvContext(req => req.ctx.myServerContext, MyClientContext)
26
+ * ```
27
+ */
28
+ export declare function useEnvContext<T>(serverGetter: ServerGetter<T>, clientFallback?: any): T;
29
+ export {};