diff --git a/.changeset/strong-swans-melt.md b/.changeset/strong-swans-melt.md
new file mode 100644
index 0000000000..981b341c09
--- /dev/null
+++ b/.changeset/strong-swans-melt.md
@@ -0,0 +1,5 @@
+---
+'@shopify/storefront-kit-react': patch
+---
+
+Added the `` and `` components, which have been a part of this package for awhile but weren't actually able to be used/imported.
diff --git a/README.md b/README.md
index d534f0a7aa..a8db3d5091 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
# React Storefront Kit
-React Storefront Kit is an unopionated and performant library of Shopify-specific commerce components, hooks, and utilities.
+React Storefront Kit is an unopionated and performant library of Shopify-specific commerce components, hooks, and utilities.
It accelerates the development of Shopify-powered custom storefronts by providing business logic, data processing, and state management on top of the [Storefront API](https://shopify.dev/api/storefront).
diff --git a/packages/react/docs/generated/generated_docs_data.json b/packages/react/docs/generated/generated_docs_data.json
index cdd35d1dcc..8cc62a7a6c 100644
--- a/packages/react/docs/generated/generated_docs_data.json
+++ b/packages/react/docs/generated/generated_docs_data.json
@@ -270,6 +270,255 @@
}
]
},
+ {
+ "name": "CartCheckoutButton",
+ "category": "components",
+ "isVisualComponent": false,
+ "related": [],
+ "description": "The `CartCheckoutButton` component renders a button that redirects to the checkout URL for the cart.\n Must be a descendent of a `CartProvider` component.\n ",
+ "type": "component",
+ "defaultExample": {
+ "description": "I am the default example",
+ "codeblock": {
+ "tabs": [
+ {
+ "title": "JavaScript",
+ "code": "import {CartCheckoutButton} from '@shopify/storefront-kit-react';\n\nexport default function ProductCartCheckoutButton() {\n return ;\n}\n",
+ "language": "jsx"
+ },
+ {
+ "title": "TypeScript",
+ "code": "import {CartCheckoutButton} from '@shopify/storefront-kit-react';\n\nexport default function ProductCartCheckoutButton() {\n return ;\n}\n",
+ "language": "tsx"
+ }
+ ],
+ "title": "Example code"
+ }
+ },
+ "definitions": [
+ {
+ "title": "Props",
+ "description": "",
+ "type": "CartCheckoutButtonProps",
+ "typeDefinitions": {
+ "CartCheckoutButtonProps": {
+ "filePath": "/CartCheckoutButton.tsx",
+ "syntaxKind": "TypeAliasDeclaration",
+ "name": "CartCheckoutButtonProps",
+ "value": "Omit, 'onClick'> & ChildrenProps",
+ "description": ""
+ },
+ "BaseButtonProps": {
+ "filePath": "/BaseButton.tsx",
+ "syntaxKind": "TypeAliasDeclaration",
+ "name": "BaseButtonProps",
+ "value": "CustomBaseButtonProps & Omit<\n React.ComponentPropsWithoutRef,\n keyof CustomBaseButtonProps\n >",
+ "description": ""
+ },
+ "CustomBaseButtonProps": {
+ "filePath": "/BaseButton.tsx",
+ "name": "CustomBaseButtonProps",
+ "description": "",
+ "members": [
+ {
+ "filePath": "/BaseButton.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "as",
+ "value": "AsType",
+ "description": "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.",
+ "isOptional": true
+ },
+ {
+ "filePath": "/BaseButton.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "children",
+ "value": "ReactNode",
+ "description": "Any ReactNode elements."
+ },
+ {
+ "filePath": "/BaseButton.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "onClick",
+ "value": "(event?: MouseEvent) => boolean | void",
+ "description": "Click event handler. Default behaviour triggers unless prevented",
+ "isOptional": true
+ },
+ {
+ "filePath": "/BaseButton.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "defaultOnClick",
+ "value": "(event?: MouseEvent) => boolean | void",
+ "description": "A default onClick behavior",
+ "isOptional": true
+ },
+ {
+ "filePath": "/BaseButton.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "buttonRef",
+ "value": "Ref",
+ "description": "A ref to the underlying button",
+ "isOptional": true
+ }
+ ],
+ "value": "export interface CustomBaseButtonProps {\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\n ) => void | boolean;\n /** A default onClick behavior */\n defaultOnClick?: (\n event?: React.MouseEvent\n ) => void | boolean;\n /** A ref to the underlying button */\n buttonRef?: Ref;\n}"
+ },
+ "ChildrenProps": {
+ "filePath": "/CartCheckoutButton.tsx",
+ "syntaxKind": "TypeAliasDeclaration",
+ "name": "ChildrenProps",
+ "value": "{\n /** A `ReactNode` element. */\n children: ReactNode;\n}",
+ "description": "",
+ "members": [
+ {
+ "filePath": "/CartCheckoutButton.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "children",
+ "value": "ReactNode",
+ "description": "A `ReactNode` element."
+ }
+ ]
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "CartCost",
+ "category": "components",
+ "isVisualComponent": false,
+ "related": [],
+ "description": "\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 ``\n ",
+ "type": "component",
+ "defaultExample": {
+ "description": "I am the default example",
+ "codeblock": {
+ "tabs": [
+ {
+ "title": "JavaScript",
+ "code": "import {CartCost} from '@shopify/storefront-kit-react';\n\nexport default function CartTotals() {\n return (\n <>\n \n Subtotal: \n
\n \n Tax: \n
\n \n Total: \n
\n >\n );\n}\n",
+ "language": "jsx"
+ },
+ {
+ "title": "TypeScript",
+ "code": "import {CartCost} from '@shopify/storefront-kit-react';\n\nexport default function CartTotals() {\n return (\n <>\n \n Subtotal: \n
\n \n Tax: \n
\n \n Total: \n
\n >\n );\n}\n",
+ "language": "tsx"
+ }
+ ],
+ "title": "Example code"
+ }
+ },
+ "definitions": [
+ {
+ "title": "Props",
+ "description": "",
+ "type": "CartCostProps",
+ "typeDefinitions": {
+ "CartCostProps": {
+ "filePath": "/CartCost.tsx",
+ "syntaxKind": "TypeAliasDeclaration",
+ "name": "CartCostProps",
+ "value": "Omit, 'data'> & CartCostPropsBase",
+ "description": ""
+ },
+ "CartCostPropsBase": {
+ "filePath": "/CartCost.tsx",
+ "name": "CartCostPropsBase",
+ "description": "",
+ "members": [
+ {
+ "filePath": "/CartCost.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "amountType",
+ "value": "\"total\" | \"subtotal\" | \"tax\" | \"duty\"",
+ "description": "A string type that defines the type of cost needed. Valid values: `total`, `subtotal`, `tax`, or `duty`.",
+ "isOptional": true
+ },
+ {
+ "filePath": "/CartCost.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "children",
+ "value": "ReactNode",
+ "description": "Any `ReactNode` elements.",
+ "isOptional": true
+ }
+ ],
+ "value": "interface 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}"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "name": "CartLinePrice",
+ "category": "components",
+ "isVisualComponent": false,
+ "related": [
+ {
+ "name": "Money",
+ "type": "component",
+ "url": "/api/react-storefront-kit/components/money"
+ }
+ ],
+ "description": "\n The `CartLinePrice` component renders a `Money` component for the cart line merchandise's price or compare at price.\n ",
+ "type": "component",
+ "defaultExample": {
+ "description": "I am the default example",
+ "codeblock": {
+ "tabs": [
+ {
+ "title": "JavaScript",
+ "code": "import {CartLinePrice} from '@shopify/storefront-kit-react';\n\nexport default function ProductCartLinePrice({cartLine}) {\n return ;\n}\n",
+ "language": "jsx"
+ },
+ {
+ "title": "TypeScript",
+ "code": "import {CartLinePrice} from '@shopify/storefront-kit-react';\nimport type {CartLine} from '@shopify/storefront-kit-react/storefront-api-types';\n\nexport default function ProductCartLinePrice({cartLine}: {cartLine: CartLine}) {\n return ;\n}\n",
+ "language": "tsx"
+ }
+ ],
+ "title": "Example code"
+ }
+ },
+ "definitions": [
+ {
+ "title": "Props",
+ "description": "",
+ "type": "CartLinePriceProps",
+ "typeDefinitions": {
+ "CartLinePriceProps": {
+ "filePath": "/CartLinePrice.tsx",
+ "syntaxKind": "TypeAliasDeclaration",
+ "name": "CartLinePriceProps",
+ "value": "Omit, 'data'> & CartLinePricePropsBase",
+ "description": ""
+ },
+ "CartLinePricePropsBase": {
+ "filePath": "/CartLinePrice.tsx",
+ "name": "CartLinePricePropsBase",
+ "description": "",
+ "members": [
+ {
+ "filePath": "/CartLinePrice.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "data",
+ "value": "PartialObjectDeep",
+ "description": "A [CartLine object](https://shopify.dev/api/storefront/reference/objects/CartLine)."
+ },
+ {
+ "filePath": "/CartLinePrice.tsx",
+ "syntaxKind": "PropertySignature",
+ "name": "priceType",
+ "value": "\"regular\" | \"compareAt\"",
+ "description": "The type of price. Valid values:`regular` (default) or `compareAt`.",
+ "isOptional": true
+ }
+ ],
+ "value": "interface CartLinePricePropsBase {\n /** A [CartLine object](https://shopify.dev/api/storefront/reference/objects/CartLine). */\n data: PartialDeep;\n /** The type of price. Valid values:`regular` (default) or `compareAt`. */\n priceType?: 'regular' | 'compareAt';\n}"
+ }
+ }
+ }
+ ]
+ },
{
"name": "ExternalVideo",
"category": "components",
diff --git a/packages/react/src/CartCheckoutButton.doc.ts b/packages/react/src/CartCheckoutButton.doc.ts
new file mode 100644
index 0000000000..97018020fc
--- /dev/null
+++ b/packages/react/src/CartCheckoutButton.doc.ts
@@ -0,0 +1,39 @@
+import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs';
+
+const data: ReferenceEntityTemplateSchema = {
+ name: 'CartCheckoutButton',
+ category: 'components',
+ isVisualComponent: false,
+ related: [],
+ description: `The \`CartCheckoutButton\` component renders a button that redirects to the checkout URL for the cart.
+ Must be a descendent of a \`CartProvider\` component.
+ `,
+ type: 'component',
+ defaultExample: {
+ description: 'I am the default example',
+ codeblock: {
+ tabs: [
+ {
+ title: 'JavaScript',
+ code: './CartCheckoutButton.example.jsx',
+ language: 'jsx',
+ },
+ {
+ title: 'TypeScript',
+ code: './CartCheckoutButton.example.tsx',
+ language: 'tsx',
+ },
+ ],
+ title: 'Example code',
+ },
+ },
+ definitions: [
+ {
+ title: 'Props',
+ type: 'CartCheckoutButtonProps',
+ description: '',
+ },
+ ],
+};
+
+export default data;
diff --git a/packages/react/src/CartCheckoutButton.example.jsx b/packages/react/src/CartCheckoutButton.example.jsx
new file mode 100644
index 0000000000..f5abdc91be
--- /dev/null
+++ b/packages/react/src/CartCheckoutButton.example.jsx
@@ -0,0 +1,5 @@
+import {CartCheckoutButton} from '@shopify/storefront-kit-react';
+
+export default function ProductCartCheckoutButton() {
+ return ;
+}
diff --git a/packages/react/src/CartCheckoutButton.example.tsx b/packages/react/src/CartCheckoutButton.example.tsx
new file mode 100644
index 0000000000..f5abdc91be
--- /dev/null
+++ b/packages/react/src/CartCheckoutButton.example.tsx
@@ -0,0 +1,5 @@
+import {CartCheckoutButton} from '@shopify/storefront-kit-react';
+
+export default function ProductCartCheckoutButton() {
+ return ;
+}
diff --git a/packages/react/src/CartCheckoutButton.tsx b/packages/react/src/CartCheckoutButton.tsx
index 2462d83a8d..58a97a66a3 100644
--- a/packages/react/src/CartCheckoutButton.tsx
+++ b/packages/react/src/CartCheckoutButton.tsx
@@ -2,18 +2,18 @@ import {ReactNode, useEffect, useState} from 'react';
import {useCart} from './CartProvider.js';
import {BaseButton, BaseButtonProps} from './BaseButton.js';
-type PropsWeControl = 'onClick';
+type ChildrenProps = {
+ /** A `ReactNode` element. */
+ children: ReactNode;
+};
+type CartCheckoutButtonProps = Omit, 'onClick'> &
+ ChildrenProps;
/**
* The `CartCheckoutButton` component renders a button that redirects to the checkout URL for the cart.
* It must be a descendent of a `CartProvider` component.
*/
-export function CartCheckoutButton(
- props: Omit, PropsWeControl> & {
- /** A `ReactNode` element. */
- children: ReactNode;
- }
-) {
+export function CartCheckoutButton(props: CartCheckoutButtonProps) {
const [requestedCheckout, setRequestedCheckout] = useState(false);
const {status, checkoutUrl} = useCart();
const {children, ...passthroughProps} = props;
diff --git a/packages/react/src/CartCost.doc.ts b/packages/react/src/CartCost.doc.ts
new file mode 100644
index 0000000000..c6a5a8c936
--- /dev/null
+++ b/packages/react/src/CartCost.doc.ts
@@ -0,0 +1,41 @@
+import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs';
+
+const data: ReferenceEntityTemplateSchema = {
+ name: 'CartCost',
+ category: 'components',
+ isVisualComponent: false,
+ related: [],
+ description: `
+ The \`CartCost\` component renders a \`Money\` component with the cost associated with the \`amountType\` prop.
+ If no \`amountType\` prop is specified, then it defaults to \`totalAmount\`.
+ Depends on \`useCart()\` and must be a child of \`\`
+ `,
+ type: 'component',
+ defaultExample: {
+ description: 'I am the default example',
+ codeblock: {
+ tabs: [
+ {
+ title: 'JavaScript',
+ code: './CartCost.example.jsx',
+ language: 'jsx',
+ },
+ {
+ title: 'TypeScript',
+ code: './CartCost.example.tsx',
+ language: 'tsx',
+ },
+ ],
+ title: 'Example code',
+ },
+ },
+ definitions: [
+ {
+ title: 'Props',
+ type: 'CartCostProps',
+ description: '',
+ },
+ ],
+};
+
+export default data;
diff --git a/packages/react/src/CartCost.example.jsx b/packages/react/src/CartCost.example.jsx
new file mode 100644
index 0000000000..ecf99333b5
--- /dev/null
+++ b/packages/react/src/CartCost.example.jsx
@@ -0,0 +1,17 @@
+import {CartCost} from '@shopify/storefront-kit-react';
+
+export default function CartTotals() {
+ return (
+ <>
+
+ Subtotal:
+
+
+ Tax:
+
+
+ Total:
+
+ >
+ );
+}
diff --git a/packages/react/src/CartCost.example.tsx b/packages/react/src/CartCost.example.tsx
new file mode 100644
index 0000000000..ecf99333b5
--- /dev/null
+++ b/packages/react/src/CartCost.example.tsx
@@ -0,0 +1,17 @@
+import {CartCost} from '@shopify/storefront-kit-react';
+
+export default function CartTotals() {
+ return (
+ <>
+
+ Subtotal:
+
+
+ Tax:
+
+
+ Total:
+
+ >
+ );
+}
diff --git a/packages/react/src/CartCost.tsx b/packages/react/src/CartCost.tsx
index 9fd40f3372..e4cec181d6 100644
--- a/packages/react/src/CartCost.tsx
+++ b/packages/react/src/CartCost.tsx
@@ -1,21 +1,22 @@
import {Money} from './Money.js';
import {useCart} from './CartProvider.js';
-export interface CartCostProps {
+interface CartCostPropsBase {
/** A string type that defines the type of cost needed. Valid values: `total`, `subtotal`, `tax`, or `duty`. */
amountType?: 'total' | 'subtotal' | 'tax' | 'duty';
/** Any `ReactNode` elements. */
children?: React.ReactNode;
}
+type CartCostProps = Omit, 'data'> &
+ CartCostPropsBase;
+
/**
- * The `CartCost` component renders a `Money` component with the
- * cost associated with the `amountType` prop. If no `amountType` prop is specified, then it defaults to `totalAmount`.
-Depends on `useCart()` and must be a child of ``
+ * The `CartCost` component renders a `Money` component with the cost associated with the `amountType` prop.
+ * If no `amountType` prop is specified, then it defaults to `totalAmount`.
+ * Depends on `useCart()` and must be a child of ``
*/
-export function CartCost(
- props: Omit, 'data'> & CartCostProps
-) {
+export function CartCost(props: CartCostProps) {
const {cost} = useCart();
const {amountType = 'total', children, ...passthroughProps} = props;
let amount;
diff --git a/packages/react/src/CartLinePrice.doc.ts b/packages/react/src/CartLinePrice.doc.ts
new file mode 100644
index 0000000000..87b7e5bf1a
--- /dev/null
+++ b/packages/react/src/CartLinePrice.doc.ts
@@ -0,0 +1,45 @@
+import {ReferenceEntityTemplateSchema} from '@shopify/generate-docs';
+
+const data: ReferenceEntityTemplateSchema = {
+ name: 'CartLinePrice',
+ category: 'components',
+ isVisualComponent: false,
+ related: [
+ {
+ name: 'Money',
+ type: 'component',
+ url: '/api/react-storefront-kit/components/money',
+ },
+ ],
+ description: `
+ The \`CartLinePrice\` component renders a \`Money\` component for the cart line merchandise's price or compare at price.
+ `,
+ type: 'component',
+ defaultExample: {
+ description: 'I am the default example',
+ codeblock: {
+ tabs: [
+ {
+ title: 'JavaScript',
+ code: './CartLinePrice.example.jsx',
+ language: 'jsx',
+ },
+ {
+ title: 'TypeScript',
+ code: './CartLinePrice.example.tsx',
+ language: 'tsx',
+ },
+ ],
+ title: 'Example code',
+ },
+ },
+ definitions: [
+ {
+ title: 'Props',
+ type: 'CartLinePriceProps',
+ description: '',
+ },
+ ],
+};
+
+export default data;
diff --git a/packages/react/src/CartLinePrice.example.jsx b/packages/react/src/CartLinePrice.example.jsx
new file mode 100644
index 0000000000..da854a2376
--- /dev/null
+++ b/packages/react/src/CartLinePrice.example.jsx
@@ -0,0 +1,5 @@
+import {CartLinePrice} from '@shopify/storefront-kit-react';
+
+export default function ProductCartLinePrice({cartLine}) {
+ return ;
+}
diff --git a/packages/react/src/CartLinePrice.example.tsx b/packages/react/src/CartLinePrice.example.tsx
new file mode 100644
index 0000000000..4d26af536f
--- /dev/null
+++ b/packages/react/src/CartLinePrice.example.tsx
@@ -0,0 +1,6 @@
+import {CartLinePrice} from '@shopify/storefront-kit-react';
+import type {CartLine} from '@shopify/storefront-kit-react/storefront-api-types';
+
+export default function ProductCartLinePrice({cartLine}: {cartLine: CartLine}) {
+ return ;
+}
diff --git a/packages/react/src/CartLinePrice.tsx b/packages/react/src/CartLinePrice.tsx
index 54f8d1a53b..536c576ec4 100644
--- a/packages/react/src/CartLinePrice.tsx
+++ b/packages/react/src/CartLinePrice.tsx
@@ -2,20 +2,20 @@ import {Money} from './Money.js';
import {CartLine} from './storefront-api-types.js';
import {PartialDeep} from 'type-fest';
-interface CartLinePriceProps {
+interface CartLinePricePropsBase {
/** A [CartLine object](https://shopify.dev/api/storefront/reference/objects/CartLine). */
data: PartialDeep;
/** The type of price. Valid values:`regular` (default) or `compareAt`. */
priceType?: 'regular' | 'compareAt';
}
+type CartLinePriceProps = Omit, 'data'> &
+ CartLinePricePropsBase;
+
/**
- * The `CartLinePrice` component renders a `Money` component for the cart line merchandise's price or
- * compare at price.
+ * The `CartLinePrice` component renders a `Money` component for the cart line merchandise's price or compare at price.
*/
-export function CartLinePrice(
- props: Omit, 'data'> & CartLinePriceProps
-) {
+export function CartLinePrice(props: CartLinePriceProps) {
const {data: cartLine, priceType = 'regular', ...passthroughProps} = props;
if (cartLine == null) {
diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts
index 7483c2762e..6d0e5da60e 100644
--- a/packages/react/src/index.ts
+++ b/packages/react/src/index.ts
@@ -1,4 +1,21 @@
export {AddToCartButton} from './AddToCartButton.js';
+export {
+ AnalyticsEventName,
+ AnalyticsPageType,
+ ShopifyAppSource,
+} from './analytics-constants.js';
+export type {
+ ClientBrowserParameters,
+ ShopifyPageViewPayload,
+ ShopifyPageView,
+ ShopifyAddToCartPayload,
+ ShopifyAddToCart,
+ ShopifyAnalyticsPayload,
+ ShopifyAnalytics,
+ ShopifyAnalyticsProduct,
+ ShopifyCookies,
+} from './analytics-types.js';
+export {sendShopifyAnalytics, getClientBrowserParameters} from './analytics.js';
export {BuyNowButton} from './BuyNowButton.js';
export type {
CartState,
@@ -8,8 +25,11 @@ export type {
CartAction,
} from './cart-types.js';
export {CartCheckoutButton} from './CartCheckoutButton.js';
+export {CartCost} from './CartCost.js';
+export {CartLinePrice} from './CartLinePrice.js';
export {CartProvider, useCart} from './CartProvider.js';
export {storefrontApiCustomScalars} from './codegen.helpers.js';
+export {getShopifyCookies} from './cookies-utils.js';
export {ExternalVideo} from './ExternalVideo.js';
export {flattenConnection} from './flatten-connection.js';
export {Image} from './Image.js';
@@ -30,23 +50,5 @@ export type {
} from './storefront-api-response.types.js';
export {createStorefrontClient} from './storefront-client.js';
export {useMoney} from './useMoney.js';
-export {Video} from './Video.js';
-export {
- AnalyticsEventName,
- AnalyticsPageType,
- ShopifyAppSource,
-} from './analytics-constants.js';
-export type {
- ClientBrowserParameters,
- ShopifyPageViewPayload,
- ShopifyPageView,
- ShopifyAddToCartPayload,
- ShopifyAddToCart,
- ShopifyAnalyticsPayload,
- ShopifyAnalytics,
- ShopifyAnalyticsProduct,
- ShopifyCookies,
-} from './analytics-types.js';
export {useShopifyCookies} from './useShopifyCookies.js';
-export {getShopifyCookies} from './cookies-utils.js';
-export {sendShopifyAnalytics, getClientBrowserParameters} from './analytics.js';
+export {Video} from './Video.js';