@shopify/hydrogen-react 0.0.0-next-a6c2b91 → 0.0.0-next-6094330
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-dev/AddToCartButton.mjs.map +1 -1
- package/dist/browser-dev/BaseButton.mjs.map +1 -1
- package/dist/browser-dev/BuyNowButton.mjs.map +1 -1
- package/dist/browser-dev/CartCheckoutButton.mjs.map +1 -1
- package/dist/browser-dev/CartProvider.mjs.map +1 -1
- package/dist/browser-dev/ExternalVideo.mjs.map +1 -1
- package/dist/browser-dev/Image.mjs.map +1 -1
- package/dist/browser-dev/MediaFile.mjs +1 -1
- package/dist/browser-dev/MediaFile.mjs.map +1 -1
- package/dist/browser-dev/Metafield.mjs.map +1 -1
- package/dist/browser-dev/ModelViewer.mjs.map +1 -1
- package/dist/browser-dev/Money.mjs.map +1 -1
- package/dist/browser-dev/ProductPrice.mjs.map +1 -1
- package/dist/browser-dev/ProductProvider.mjs.map +1 -1
- package/dist/browser-dev/ShopPayButton.mjs.map +1 -1
- package/dist/browser-dev/ShopifyProvider.mjs.map +1 -1
- package/dist/browser-dev/Video.mjs.map +1 -1
- package/dist/browser-dev/cart-hooks.mjs.map +1 -1
- package/dist/browser-dev/load-script.mjs.map +1 -1
- package/dist/browser-dev/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/browser-dev/useCartActions.mjs.map +1 -1
- package/dist/browser-dev/useMoney.mjs.map +1 -1
- package/dist/browser-prod/AddToCartButton.mjs.map +1 -1
- package/dist/browser-prod/BaseButton.mjs.map +1 -1
- package/dist/browser-prod/BuyNowButton.mjs.map +1 -1
- package/dist/browser-prod/CartCheckoutButton.mjs.map +1 -1
- package/dist/browser-prod/CartProvider.mjs.map +1 -1
- package/dist/browser-prod/ExternalVideo.mjs.map +1 -1
- package/dist/browser-prod/Image.mjs.map +1 -1
- package/dist/browser-prod/MediaFile.mjs +2 -2
- package/dist/browser-prod/MediaFile.mjs.map +1 -1
- package/dist/browser-prod/Metafield.mjs.map +1 -1
- package/dist/browser-prod/ModelViewer.mjs.map +1 -1
- package/dist/browser-prod/Money.mjs.map +1 -1
- package/dist/browser-prod/ProductPrice.mjs.map +1 -1
- package/dist/browser-prod/ProductProvider.mjs.map +1 -1
- package/dist/browser-prod/ShopPayButton.mjs.map +1 -1
- package/dist/browser-prod/ShopifyProvider.mjs.map +1 -1
- package/dist/browser-prod/Video.mjs.map +1 -1
- package/dist/browser-prod/cart-hooks.mjs.map +1 -1
- package/dist/browser-prod/load-script.mjs.map +1 -1
- package/dist/browser-prod/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/browser-prod/useCartActions.mjs.map +1 -1
- package/dist/browser-prod/useMoney.mjs.map +1 -1
- package/dist/node-dev/AddToCartButton.js.map +1 -1
- package/dist/node-dev/AddToCartButton.mjs.map +1 -1
- package/dist/node-dev/BaseButton.js.map +1 -1
- package/dist/node-dev/BaseButton.mjs.map +1 -1
- package/dist/node-dev/BuyNowButton.js.map +1 -1
- package/dist/node-dev/BuyNowButton.mjs.map +1 -1
- package/dist/node-dev/CartCheckoutButton.js.map +1 -1
- package/dist/node-dev/CartCheckoutButton.mjs.map +1 -1
- package/dist/node-dev/CartProvider.js.map +1 -1
- package/dist/node-dev/CartProvider.mjs.map +1 -1
- package/dist/node-dev/ExternalVideo.js.map +1 -1
- package/dist/node-dev/ExternalVideo.mjs.map +1 -1
- package/dist/node-dev/Image.js.map +1 -1
- package/dist/node-dev/Image.mjs.map +1 -1
- package/dist/node-dev/MediaFile.js +1 -1
- package/dist/node-dev/MediaFile.js.map +1 -1
- package/dist/node-dev/MediaFile.mjs +1 -1
- package/dist/node-dev/MediaFile.mjs.map +1 -1
- package/dist/node-dev/Metafield.js.map +1 -1
- package/dist/node-dev/Metafield.mjs.map +1 -1
- package/dist/node-dev/ModelViewer.js.map +1 -1
- package/dist/node-dev/ModelViewer.mjs.map +1 -1
- package/dist/node-dev/Money.js.map +1 -1
- package/dist/node-dev/Money.mjs.map +1 -1
- package/dist/node-dev/ProductPrice.js.map +1 -1
- package/dist/node-dev/ProductPrice.mjs.map +1 -1
- package/dist/node-dev/ProductProvider.js.map +1 -1
- package/dist/node-dev/ProductProvider.mjs.map +1 -1
- package/dist/node-dev/ShopPayButton.js.map +1 -1
- package/dist/node-dev/ShopPayButton.mjs.map +1 -1
- package/dist/node-dev/ShopifyProvider.js.map +1 -1
- package/dist/node-dev/ShopifyProvider.mjs.map +1 -1
- package/dist/node-dev/Video.js.map +1 -1
- package/dist/node-dev/Video.mjs.map +1 -1
- package/dist/node-dev/cart-hooks.js.map +1 -1
- package/dist/node-dev/cart-hooks.mjs.map +1 -1
- package/dist/node-dev/load-script.js.map +1 -1
- package/dist/node-dev/load-script.mjs.map +1 -1
- package/dist/node-dev/useCartAPIStateMachine.js.map +1 -1
- package/dist/node-dev/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/node-dev/useCartActions.js.map +1 -1
- package/dist/node-dev/useCartActions.mjs.map +1 -1
- package/dist/node-dev/useMoney.js.map +1 -1
- package/dist/node-dev/useMoney.mjs.map +1 -1
- package/dist/node-prod/AddToCartButton.js.map +1 -1
- package/dist/node-prod/AddToCartButton.mjs.map +1 -1
- package/dist/node-prod/BaseButton.js.map +1 -1
- package/dist/node-prod/BaseButton.mjs.map +1 -1
- package/dist/node-prod/BuyNowButton.js.map +1 -1
- package/dist/node-prod/BuyNowButton.mjs.map +1 -1
- package/dist/node-prod/CartCheckoutButton.js.map +1 -1
- package/dist/node-prod/CartCheckoutButton.mjs.map +1 -1
- package/dist/node-prod/CartProvider.js.map +1 -1
- package/dist/node-prod/CartProvider.mjs.map +1 -1
- package/dist/node-prod/ExternalVideo.js.map +1 -1
- package/dist/node-prod/ExternalVideo.mjs.map +1 -1
- package/dist/node-prod/Image.js.map +1 -1
- package/dist/node-prod/Image.mjs.map +1 -1
- package/dist/node-prod/MediaFile.js +2 -2
- package/dist/node-prod/MediaFile.js.map +1 -1
- package/dist/node-prod/MediaFile.mjs +2 -2
- package/dist/node-prod/MediaFile.mjs.map +1 -1
- package/dist/node-prod/Metafield.js.map +1 -1
- package/dist/node-prod/Metafield.mjs.map +1 -1
- package/dist/node-prod/ModelViewer.js.map +1 -1
- package/dist/node-prod/ModelViewer.mjs.map +1 -1
- package/dist/node-prod/Money.js.map +1 -1
- package/dist/node-prod/Money.mjs.map +1 -1
- package/dist/node-prod/ProductPrice.js.map +1 -1
- package/dist/node-prod/ProductPrice.mjs.map +1 -1
- package/dist/node-prod/ProductProvider.js.map +1 -1
- package/dist/node-prod/ProductProvider.mjs.map +1 -1
- package/dist/node-prod/ShopPayButton.js.map +1 -1
- package/dist/node-prod/ShopPayButton.mjs.map +1 -1
- package/dist/node-prod/ShopifyProvider.js.map +1 -1
- package/dist/node-prod/ShopifyProvider.mjs.map +1 -1
- package/dist/node-prod/Video.js.map +1 -1
- package/dist/node-prod/Video.mjs.map +1 -1
- package/dist/node-prod/cart-hooks.js.map +1 -1
- package/dist/node-prod/cart-hooks.mjs.map +1 -1
- package/dist/node-prod/load-script.js.map +1 -1
- package/dist/node-prod/load-script.mjs.map +1 -1
- package/dist/node-prod/useCartAPIStateMachine.js.map +1 -1
- package/dist/node-prod/useCartAPIStateMachine.mjs.map +1 -1
- package/dist/node-prod/useCartActions.js.map +1 -1
- package/dist/node-prod/useCartActions.mjs.map +1 -1
- package/dist/node-prod/useMoney.js.map +1 -1
- package/dist/node-prod/useMoney.mjs.map +1 -1
- package/dist/types/BaseButton.d.ts +1 -1
- package/dist/types/CartCheckoutButton.d.ts +1 -1
- package/dist/types/ExternalVideo.d.ts +3 -3
- package/dist/types/Image.d.ts +4 -4
- package/dist/types/MediaFile.d.ts +5 -5
- package/dist/types/Metafield.d.ts +2 -2
- package/dist/types/ModelViewer.d.ts +2 -2
- package/dist/types/Money.d.ts +1 -1
- package/dist/types/ProductProvider.d.ts +3 -3
- package/dist/types/ShopPayButton.d.ts +1 -1
- package/dist/types/ShopifyProvider.d.ts +2 -2
- package/dist/types/cart-types.d.ts +21 -21
- package/dist/types/image-size.d.ts +3 -3
- package/dist/types/load-script.d.ts +2 -2
- package/dist/types/metafield-parser.d.ts +27 -27
- package/dist/types/storefront-api-response.types.d.ts +6 -6
- package/dist/types/storefront-client.d.ts +3 -3
- package/dist/types/useCartActions.d.ts +1 -1
- package/dist/types/useMoney.d.ts +1 -1
- package/dist/umd/hydrogen-react.dev.js +1 -1
- package/dist/umd/hydrogen-react.dev.js.map +1 -1
- package/dist/umd/hydrogen-react.prod.js +1 -1
- package/dist/umd/hydrogen-react.prod.js.map +1 -1
- package/package.json +10 -10
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Money.mjs","sources":["../../src/Money.tsx"],"sourcesContent":["import {type ReactNode} from 'react';\nimport {useMoney} from './useMoney.js';\nimport type {MoneyV2, UnitPriceMeasurement} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\ninterface CustomProps<ComponentGeneric extends React.ElementType> {\n /** An HTML tag or React Component to be rendered as the base element wrapper. The default is `div`. */\n as?: ComponentGeneric;\n /** An object with fields that correspond to the Storefront API's [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2). */\n data: PartialDeep<MoneyV2, {recurseIntoArrays: true}>;\n /** Whether to remove the currency symbol from the output. */\n withoutCurrency?: boolean;\n /** Whether to remove trailing zeros (fractional money) from the output. */\n withoutTrailingZeros?: boolean;\n /** A [UnitPriceMeasurement object](https://shopify.dev/api/storefront/latest/objects/unitpricemeasurement). */\n measurement?: PartialDeep<UnitPriceMeasurement, {recurseIntoArrays: true}>;\n /** Customizes the separator between the money output and the measurement output. Used with the `measurement` prop. Defaults to `'/'`. */\n measurementSeparator?: ReactNode;\n}\n\n// This article helps understand the typing here https://www.benmvp.com/blog/polymorphic-react-components-typescript/ Ben is the best :)\nexport type MoneyProps<ComponentGeneric extends React.ElementType> =\n CustomProps<ComponentGeneric> &\n Omit<\n React.ComponentPropsWithoutRef<ComponentGeneric>,\n keyof CustomProps<ComponentGeneric>\n >;\n\n/**\n * The `Money` component renders a string of the Storefront API's\n * [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the\n * `locale` in the `ShopifyProvider` component.\n */\nexport function Money<ComponentGeneric extends React.ElementType>({\n data,\n as,\n withoutCurrency,\n withoutTrailingZeros,\n measurement,\n measurementSeparator = '/',\n ...passthroughProps\n}: MoneyProps<ComponentGeneric>) {\n if (!isMoney(data)) {\n throw new Error(\n `<Money/> needs a valid 'data' prop that has 'amount' and 'currencyCode'`\n );\n }\n const moneyObject = useMoney(data);\n const Wrapper = as ?? 'div';\n\n let output = moneyObject.localizedString;\n\n if (withoutCurrency || withoutTrailingZeros) {\n if (withoutCurrency && !withoutTrailingZeros) {\n output = moneyObject.amount;\n } else if (!withoutCurrency && withoutTrailingZeros) {\n output = moneyObject.withoutTrailingZeros;\n } else {\n // both\n output = moneyObject.withoutTrailingZerosAndCurrency;\n }\n }\n\n return (\n <Wrapper {...passthroughProps}>\n {output}\n {measurement && measurement.referenceUnit && (\n <>\n {measurementSeparator}\n {measurement.referenceUnit}\n </>\n )}\n </Wrapper>\n );\n}\n\n// required in order to narrow the money object down and make TS happy\nfunction isMoney(\n maybeMoney: PartialDeep<MoneyV2, {recurseIntoArrays: true}>\n): maybeMoney is MoneyV2 {\n return (\n typeof maybeMoney.amount === 'string' &&\n !!maybeMoney.amount &&\n typeof maybeMoney.currencyCode === 'string' &&\n !!maybeMoney.currencyCode\n );\n}\n"],"names":["Money","data","as","withoutCurrency","withoutTrailingZeros","measurement","measurementSeparator","passthroughProps","isMoney","Error","moneyObject","useMoney","Wrapper","output","localizedString","amount","withoutTrailingZerosAndCurrency","referenceUnit","_Fragment","maybeMoney","currencyCode"],"mappings":";;AAiCO,SAASA,MAAkD;AAAA,EAChEC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC,uBAAuB;AAAA,KACpBC;
|
|
1
|
+
{"version":3,"file":"Money.mjs","sources":["../../src/Money.tsx"],"sourcesContent":["import {type ReactNode} from 'react';\nimport {useMoney} from './useMoney.js';\nimport type {MoneyV2, UnitPriceMeasurement} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\ninterface CustomProps<ComponentGeneric extends React.ElementType> {\n /** An HTML tag or React Component to be rendered as the base element wrapper. The default is `div`. */\n as?: ComponentGeneric;\n /** An object with fields that correspond to the Storefront API's [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2). */\n data: PartialDeep<MoneyV2, {recurseIntoArrays: true}>;\n /** Whether to remove the currency symbol from the output. */\n withoutCurrency?: boolean;\n /** Whether to remove trailing zeros (fractional money) from the output. */\n withoutTrailingZeros?: boolean;\n /** A [UnitPriceMeasurement object](https://shopify.dev/api/storefront/latest/objects/unitpricemeasurement). */\n measurement?: PartialDeep<UnitPriceMeasurement, {recurseIntoArrays: true}>;\n /** Customizes the separator between the money output and the measurement output. Used with the `measurement` prop. Defaults to `'/'`. */\n measurementSeparator?: ReactNode;\n}\n\n// This article helps understand the typing here https://www.benmvp.com/blog/polymorphic-react-components-typescript/ Ben is the best :)\nexport type MoneyProps<ComponentGeneric extends React.ElementType> =\n CustomProps<ComponentGeneric> &\n Omit<\n React.ComponentPropsWithoutRef<ComponentGeneric>,\n keyof CustomProps<ComponentGeneric>\n >;\n\n/**\n * The `Money` component renders a string of the Storefront API's\n * [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) according to the\n * `locale` in the `ShopifyProvider` component.\n */\nexport function Money<ComponentGeneric extends React.ElementType>({\n data,\n as,\n withoutCurrency,\n withoutTrailingZeros,\n measurement,\n measurementSeparator = '/',\n ...passthroughProps\n}: MoneyProps<ComponentGeneric>) {\n if (!isMoney(data)) {\n throw new Error(\n `<Money/> needs a valid 'data' prop that has 'amount' and 'currencyCode'`\n );\n }\n const moneyObject = useMoney(data);\n const Wrapper = as ?? 'div';\n\n let output = moneyObject.localizedString;\n\n if (withoutCurrency || withoutTrailingZeros) {\n if (withoutCurrency && !withoutTrailingZeros) {\n output = moneyObject.amount;\n } else if (!withoutCurrency && withoutTrailingZeros) {\n output = moneyObject.withoutTrailingZeros;\n } else {\n // both\n output = moneyObject.withoutTrailingZerosAndCurrency;\n }\n }\n\n return (\n <Wrapper {...passthroughProps}>\n {output}\n {measurement && measurement.referenceUnit && (\n <>\n {measurementSeparator}\n {measurement.referenceUnit}\n </>\n )}\n </Wrapper>\n );\n}\n\n// required in order to narrow the money object down and make TS happy\nfunction isMoney(\n maybeMoney: PartialDeep<MoneyV2, {recurseIntoArrays: true}>\n): maybeMoney is MoneyV2 {\n return (\n typeof maybeMoney.amount === 'string' &&\n !!maybeMoney.amount &&\n typeof maybeMoney.currencyCode === 'string' &&\n !!maybeMoney.currencyCode\n );\n}\n"],"names":["Money","data","as","withoutCurrency","withoutTrailingZeros","measurement","measurementSeparator","passthroughProps","isMoney","Error","moneyObject","useMoney","Wrapper","output","localizedString","amount","withoutTrailingZerosAndCurrency","referenceUnit","_Fragment","maybeMoney","currencyCode"],"mappings":";;AAiCO,SAASA,MAAkD;AAAA,EAChEC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC,uBAAuB;AAAA,KACpBC;AACyB,GAAG;AAC3B,MAAA,CAACC,QAAQP,IAAI,GAAG;AACZ,UAAA,IAAIQ,MACP,yEAAwE;AAAA,EAE7E;AACMC,QAAAA,cAAcC,SAASV,IAAI;AACjC,QAAMW,UAAUV,kBAAM;AAEtB,MAAIW,SAASH,YAAYI;AAEzB,MAAIX,mBAAmBC,sBAAsB;AACvCD,QAAAA,mBAAmB,CAACC,sBAAsB;AAC5CS,eAASH,YAAYK;AAAAA,IAAAA,WACZ,CAACZ,mBAAmBC,sBAAsB;AACnDS,eAASH,YAAYN;AAAAA,IAAAA,OAChB;AAELS,eAASH,YAAYM;AAAAA,IACvB;AAAA,EACF;AAEA,8BACG,SAAO;AAAA,IAAA,GAAKT;AAAAA,IAAgB,UAAA,CAC1BM,QACAR,eAAeA,YAAYY,sCAC1BC,UAAA;AAAA,MAAA,UAAA,CACGZ,sBACAD,YAAYY,aAAa;AAAA,IAAA,CAE7B,CAAA;AAAA,EAAA,CACO;AAEd;AAGA,SAAST,QACPW,YACuB;AACvB,SACE,OAAOA,WAAWJ,WAAW,YAC7B,CAAC,CAACI,WAAWJ,UACb,OAAOI,WAAWC,iBAAiB,YACnC,CAAC,CAACD,WAAWC;AAEjB;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductPrice.mjs","sources":["../../src/ProductPrice.tsx"],"sourcesContent":["import type {\n MoneyV2,\n UnitPriceMeasurement,\n Product,\n} from './storefront-api-types.js';\nimport {Money, type MoneyProps} from './Money.js';\nimport type {PartialDeep} from 'type-fest';\nimport {flattenConnection} from './flatten-connection.js';\n\nexport interface ProductPriceProps {\n /** A [Product object](https://shopify.dev/api/storefront/reference/products/product). */\n data: PartialDeep<Product, {recurseIntoArrays: true}>;\n /** The type of price. Valid values: `regular` (default) or `compareAt`. */\n priceType?: 'regular' | 'compareAt';\n /** The type of value. Valid values: `min` (default), `max` or `unit`. */\n valueType?: 'max' | 'min' | 'unit';\n /** The ID of the variant. */\n variantId?: string;\n}\n\n/**\n * The `ProductPrice` component renders a `Money` component with the product\n * [`priceRange`](https://shopify.dev/api/storefront/reference/products/productpricerange)'s `maxVariantPrice` or `minVariantPrice`, for either the regular price or compare at price range.\n */\nexport function ProductPrice<ComponentGeneric extends React.ElementType>(\n props: ProductPriceProps &\n Omit<MoneyProps<ComponentGeneric>, 'data' | 'measurement'>\n) {\n const {\n priceType = 'regular',\n variantId,\n valueType = 'min',\n data: product,\n ...passthroughProps\n } = props;\n\n if (product == null) {\n throw new Error(`<ProductPrice/> requires a product as the 'data' prop`);\n }\n\n let price: Partial<MoneyV2> | undefined | null;\n let measurement: Partial<UnitPriceMeasurement> | undefined | null;\n\n const variant = variantId\n ? flattenConnection(product?.variants ?? {}).find(\n (variant) => variant?.id === variantId\n ) ?? null\n : null;\n\n if (priceType === 'compareAt') {\n if (variantId && variant) {\n if (variant.compareAtPriceV2?.amount === variant.priceV2?.amount) {\n return null;\n }\n price = variant.compareAtPriceV2;\n } else if (valueType === 'max') {\n price = product?.compareAtPriceRange?.maxVariantPrice;\n } else {\n price = product?.compareAtPriceRange?.minVariantPrice;\n }\n } else {\n if (variantId && variant) {\n price = variant.priceV2;\n if (valueType === 'unit') {\n price = variant.unitPrice;\n measurement = variant.unitPriceMeasurement;\n }\n } else if (valueType === 'max') {\n price = product.priceRange?.maxVariantPrice;\n } else {\n price = product.priceRange?.minVariantPrice;\n }\n }\n\n if (!price) {\n return null;\n }\n\n if (measurement) {\n return (\n <Money {...passthroughProps} data={price} measurement={measurement} />\n );\n }\n\n return <Money {...passthroughProps} data={price} />;\n}\n"],"names":["ProductPrice","props","priceType","variantId","valueType","data","product","passthroughProps","Error","price","measurement","variant","flattenConnection","variants","find","id","compareAtPriceV2","amount","priceV2","compareAtPriceRange","maxVariantPrice","minVariantPrice","unitPrice","unitPriceMeasurement","priceRange"],"mappings":";;;AAwBO,SAASA,aACdC,OAEA;;AACM,QAAA;AAAA,IACJC,YAAY;AAAA,IACZC;AAAAA,IACAC,YAAY;AAAA,IACZC,MAAMC;AAAAA,OACHC;AAAAA,EACDN,IAAAA;AAEJ,MAAIK,WAAW,MAAM;AACb,UAAA,IAAIE,MAAO,
|
|
1
|
+
{"version":3,"file":"ProductPrice.mjs","sources":["../../src/ProductPrice.tsx"],"sourcesContent":["import type {\n MoneyV2,\n UnitPriceMeasurement,\n Product,\n} from './storefront-api-types.js';\nimport {Money, type MoneyProps} from './Money.js';\nimport type {PartialDeep} from 'type-fest';\nimport {flattenConnection} from './flatten-connection.js';\n\nexport interface ProductPriceProps {\n /** A [Product object](https://shopify.dev/api/storefront/reference/products/product). */\n data: PartialDeep<Product, {recurseIntoArrays: true}>;\n /** The type of price. Valid values: `regular` (default) or `compareAt`. */\n priceType?: 'regular' | 'compareAt';\n /** The type of value. Valid values: `min` (default), `max` or `unit`. */\n valueType?: 'max' | 'min' | 'unit';\n /** The ID of the variant. */\n variantId?: string;\n}\n\n/**\n * The `ProductPrice` component renders a `Money` component with the product\n * [`priceRange`](https://shopify.dev/api/storefront/reference/products/productpricerange)'s `maxVariantPrice` or `minVariantPrice`, for either the regular price or compare at price range.\n */\nexport function ProductPrice<ComponentGeneric extends React.ElementType>(\n props: ProductPriceProps &\n Omit<MoneyProps<ComponentGeneric>, 'data' | 'measurement'>\n) {\n const {\n priceType = 'regular',\n variantId,\n valueType = 'min',\n data: product,\n ...passthroughProps\n } = props;\n\n if (product == null) {\n throw new Error(`<ProductPrice/> requires a product as the 'data' prop`);\n }\n\n let price: Partial<MoneyV2> | undefined | null;\n let measurement: Partial<UnitPriceMeasurement> | undefined | null;\n\n const variant = variantId\n ? flattenConnection(product?.variants ?? {}).find(\n (variant) => variant?.id === variantId\n ) ?? null\n : null;\n\n if (priceType === 'compareAt') {\n if (variantId && variant) {\n if (variant.compareAtPriceV2?.amount === variant.priceV2?.amount) {\n return null;\n }\n price = variant.compareAtPriceV2;\n } else if (valueType === 'max') {\n price = product?.compareAtPriceRange?.maxVariantPrice;\n } else {\n price = product?.compareAtPriceRange?.minVariantPrice;\n }\n } else {\n if (variantId && variant) {\n price = variant.priceV2;\n if (valueType === 'unit') {\n price = variant.unitPrice;\n measurement = variant.unitPriceMeasurement;\n }\n } else if (valueType === 'max') {\n price = product.priceRange?.maxVariantPrice;\n } else {\n price = product.priceRange?.minVariantPrice;\n }\n }\n\n if (!price) {\n return null;\n }\n\n if (measurement) {\n return (\n <Money {...passthroughProps} data={price} measurement={measurement} />\n );\n }\n\n return <Money {...passthroughProps} data={price} />;\n}\n"],"names":["ProductPrice","props","priceType","variantId","valueType","data","product","passthroughProps","Error","price","measurement","variant","flattenConnection","variants","find","id","compareAtPriceV2","amount","priceV2","compareAtPriceRange","maxVariantPrice","minVariantPrice","unitPrice","unitPriceMeasurement","priceRange"],"mappings":";;;AAwBO,SAASA,aACdC,OAEA;;AACM,QAAA;AAAA,IACJC,YAAY;AAAA,IACZC;AAAAA,IACAC,YAAY;AAAA,IACZC,MAAMC;AAAAA,OACHC;AAAAA,EACDN,IAAAA;AAEJ,MAAIK,WAAW,MAAM;AACb,UAAA,IAAIE,MAAO,uDAAsD;AAAA,EACzE;AAEIC,MAAAA;AACAC,MAAAA;AAEJ,QAAMC,UAAUR,aACZS,wBAAkBN,wCAASO,aAATP,YAAqB,CAAA,CAAE,EAAEQ,KACxCH,CAAAA,cAAYA,qCAASI,QAAOZ,SAAS,MADxCS,YAEK,OACL;AAEJ,MAAIV,cAAc,aAAa;AAC7B,QAAIC,aAAaQ,SAAS;AACxB,YAAIA,aAAQK,qBAARL,mBAA0BM,cAAWN,aAAQO,YAARP,mBAAiBM,SAAQ;AACzD,eAAA;AAAA,MACT;AACAR,cAAQE,QAAQK;AAAAA,IAAAA,WACPZ,cAAc,OAAO;AAC9BK,eAAQH,wCAASa,wBAATb,mBAA8Bc;AAAAA,IAAAA,OACjC;AACLX,eAAQH,wCAASa,wBAATb,mBAA8Be;AAAAA,IACxC;AAAA,EAAA,OACK;AACL,QAAIlB,aAAaQ,SAAS;AACxBF,cAAQE,QAAQO;AAChB,UAAId,cAAc,QAAQ;AACxBK,gBAAQE,QAAQW;AAChBZ,sBAAcC,QAAQY;AAAAA,MACxB;AAAA,IAAA,WACSnB,cAAc,OAAO;AAC9BK,eAAQH,aAAQkB,eAARlB,mBAAoBc;AAAAA,IAAAA,OACvB;AACLX,eAAQH,aAAQkB,eAARlB,mBAAoBe;AAAAA,IAC9B;AAAA,EACF;AAEA,MAAI,CAACZ,OAAO;AACH,WAAA;AAAA,EACT;AAEA,MAAIC,aAAa;AACf,+BACG,OAAK;AAAA,MAAA,GAAKH;AAAAA,MAAkB,MAAME;AAAAA,MAAO;AAAA,IAAA,CAA4B;AAAA,EAE1E;AAEA,6BAAQ,OAAK;AAAA,IAAA,GAAKF;AAAAA,IAAkB,MAAME;AAAAA,EAAAA,CAAS;AACrD;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProductProvider.mjs","sources":["../../src/ProductProvider.tsx"],"sourcesContent":["import {\n useMemo,\n useState,\n useEffect,\n useCallback,\n createContext,\n useContext,\n} from 'react';\nimport type {\n SelectedOption as SelectedOptionType,\n SellingPlan,\n SellingPlanAllocation,\n Product,\n ProductVariant as ProductVariantType,\n ProductVariantConnection,\n SellingPlan as SellingPlanType,\n SellingPlanAllocation as SellingPlanAllocationType,\n SellingPlanGroup as SellingPlanGroupType,\n SellingPlanGroupConnection,\n} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\nimport {flattenConnection} from './flatten-connection.js';\n\nconst ProductOptionsContext = createContext<ProductHookValue | null>(null);\n\ntype InitialVariantId = ProductVariantType['id'] | null;\n\ninterface ProductProviderProps {\n /** A [Product object](https://shopify.dev/api/storefront/reference/products/product). */\n data: PartialDeep<Product, {recurseIntoArrays: true}>;\n /** A `ReactNode` element. */\n children: React.ReactNode;\n /**\n * The initially selected variant.\n * The following logic applies to `initialVariantId`:\n * 1. If `initialVariantId` is provided, then it's used even if it's out of stock.\n * 2. If `initialVariantId` is provided but is `null`, then no variant is used.\n * 3. If nothing is passed to `initialVariantId` then the first available / in-stock variant is used.\n * 4. If nothing is passed to `initialVariantId` and no variants are in stock, then the first variant is used.\n */\n initialVariantId?: InitialVariantId;\n}\n\n/**\n * `<ProductProvider />` is a context provider that enables use of the `useProduct()` hook.\n *\n * It helps manage selected options and variants for a product.\n */\nexport function ProductProvider({\n children,\n data: product,\n initialVariantId: explicitVariantId,\n}: ProductProviderProps) {\n // The flattened variants\n const variants = useMemo(\n () => flattenConnection(product.variants ?? {}),\n [product.variants]\n );\n\n if (!isProductVariantArray(variants)) {\n throw new Error(\n `<ProductProvider/> requires 'product.variants.nodes' or 'product.variants.edges'`\n );\n }\n\n // All the options available for a product, based on all the variants\n const options = useMemo(() => getOptions(variants), [variants]);\n\n /**\n * Track the selectedVariant within the provider.\n */\n const [selectedVariant, setSelectedVariant] = useState<\n | PartialDeep<ProductVariantType, {recurseIntoArrays: true}>\n | undefined\n | null\n >(() => getVariantBasedOnIdProp(explicitVariantId, variants));\n\n /**\n * Track the selectedOptions within the provider. If a `initialVariantId`\n * is passed, use that to select initial options.\n */\n const [selectedOptions, setSelectedOptions] = useState<SelectedOptions>(() =>\n getSelectedOptions(selectedVariant)\n );\n\n /**\n * When the initialVariantId changes, we need to make sure we\n * update the selected variant and selected options. If not,\n * then the selected variant and options will reference incorrect\n * values.\n */\n useEffect(() => {\n const newSelectedVariant = getVariantBasedOnIdProp(\n explicitVariantId,\n variants\n );\n setSelectedVariant(newSelectedVariant);\n setSelectedOptions(getSelectedOptions(newSelectedVariant));\n }, [explicitVariantId, variants]);\n\n /**\n * Allow the developer to select an option.\n */\n const setSelectedOption = useCallback(\n (name: string, value: string) => {\n setSelectedOptions((selectedOptions) => {\n const opts = {...selectedOptions, [name]: value};\n setSelectedVariant(getSelectedVariant(variants, opts));\n return opts;\n });\n },\n [setSelectedOptions, variants]\n );\n\n const isOptionInStock = useCallback(\n (option: string, value: string) => {\n const proposedVariant = getSelectedVariant(variants, {\n ...selectedOptions,\n ...{[option]: value},\n });\n\n return proposedVariant?.availableForSale ?? true;\n },\n [selectedOptions, variants]\n );\n\n const sellingPlanGroups = useMemo(\n () =>\n flattenConnection(product.sellingPlanGroups ?? {}).map(\n (sellingPlanGroup) => ({\n ...sellingPlanGroup,\n sellingPlans: flattenConnection(sellingPlanGroup?.sellingPlans ?? {}),\n })\n ),\n [product.sellingPlanGroups]\n );\n\n /**\n * Track the selectedSellingPlan within the hook. If `initialSellingPlanId`\n * is passed, use that as an initial value. Look it up from the `selectedVariant`, since\n * that is also a requirement.\n */\n const [selectedSellingPlan, setSelectedSellingPlan] = useState<\n PartialDeep<SellingPlan, {recurseIntoArrays: true}> | undefined\n >(undefined);\n\n const selectedSellingPlanAllocation = useMemo<\n PartialDeep<SellingPlanAllocation, {recurseIntoArrays: true}> | undefined\n >(() => {\n if (!selectedVariant || !selectedSellingPlan) {\n return;\n }\n\n if (\n !selectedVariant.sellingPlanAllocations?.nodes &&\n !selectedVariant.sellingPlanAllocations?.edges\n ) {\n throw new Error(\n `<ProductProvider/>: You must include 'sellingPlanAllocations.nodes' or 'sellingPlanAllocations.edges' in your variants in order to calculate selectedSellingPlanAllocation`\n );\n }\n\n return flattenConnection(selectedVariant.sellingPlanAllocations).find(\n (allocation) => allocation?.sellingPlan?.id === selectedSellingPlan.id\n );\n }, [selectedVariant, selectedSellingPlan]);\n\n const value = useMemo<ProductHookValue>(\n () => ({\n variants,\n variantsConnection: product.variants,\n options,\n selectedVariant,\n setSelectedVariant,\n selectedOptions,\n setSelectedOption,\n setSelectedOptions,\n isOptionInStock,\n selectedSellingPlan,\n setSelectedSellingPlan,\n selectedSellingPlanAllocation,\n sellingPlanGroups,\n sellingPlanGroupsConnection: product.sellingPlanGroups,\n }),\n [\n isOptionInStock,\n options,\n product.sellingPlanGroups,\n product.variants,\n selectedOptions,\n selectedSellingPlan,\n selectedSellingPlanAllocation,\n selectedVariant,\n sellingPlanGroups,\n setSelectedOption,\n variants,\n ]\n );\n\n return (\n <ProductOptionsContext.Provider value={value}>\n {children}\n </ProductOptionsContext.Provider>\n );\n}\n\n/**\n * Provides access to the context value provided by `<ProductProvider />`. Must be a descendent of `<ProductProvider />`.\n */\nexport function useProduct() {\n const context = useContext(ProductOptionsContext);\n\n if (!context) {\n throw new Error(`'useProduct' must be a child of <ProductProvider />`);\n }\n\n return context;\n}\n\nfunction getSelectedVariant(\n variants: PartialDeep<ProductVariantType, {recurseIntoArrays: true}>[],\n choices: SelectedOptions\n): PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | undefined {\n /**\n * Ensure the user has selected all the required options, not just some.\n */\n if (\n !variants.length ||\n variants?.[0]?.selectedOptions?.length !== Object.keys(choices).length\n ) {\n return;\n }\n\n return variants?.find((variant) => {\n return Object.entries(choices).every(([name, value]) => {\n return variant?.selectedOptions?.some(\n (option) => option?.name === name && option?.value === value\n );\n });\n });\n}\n\nfunction getOptions(\n variants: PartialDeep<ProductVariantType, {recurseIntoArrays: true}>[]\n): OptionWithValues[] {\n const map = variants.reduce((memo, variant) => {\n if (!variant.selectedOptions) {\n throw new Error(`'getOptions' requires 'variant.selectedOptions'`);\n }\n variant?.selectedOptions?.forEach((opt) => {\n memo[opt?.name ?? ''] = memo[opt?.name ?? ''] || new Set();\n memo[opt?.name ?? ''].add(opt?.value ?? '');\n });\n\n return memo;\n }, {} as Record<string, Set<string>>);\n\n return Object.keys(map).map((option) => {\n return {\n name: option,\n values: Array.from(map[option]),\n };\n });\n}\n\nfunction getVariantBasedOnIdProp(\n explicitVariantId: InitialVariantId | undefined,\n variants: Array<\n PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | undefined\n >\n) {\n // get the initial variant based on the logic outlined in the comments for 'initialVariantId' above\n // * 1. If `initialVariantId` is provided, then it's used even if it's out of stock.\n if (explicitVariantId) {\n const foundVariant = variants.find(\n (variant) => variant?.id === explicitVariantId\n );\n if (!foundVariant) {\n console.warn(\n `<ProductProvider/> received a 'initialVariantId' prop, but could not actually find a variant with that ID`\n );\n }\n return foundVariant;\n }\n // * 2. If `initialVariantId` is provided but is `null`, then no variant is used.\n if (explicitVariantId === null) {\n return null;\n }\n // * 3. If nothing is passed to `initialVariantId` then the first available / in-stock variant is used.\n // * 4. If nothing is passed to `initialVariantId` and no variants are in stock, then the first variant is used.\n if (explicitVariantId === undefined) {\n return variants.find((variant) => variant?.availableForSale) || variants[0];\n }\n}\n\nfunction getSelectedOptions(\n selectedVariant:\n | PartialDeep<ProductVariantType, {recurseIntoArrays: true}>\n | undefined\n | null\n): SelectedOptions {\n return selectedVariant?.selectedOptions\n ? selectedVariant.selectedOptions.reduce<SelectedOptions>(\n (memo, optionSet) => {\n memo[optionSet?.name ?? ''] = optionSet?.value ?? '';\n return memo;\n },\n {}\n )\n : {};\n}\n\nfunction isProductVariantArray(\n maybeVariantArray:\n | (PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | undefined)[]\n | undefined\n): maybeVariantArray is PartialDeep<\n ProductVariantType,\n {recurseIntoArrays: true}\n>[] {\n if (!maybeVariantArray || !Array.isArray(maybeVariantArray)) {\n return false;\n }\n\n return true;\n}\n\nexport interface OptionWithValues {\n name: SelectedOptionType['name'];\n values: SelectedOptionType['value'][];\n}\n\ntype ProductHookValue = PartialDeep<\n {\n /** An array of the variant `nodes` from the `VariantConnection`. */\n variants: ProductVariantType[];\n variantsConnection?: ProductVariantConnection;\n /** An array of the product's options and values. */\n options: OptionWithValues[];\n /** The selected variant. */\n selectedVariant?: ProductVariantType | null;\n selectedOptions: SelectedOptions;\n /** The selected selling plan. */\n selectedSellingPlan?: SellingPlanType;\n /** The selected selling plan allocation. */\n selectedSellingPlanAllocation?: SellingPlanAllocationType;\n /** The selling plan groups. */\n sellingPlanGroups?: (Omit<SellingPlanGroupType, 'sellingPlans'> & {\n sellingPlans: SellingPlanType[];\n })[];\n sellingPlanGroupsConnection?: SellingPlanGroupConnection;\n },\n {recurseIntoArrays: true}\n> & {\n /** A callback to set the selected variant to the variant passed as an argument. */\n setSelectedVariant: (\n variant: PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | null\n ) => void;\n /** A callback to set the selected option. */\n setSelectedOption: (\n name: SelectedOptionType['name'],\n value: SelectedOptionType['value']\n ) => void;\n /** A callback to set multiple selected options at once. */\n setSelectedOptions: (options: SelectedOptions) => void;\n /** A callback to set the selected selling plan to the one passed as an argument. */\n setSelectedSellingPlan: (\n sellingPlan: PartialDeep<SellingPlanType, {recurseIntoArrays: true}>\n ) => void;\n /** A callback that returns a boolean indicating if the option is in stock. */\n isOptionInStock: (\n name: SelectedOptionType['name'],\n value: SelectedOptionType['value']\n ) => boolean;\n};\n\nexport type SelectedOptions = {\n [key: string]: string;\n};\n"],"names":["ProductOptionsContext","createContext","ProductProvider","children","data","product","initialVariantId","explicitVariantId","variants","useMemo","flattenConnection","isProductVariantArray","Error","options","getOptions","selectedVariant","setSelectedVariant","useState","getVariantBasedOnIdProp","selectedOptions","setSelectedOptions","getSelectedOptions","useEffect","newSelectedVariant","setSelectedOption","useCallback","name","value","opts","getSelectedVariant","isOptionInStock","option","proposedVariant","availableForSale","sellingPlanGroups","map","sellingPlanGroup","sellingPlans","selectedSellingPlan","setSelectedSellingPlan","undefined","selectedSellingPlanAllocation","sellingPlanAllocations","nodes","edges","find","allocation","sellingPlan","id","variantsConnection","sellingPlanGroupsConnection","_jsx","useProduct","context","useContext","choices","length","Object","keys","variant","entries","every","some","reduce","memo","forEach","opt","Set","add","values","Array","from","foundVariant","console","warn","optionSet","maybeVariantArray","isArray"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProductProvider.mjs","sources":["../../src/ProductProvider.tsx"],"sourcesContent":["import {\n useMemo,\n useState,\n useEffect,\n useCallback,\n createContext,\n useContext,\n} from 'react';\nimport type {\n SelectedOption as SelectedOptionType,\n SellingPlan,\n SellingPlanAllocation,\n Product,\n ProductVariant as ProductVariantType,\n ProductVariantConnection,\n SellingPlan as SellingPlanType,\n SellingPlanAllocation as SellingPlanAllocationType,\n SellingPlanGroup as SellingPlanGroupType,\n SellingPlanGroupConnection,\n} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\nimport {flattenConnection} from './flatten-connection.js';\n\nconst ProductOptionsContext = createContext<ProductHookValue | null>(null);\n\ntype InitialVariantId = ProductVariantType['id'] | null;\n\ninterface ProductProviderProps {\n /** A [Product object](https://shopify.dev/api/storefront/reference/products/product). */\n data: PartialDeep<Product, {recurseIntoArrays: true}>;\n /** A `ReactNode` element. */\n children: React.ReactNode;\n /**\n * The initially selected variant.\n * The following logic applies to `initialVariantId`:\n * 1. If `initialVariantId` is provided, then it's used even if it's out of stock.\n * 2. If `initialVariantId` is provided but is `null`, then no variant is used.\n * 3. If nothing is passed to `initialVariantId` then the first available / in-stock variant is used.\n * 4. If nothing is passed to `initialVariantId` and no variants are in stock, then the first variant is used.\n */\n initialVariantId?: InitialVariantId;\n}\n\n/**\n * `<ProductProvider />` is a context provider that enables use of the `useProduct()` hook.\n *\n * It helps manage selected options and variants for a product.\n */\nexport function ProductProvider({\n children,\n data: product,\n initialVariantId: explicitVariantId,\n}: ProductProviderProps) {\n // The flattened variants\n const variants = useMemo(\n () => flattenConnection(product.variants ?? {}),\n [product.variants]\n );\n\n if (!isProductVariantArray(variants)) {\n throw new Error(\n `<ProductProvider/> requires 'product.variants.nodes' or 'product.variants.edges'`\n );\n }\n\n // All the options available for a product, based on all the variants\n const options = useMemo(() => getOptions(variants), [variants]);\n\n /**\n * Track the selectedVariant within the provider.\n */\n const [selectedVariant, setSelectedVariant] = useState<\n | PartialDeep<ProductVariantType, {recurseIntoArrays: true}>\n | undefined\n | null\n >(() => getVariantBasedOnIdProp(explicitVariantId, variants));\n\n /**\n * Track the selectedOptions within the provider. If a `initialVariantId`\n * is passed, use that to select initial options.\n */\n const [selectedOptions, setSelectedOptions] = useState<SelectedOptions>(() =>\n getSelectedOptions(selectedVariant)\n );\n\n /**\n * When the initialVariantId changes, we need to make sure we\n * update the selected variant and selected options. If not,\n * then the selected variant and options will reference incorrect\n * values.\n */\n useEffect(() => {\n const newSelectedVariant = getVariantBasedOnIdProp(\n explicitVariantId,\n variants\n );\n setSelectedVariant(newSelectedVariant);\n setSelectedOptions(getSelectedOptions(newSelectedVariant));\n }, [explicitVariantId, variants]);\n\n /**\n * Allow the developer to select an option.\n */\n const setSelectedOption = useCallback(\n (name: string, value: string) => {\n setSelectedOptions((selectedOptions) => {\n const opts = {...selectedOptions, [name]: value};\n setSelectedVariant(getSelectedVariant(variants, opts));\n return opts;\n });\n },\n [setSelectedOptions, variants]\n );\n\n const isOptionInStock = useCallback(\n (option: string, value: string) => {\n const proposedVariant = getSelectedVariant(variants, {\n ...selectedOptions,\n ...{[option]: value},\n });\n\n return proposedVariant?.availableForSale ?? true;\n },\n [selectedOptions, variants]\n );\n\n const sellingPlanGroups = useMemo(\n () =>\n flattenConnection(product.sellingPlanGroups ?? {}).map(\n (sellingPlanGroup) => ({\n ...sellingPlanGroup,\n sellingPlans: flattenConnection(sellingPlanGroup?.sellingPlans ?? {}),\n })\n ),\n [product.sellingPlanGroups]\n );\n\n /**\n * Track the selectedSellingPlan within the hook. If `initialSellingPlanId`\n * is passed, use that as an initial value. Look it up from the `selectedVariant`, since\n * that is also a requirement.\n */\n const [selectedSellingPlan, setSelectedSellingPlan] = useState<\n PartialDeep<SellingPlan, {recurseIntoArrays: true}> | undefined\n >(undefined);\n\n const selectedSellingPlanAllocation = useMemo<\n PartialDeep<SellingPlanAllocation, {recurseIntoArrays: true}> | undefined\n >(() => {\n if (!selectedVariant || !selectedSellingPlan) {\n return;\n }\n\n if (\n !selectedVariant.sellingPlanAllocations?.nodes &&\n !selectedVariant.sellingPlanAllocations?.edges\n ) {\n throw new Error(\n `<ProductProvider/>: You must include 'sellingPlanAllocations.nodes' or 'sellingPlanAllocations.edges' in your variants in order to calculate selectedSellingPlanAllocation`\n );\n }\n\n return flattenConnection(selectedVariant.sellingPlanAllocations).find(\n (allocation) => allocation?.sellingPlan?.id === selectedSellingPlan.id\n );\n }, [selectedVariant, selectedSellingPlan]);\n\n const value = useMemo<ProductHookValue>(\n () => ({\n variants,\n variantsConnection: product.variants,\n options,\n selectedVariant,\n setSelectedVariant,\n selectedOptions,\n setSelectedOption,\n setSelectedOptions,\n isOptionInStock,\n selectedSellingPlan,\n setSelectedSellingPlan,\n selectedSellingPlanAllocation,\n sellingPlanGroups,\n sellingPlanGroupsConnection: product.sellingPlanGroups,\n }),\n [\n isOptionInStock,\n options,\n product.sellingPlanGroups,\n product.variants,\n selectedOptions,\n selectedSellingPlan,\n selectedSellingPlanAllocation,\n selectedVariant,\n sellingPlanGroups,\n setSelectedOption,\n variants,\n ]\n );\n\n return (\n <ProductOptionsContext.Provider value={value}>\n {children}\n </ProductOptionsContext.Provider>\n );\n}\n\n/**\n * Provides access to the context value provided by `<ProductProvider />`. Must be a descendent of `<ProductProvider />`.\n */\nexport function useProduct() {\n const context = useContext(ProductOptionsContext);\n\n if (!context) {\n throw new Error(`'useProduct' must be a child of <ProductProvider />`);\n }\n\n return context;\n}\n\nfunction getSelectedVariant(\n variants: PartialDeep<ProductVariantType, {recurseIntoArrays: true}>[],\n choices: SelectedOptions\n): PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | undefined {\n /**\n * Ensure the user has selected all the required options, not just some.\n */\n if (\n !variants.length ||\n variants?.[0]?.selectedOptions?.length !== Object.keys(choices).length\n ) {\n return;\n }\n\n return variants?.find((variant) => {\n return Object.entries(choices).every(([name, value]) => {\n return variant?.selectedOptions?.some(\n (option) => option?.name === name && option?.value === value\n );\n });\n });\n}\n\nfunction getOptions(\n variants: PartialDeep<ProductVariantType, {recurseIntoArrays: true}>[]\n): OptionWithValues[] {\n const map = variants.reduce((memo, variant) => {\n if (!variant.selectedOptions) {\n throw new Error(`'getOptions' requires 'variant.selectedOptions'`);\n }\n variant?.selectedOptions?.forEach((opt) => {\n memo[opt?.name ?? ''] = memo[opt?.name ?? ''] || new Set();\n memo[opt?.name ?? ''].add(opt?.value ?? '');\n });\n\n return memo;\n }, {} as Record<string, Set<string>>);\n\n return Object.keys(map).map((option) => {\n return {\n name: option,\n values: Array.from(map[option]),\n };\n });\n}\n\nfunction getVariantBasedOnIdProp(\n explicitVariantId: InitialVariantId | undefined,\n variants: Array<\n PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | undefined\n >\n) {\n // get the initial variant based on the logic outlined in the comments for 'initialVariantId' above\n // * 1. If `initialVariantId` is provided, then it's used even if it's out of stock.\n if (explicitVariantId) {\n const foundVariant = variants.find(\n (variant) => variant?.id === explicitVariantId\n );\n if (!foundVariant) {\n console.warn(\n `<ProductProvider/> received a 'initialVariantId' prop, but could not actually find a variant with that ID`\n );\n }\n return foundVariant;\n }\n // * 2. If `initialVariantId` is provided but is `null`, then no variant is used.\n if (explicitVariantId === null) {\n return null;\n }\n // * 3. If nothing is passed to `initialVariantId` then the first available / in-stock variant is used.\n // * 4. If nothing is passed to `initialVariantId` and no variants are in stock, then the first variant is used.\n if (explicitVariantId === undefined) {\n return variants.find((variant) => variant?.availableForSale) || variants[0];\n }\n}\n\nfunction getSelectedOptions(\n selectedVariant:\n | PartialDeep<ProductVariantType, {recurseIntoArrays: true}>\n | undefined\n | null\n): SelectedOptions {\n return selectedVariant?.selectedOptions\n ? selectedVariant.selectedOptions.reduce<SelectedOptions>(\n (memo, optionSet) => {\n memo[optionSet?.name ?? ''] = optionSet?.value ?? '';\n return memo;\n },\n {}\n )\n : {};\n}\n\nfunction isProductVariantArray(\n maybeVariantArray:\n | (PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | undefined)[]\n | undefined\n): maybeVariantArray is PartialDeep<\n ProductVariantType,\n {recurseIntoArrays: true}\n>[] {\n if (!maybeVariantArray || !Array.isArray(maybeVariantArray)) {\n return false;\n }\n\n return true;\n}\n\nexport interface OptionWithValues {\n name: SelectedOptionType['name'];\n values: SelectedOptionType['value'][];\n}\n\ntype ProductHookValue = PartialDeep<\n {\n /** An array of the variant `nodes` from the `VariantConnection`. */\n variants: ProductVariantType[];\n variantsConnection?: ProductVariantConnection;\n /** An array of the product's options and values. */\n options: OptionWithValues[];\n /** The selected variant. */\n selectedVariant?: ProductVariantType | null;\n selectedOptions: SelectedOptions;\n /** The selected selling plan. */\n selectedSellingPlan?: SellingPlanType;\n /** The selected selling plan allocation. */\n selectedSellingPlanAllocation?: SellingPlanAllocationType;\n /** The selling plan groups. */\n sellingPlanGroups?: (Omit<SellingPlanGroupType, 'sellingPlans'> & {\n sellingPlans: SellingPlanType[];\n })[];\n sellingPlanGroupsConnection?: SellingPlanGroupConnection;\n },\n {recurseIntoArrays: true}\n> & {\n /** A callback to set the selected variant to the variant passed as an argument. */\n setSelectedVariant: (\n variant: PartialDeep<ProductVariantType, {recurseIntoArrays: true}> | null\n ) => void;\n /** A callback to set the selected option. */\n setSelectedOption: (\n name: SelectedOptionType['name'],\n value: SelectedOptionType['value']\n ) => void;\n /** A callback to set multiple selected options at once. */\n setSelectedOptions: (options: SelectedOptions) => void;\n /** A callback to set the selected selling plan to the one passed as an argument. */\n setSelectedSellingPlan: (\n sellingPlan: PartialDeep<SellingPlanType, {recurseIntoArrays: true}>\n ) => void;\n /** A callback that returns a boolean indicating if the option is in stock. */\n isOptionInStock: (\n name: SelectedOptionType['name'],\n value: SelectedOptionType['value']\n ) => boolean;\n};\n\nexport type SelectedOptions = {\n [key: string]: string;\n};\n"],"names":["ProductOptionsContext","createContext","ProductProvider","children","data","product","initialVariantId","explicitVariantId","variants","useMemo","flattenConnection","isProductVariantArray","Error","options","getOptions","selectedVariant","setSelectedVariant","useState","getVariantBasedOnIdProp","selectedOptions","setSelectedOptions","getSelectedOptions","useEffect","newSelectedVariant","setSelectedOption","useCallback","name","value","opts","getSelectedVariant","isOptionInStock","option","proposedVariant","availableForSale","sellingPlanGroups","map","sellingPlanGroup","sellingPlans","selectedSellingPlan","setSelectedSellingPlan","undefined","selectedSellingPlanAllocation","sellingPlanAllocations","nodes","edges","find","allocation","sellingPlan","id","variantsConnection","sellingPlanGroupsConnection","_jsx","useProduct","context","useContext","choices","length","Object","keys","variant","entries","every","some","reduce","memo","forEach","opt","Set","add","values","Array","from","foundVariant","console","warn","optionSet","maybeVariantArray","isArray"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShopPayButton.mjs","sources":["../../src/ShopPayButton.tsx"],"sourcesContent":["import {useShop} from './ShopifyProvider.js';\nimport {useLoadScript} from './load-script.js';\n\n// By using 'never' in the \"or\" cases below, it makes these props \"exclusive\" and means that you cannot pass both of them; you must pass either one OR the other.\ntype ShopPayButtonProps = {\n /** A string of classes to apply to the `div` that wraps the Shop Pay button. */\n className?: string;\n /** A string that's applied to the [CSS custom property (variable)](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) `--shop-pay-button-width` for the [Buy with Shop Pay component](https://shopify.dev/custom-storefronts/tools/web-components#buy-with-shop-pay-component). */\n width?: string;\n} & (\n | {\n /** 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'. */\n variantIds: string[];\n /** An array of variant IDs and quantities to purchase with Shop Pay. */\n variantIdsAndQuantities?: never;\n }\n | {\n /** 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'. */\n variantIds?: never;\n /** An array of variant IDs and quantities to purchase with Shop Pay. */\n variantIdsAndQuantities: Array<{\n id: string;\n quantity: number;\n }>;\n }\n);\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace JSX {\n interface IntrinsicElements {\n 'shop-pay-button': {\n variants: string;\n 'store-url': string;\n };\n }\n }\n}\n\nconst SHOPJS_URL =\n 'https://cdn.shopify.com/shopifycloud/shop-js/v1.0/client.js';\n\n/**\n * The `ShopPayButton` component renders a button that redirects to the Shop Pay checkout.\n * It renders a [`<shop-pay-button>`](https://shopify.dev/custom-storefronts/tools/web-components) custom element, for which it will lazy-load the source code automatically.\n * It relies on the `<ShopProvider>` context provider.\n */\nexport function ShopPayButton({\n variantIds,\n className,\n variantIdsAndQuantities,\n width,\n}: ShopPayButtonProps) {\n const {storeDomain} = useShop();\n const shopPayLoadedStatus = useLoadScript(SHOPJS_URL);\n\n let ids: string[];\n\n if (variantIds && variantIdsAndQuantities) {\n throw new Error(DoublePropsErrorMessage);\n }\n\n if (variantIds) {\n ids = variantIds.reduce<string[]>((prev, curr) => {\n const bareId = getIdFromGid(curr);\n if (bareId) {\n prev.push(bareId);\n }\n return prev;\n }, []);\n } else if (variantIdsAndQuantities) {\n ids = variantIdsAndQuantities.reduce<string[]>((prev, curr) => {\n const bareId = getIdFromGid(curr?.id);\n if (bareId) {\n prev.push(`${bareId}:${curr?.quantity ?? 1}`);\n }\n return prev;\n }, []);\n } else {\n throw new Error(MissingPropsErrorMessage);\n }\n\n const style = width\n ? ({\n '--shop-pay-button-width': width,\n } as React.CSSProperties)\n : undefined;\n\n return (\n <div className={className} style={style}>\n {shopPayLoadedStatus === 'done' && (\n <shop-pay-button\n store-url={`https://${storeDomain}`}\n variants={ids.join(',')}\n />\n )}\n </div>\n );\n}\n\n/**\n * Takes a string in the format of \"gid://shopify/ProductVariant/41007289630776\" and returns a string of the ID part at the end: \"41007289630776\"\n */\nexport function getIdFromGid(id?: string) {\n if (!id) return;\n return id.split('/').pop();\n}\n\nexport const MissingPropsErrorMessage = `You must pass in either \"variantIds\" or \"variantIdsAndQuantities\" to ShopPayButton`;\nexport const DoublePropsErrorMessage = `You must provide either a variantIds or variantIdsAndQuantities prop, but not both in the ShopPayButton component`;\n"],"names":["SHOPJS_URL","ShopPayButton","variantIds","className","variantIdsAndQuantities","width","storeDomain","useShop","shopPayLoadedStatus","useLoadScript","ids","Error","DoublePropsErrorMessage","reduce","prev","curr","bareId","getIdFromGid","push","id","quantity","MissingPropsErrorMessage","style","undefined","_jsx","join","split","pop"],"mappings":";;;AAuCA,MAAMA,aACJ;AAOK,SAASC,cAAc;AAAA,EAC5BC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC;
|
|
1
|
+
{"version":3,"file":"ShopPayButton.mjs","sources":["../../src/ShopPayButton.tsx"],"sourcesContent":["import {useShop} from './ShopifyProvider.js';\nimport {useLoadScript} from './load-script.js';\n\n// By using 'never' in the \"or\" cases below, it makes these props \"exclusive\" and means that you cannot pass both of them; you must pass either one OR the other.\ntype ShopPayButtonProps = {\n /** A string of classes to apply to the `div` that wraps the Shop Pay button. */\n className?: string;\n /** A string that's applied to the [CSS custom property (variable)](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) `--shop-pay-button-width` for the [Buy with Shop Pay component](https://shopify.dev/custom-storefronts/tools/web-components#buy-with-shop-pay-component). */\n width?: string;\n} & (\n | {\n /** 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'. */\n variantIds: string[];\n /** An array of variant IDs and quantities to purchase with Shop Pay. */\n variantIdsAndQuantities?: never;\n }\n | {\n /** 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'. */\n variantIds?: never;\n /** An array of variant IDs and quantities to purchase with Shop Pay. */\n variantIdsAndQuantities: Array<{\n id: string;\n quantity: number;\n }>;\n }\n);\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace JSX {\n interface IntrinsicElements {\n 'shop-pay-button': {\n variants: string;\n 'store-url': string;\n };\n }\n }\n}\n\nconst SHOPJS_URL =\n 'https://cdn.shopify.com/shopifycloud/shop-js/v1.0/client.js';\n\n/**\n * The `ShopPayButton` component renders a button that redirects to the Shop Pay checkout.\n * It renders a [`<shop-pay-button>`](https://shopify.dev/custom-storefronts/tools/web-components) custom element, for which it will lazy-load the source code automatically.\n * It relies on the `<ShopProvider>` context provider.\n */\nexport function ShopPayButton({\n variantIds,\n className,\n variantIdsAndQuantities,\n width,\n}: ShopPayButtonProps) {\n const {storeDomain} = useShop();\n const shopPayLoadedStatus = useLoadScript(SHOPJS_URL);\n\n let ids: string[];\n\n if (variantIds && variantIdsAndQuantities) {\n throw new Error(DoublePropsErrorMessage);\n }\n\n if (variantIds) {\n ids = variantIds.reduce<string[]>((prev, curr) => {\n const bareId = getIdFromGid(curr);\n if (bareId) {\n prev.push(bareId);\n }\n return prev;\n }, []);\n } else if (variantIdsAndQuantities) {\n ids = variantIdsAndQuantities.reduce<string[]>((prev, curr) => {\n const bareId = getIdFromGid(curr?.id);\n if (bareId) {\n prev.push(`${bareId}:${curr?.quantity ?? 1}`);\n }\n return prev;\n }, []);\n } else {\n throw new Error(MissingPropsErrorMessage);\n }\n\n const style = width\n ? ({\n '--shop-pay-button-width': width,\n } as React.CSSProperties)\n : undefined;\n\n return (\n <div className={className} style={style}>\n {shopPayLoadedStatus === 'done' && (\n <shop-pay-button\n store-url={`https://${storeDomain}`}\n variants={ids.join(',')}\n />\n )}\n </div>\n );\n}\n\n/**\n * Takes a string in the format of \"gid://shopify/ProductVariant/41007289630776\" and returns a string of the ID part at the end: \"41007289630776\"\n */\nexport function getIdFromGid(id?: string) {\n if (!id) return;\n return id.split('/').pop();\n}\n\nexport const MissingPropsErrorMessage = `You must pass in either \"variantIds\" or \"variantIdsAndQuantities\" to ShopPayButton`;\nexport const DoublePropsErrorMessage = `You must provide either a variantIds or variantIdsAndQuantities prop, but not both in the ShopPayButton component`;\n"],"names":["SHOPJS_URL","ShopPayButton","variantIds","className","variantIdsAndQuantities","width","storeDomain","useShop","shopPayLoadedStatus","useLoadScript","ids","Error","DoublePropsErrorMessage","reduce","prev","curr","bareId","getIdFromGid","push","id","quantity","MissingPropsErrorMessage","style","undefined","_jsx","join","split","pop"],"mappings":";;;AAuCA,MAAMA,aACJ;AAOK,SAASC,cAAc;AAAA,EAC5BC;AAAAA,EACAC;AAAAA,EACAC;AAAAA,EACAC;AACkB,GAAG;AACf,QAAA;AAAA,IAACC;AAAAA,MAAeC,QAAS;AACzBC,QAAAA,sBAAsBC,cAAcT,UAAU;AAEhDU,MAAAA;AAEJ,MAAIR,cAAcE,yBAAyB;AACnC,UAAA,IAAIO,MAAMC,uBAAuB;AAAA,EACzC;AAEA,MAAIV,YAAY;AACdQ,UAAMR,WAAWW,OAAiB,CAACC,MAAMC,SAAS;AAC1CC,YAAAA,SAASC,aAAaF,IAAI;AAChC,UAAIC,QAAQ;AACVF,aAAKI,KAAKF,MAAM;AAAA,MAClB;AACOF,aAAAA;AAAAA,IACT,GAAG,CAAE,CAAA;AAAA,aACIV,yBAAyB;AAClCM,UAAMN,wBAAwBS,OAAiB,CAACC,MAAMC,SAAS;;AACvDC,YAAAA,SAASC,aAAaF,6BAAMI,EAAE;AACpC,UAAIH,QAAQ;AACVF,aAAKI,KAAM,GAAEF,WAAUD,kCAAMK,aAANL,YAAkB,GAAG;AAAA,MAC9C;AACOD,aAAAA;AAAAA,IACT,GAAG,CAAE,CAAA;AAAA,EAAA,OACA;AACC,UAAA,IAAIH,MAAMU,wBAAwB;AAAA,EAC1C;AAEA,QAAMC,QAAQjB,QACT;AAAA,IACC,2BAA2BA;AAAAA,EAE7BkB,IAAAA;AAEJ,6BACE,OAAA;AAAA,IAAK;AAAA,IAAsB;AAAA,IAAa,UACrCf,wBAAwB,UACvBgB,oBAAA,mBAAA;AAAA,MACE,aAAY,WAAUlB;AAAAA,MACtB,UAAUI,IAAIe,KAAK,GAAG;AAAA,IAAA,CAAE;AAAA,EAAA,CAGxB;AAEV;AAKO,SAASR,aAAaE,IAAa;AACxC,MAAI,CAACA;AAAI;AACT,SAAOA,GAAGO,MAAM,GAAG,EAAEC,IAAK;AAC5B;AAEO,MAAMN,2BAA4B;AAClC,MAAMT,0BAA2B;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShopifyProvider.mjs","sources":["../../src/ShopifyProvider.tsx"],"sourcesContent":["import {createContext, useContext, useMemo, type ReactNode} from 'react';\nimport type {LanguageCode, CountryCode, Shop} from './storefront-api-types.js';\nimport {SFAPI_VERSION} from './storefront-api-constants.js';\nimport {getPublicTokenHeadersRaw} from './storefront-client.js';\n\nconst ShopifyContext = createContext<ShopifyContextValue>({\n storeDomain: 'test.myshopify.com',\n storefrontToken: 'abc123',\n storefrontApiVersion: SFAPI_VERSION,\n country: {\n isoCode: 'US',\n },\n language: {\n isoCode: 'EN',\n },\n locale: 'EN-US',\n getStorefrontApiUrl() {\n return '';\n },\n getPublicTokenHeaders() {\n return {};\n },\n});\n\n/**\n * The `<ShopifyProvider/>` component enables use of the `useShop()` hook. The component should wrap your app.\n */\nexport function ShopifyProvider({\n children,\n shopifyConfig,\n}: {\n children: ReactNode;\n shopifyConfig: ShopifyContextProps;\n}) {\n if (!shopifyConfig) {\n throw new Error(\n `The 'shopifyConfig' prop must be passed to '<ShopifyProvider/>'`\n );\n }\n\n if (shopifyConfig.storefrontApiVersion !== SFAPI_VERSION) {\n console.warn(\n `This version of Hydrogen-UI is built for Shopify's Storefront API version ${SFAPI_VERSION}, but it looks like you're using version ${shopifyConfig.storefrontApiVersion}. There may be issues or bugs if you use a mismatched version of Hydrogen-UI and the Storefront API.`\n );\n }\n\n const finalConfig = useMemo<ShopifyContextValue>(() => {\n const storeDomain = shopifyConfig.storeDomain.replace(/^https?:\\/\\//, '');\n return {\n ...shopifyConfig,\n storeDomain,\n getPublicTokenHeaders(overrideProps) {\n return getPublicTokenHeadersRaw(\n overrideProps.contentType,\n shopifyConfig.storefrontApiVersion,\n overrideProps.storefrontToken ?? shopifyConfig.storefrontToken\n );\n },\n getStorefrontApiUrl(overrideProps) {\n return `https://${overrideProps?.storeDomain ?? storeDomain}/api/${\n overrideProps?.storefrontApiVersion ??\n shopifyConfig.storefrontApiVersion\n }/graphql.json`;\n },\n };\n }, [shopifyConfig]);\n\n return (\n <ShopifyContext.Provider value={finalConfig}>\n {children}\n </ShopifyContext.Provider>\n );\n}\n\n/**\n * Provides access to the `shopifyConfig` prop of `<ShopifyProvider/>`. Must be a descendent of `<ShopifyProvider/>`.\n */\nexport function useShop() {\n const shopContext = useContext(ShopifyContext);\n if (!shopContext) {\n throw new Error(`'useShop()' must be a descendent of <ShopifyProvider/>`);\n }\n return shopContext;\n}\n\n/**\n * Shopify-specific values that are used in various Hydrogen-UI components and hooks.\n */\nexport type ShopifyContextProps = {\n /** The globally-unique identifier for the Shop */\n storefrontId?: string;\n /** The host name of the domain (eg: `{shop}.myshopify.com`). If a URL with a scheme (for example `https://`) is passed in, then the scheme is removed. */\n storeDomain: Shop['primaryDomain']['host'];\n /** The Storefront API public access token. Refer to the [authentication](https://shopify.dev/api/storefront#authentication) documentation for more details. */\n storefrontToken: string;\n /** The Storefront API version. This should almost always be the same as the version Hydrogen-UI was built for. Learn more about Shopify [API versioning](https://shopify.dev/api/usage/versioning) for more details. */\n storefrontApiVersion: string;\n country?: {\n /**\n * The code designating a country, which generally follows ISO 3166-1 alpha-2 guidelines. If a territory doesn't have a country code value in the `CountryCode` enum, it might be considered a subdivision of another country. For example, the territories associated with Spain are represented by the country code `ES`, and the territories associated with the United States of America are represented by the country code `US`.\n */\n isoCode: CountryCode;\n };\n language?: {\n /**\n * `ISO 369` language codes supported by Shopify.\n */\n isoCode: LanguageCode;\n };\n /**\n * The locale string based on `country` and `language`.\n */\n locale?: string;\n};\n\nexport type ShopifyContextValue = ShopifyContextProps & {\n /**\n * Creates the fully-qualified URL to your store's GraphQL endpoint.\n *\n * By default, it will use the config you passed in when creating `<ShopifyProvider/>`. However, you can override the following settings on each invocation of `getStorefrontApiUrl({...})`:\n *\n * - `storeDomain`\n * - `storefrontApiVersion`\n */\n getStorefrontApiUrl: (props?: {\n /** The host name of the domain (eg: `{shop}.myshopify.com`). */\n storeDomain?: string;\n /** The Storefront API version. This should almost always be the same as the version Hydrogen-UI was built for. Learn more about Shopify [API versioning](https://shopify.dev/api/usage/versioning) for more details. */\n storefrontApiVersion?: string;\n }) => string;\n /**\n * Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. This uses the public Storefront API token.\n *\n * By default, it will use the config you passed in when creating `<ShopifyProvider/>`. However, you can override the following settings on each invocation of `getPublicTokenHeaders({...})`:\n *\n * - `contentType`\n * - `storefrontToken`\n *\n */\n getPublicTokenHeaders: (props: {\n /**\n * Customizes which `\"content-type\"` header is added when using `getPrivateTokenHeaders()` and `getPublicTokenHeaders()`. When fetching with a `JSON.stringify()`-ed `body`, use `\"json\"`. When fetching with a `body` that is a plain string, use `\"graphql\"`. Defaults to `\"json\"`\n */\n contentType: 'json' | 'graphql';\n /** The Storefront API access token. Refer to the [authentication](https://shopify.dev/api/storefront#authentication) documentation for more details. */\n storefrontToken?: string;\n }) => Record<string, string>;\n};\n"],"names":["ShopifyContext","createContext","storeDomain","storefrontToken","storefrontApiVersion","SFAPI_VERSION","country","isoCode","language","locale","getStorefrontApiUrl","getPublicTokenHeaders","ShopifyProvider","children","shopifyConfig","Error","console","warn","finalConfig","useMemo","replace","overrideProps","getPublicTokenHeadersRaw","contentType","_jsx","useShop","shopContext","useContext"],"mappings":";;;;AAKA,MAAMA,iBAAiBC,cAAmC;AAAA,EACxDC,aAAa;AAAA,EACbC,iBAAiB;AAAA,EACjBC,sBAAsBC;AAAAA,EACtBC,SAAS;AAAA,IACPC,SAAS;AAAA,
|
|
1
|
+
{"version":3,"file":"ShopifyProvider.mjs","sources":["../../src/ShopifyProvider.tsx"],"sourcesContent":["import {createContext, useContext, useMemo, type ReactNode} from 'react';\nimport type {LanguageCode, CountryCode, Shop} from './storefront-api-types.js';\nimport {SFAPI_VERSION} from './storefront-api-constants.js';\nimport {getPublicTokenHeadersRaw} from './storefront-client.js';\n\nconst ShopifyContext = createContext<ShopifyContextValue>({\n storeDomain: 'test.myshopify.com',\n storefrontToken: 'abc123',\n storefrontApiVersion: SFAPI_VERSION,\n country: {\n isoCode: 'US',\n },\n language: {\n isoCode: 'EN',\n },\n locale: 'EN-US',\n getStorefrontApiUrl() {\n return '';\n },\n getPublicTokenHeaders() {\n return {};\n },\n});\n\n/**\n * The `<ShopifyProvider/>` component enables use of the `useShop()` hook. The component should wrap your app.\n */\nexport function ShopifyProvider({\n children,\n shopifyConfig,\n}: {\n children: ReactNode;\n shopifyConfig: ShopifyContextProps;\n}) {\n if (!shopifyConfig) {\n throw new Error(\n `The 'shopifyConfig' prop must be passed to '<ShopifyProvider/>'`\n );\n }\n\n if (shopifyConfig.storefrontApiVersion !== SFAPI_VERSION) {\n console.warn(\n `This version of Hydrogen-UI is built for Shopify's Storefront API version ${SFAPI_VERSION}, but it looks like you're using version ${shopifyConfig.storefrontApiVersion}. There may be issues or bugs if you use a mismatched version of Hydrogen-UI and the Storefront API.`\n );\n }\n\n const finalConfig = useMemo<ShopifyContextValue>(() => {\n const storeDomain = shopifyConfig.storeDomain.replace(/^https?:\\/\\//, '');\n return {\n ...shopifyConfig,\n storeDomain,\n getPublicTokenHeaders(overrideProps) {\n return getPublicTokenHeadersRaw(\n overrideProps.contentType,\n shopifyConfig.storefrontApiVersion,\n overrideProps.storefrontToken ?? shopifyConfig.storefrontToken\n );\n },\n getStorefrontApiUrl(overrideProps) {\n return `https://${overrideProps?.storeDomain ?? storeDomain}/api/${\n overrideProps?.storefrontApiVersion ??\n shopifyConfig.storefrontApiVersion\n }/graphql.json`;\n },\n };\n }, [shopifyConfig]);\n\n return (\n <ShopifyContext.Provider value={finalConfig}>\n {children}\n </ShopifyContext.Provider>\n );\n}\n\n/**\n * Provides access to the `shopifyConfig` prop of `<ShopifyProvider/>`. Must be a descendent of `<ShopifyProvider/>`.\n */\nexport function useShop() {\n const shopContext = useContext(ShopifyContext);\n if (!shopContext) {\n throw new Error(`'useShop()' must be a descendent of <ShopifyProvider/>`);\n }\n return shopContext;\n}\n\n/**\n * Shopify-specific values that are used in various Hydrogen-UI components and hooks.\n */\nexport type ShopifyContextProps = {\n /** The globally-unique identifier for the Shop */\n storefrontId?: string;\n /** The host name of the domain (eg: `{shop}.myshopify.com`). If a URL with a scheme (for example `https://`) is passed in, then the scheme is removed. */\n storeDomain: Shop['primaryDomain']['host'];\n /** The Storefront API public access token. Refer to the [authentication](https://shopify.dev/api/storefront#authentication) documentation for more details. */\n storefrontToken: string;\n /** The Storefront API version. This should almost always be the same as the version Hydrogen-UI was built for. Learn more about Shopify [API versioning](https://shopify.dev/api/usage/versioning) for more details. */\n storefrontApiVersion: string;\n country?: {\n /**\n * The code designating a country, which generally follows ISO 3166-1 alpha-2 guidelines. If a territory doesn't have a country code value in the `CountryCode` enum, it might be considered a subdivision of another country. For example, the territories associated with Spain are represented by the country code `ES`, and the territories associated with the United States of America are represented by the country code `US`.\n */\n isoCode: CountryCode;\n };\n language?: {\n /**\n * `ISO 369` language codes supported by Shopify.\n */\n isoCode: LanguageCode;\n };\n /**\n * The locale string based on `country` and `language`.\n */\n locale?: string;\n};\n\nexport type ShopifyContextValue = ShopifyContextProps & {\n /**\n * Creates the fully-qualified URL to your store's GraphQL endpoint.\n *\n * By default, it will use the config you passed in when creating `<ShopifyProvider/>`. However, you can override the following settings on each invocation of `getStorefrontApiUrl({...})`:\n *\n * - `storeDomain`\n * - `storefrontApiVersion`\n */\n getStorefrontApiUrl: (props?: {\n /** The host name of the domain (eg: `{shop}.myshopify.com`). */\n storeDomain?: string;\n /** The Storefront API version. This should almost always be the same as the version Hydrogen-UI was built for. Learn more about Shopify [API versioning](https://shopify.dev/api/usage/versioning) for more details. */\n storefrontApiVersion?: string;\n }) => string;\n /**\n * Returns an object that contains headers that are needed for each query to Storefront API GraphQL endpoint. This uses the public Storefront API token.\n *\n * By default, it will use the config you passed in when creating `<ShopifyProvider/>`. However, you can override the following settings on each invocation of `getPublicTokenHeaders({...})`:\n *\n * - `contentType`\n * - `storefrontToken`\n *\n */\n getPublicTokenHeaders: (props: {\n /**\n * Customizes which `\"content-type\"` header is added when using `getPrivateTokenHeaders()` and `getPublicTokenHeaders()`. When fetching with a `JSON.stringify()`-ed `body`, use `\"json\"`. When fetching with a `body` that is a plain string, use `\"graphql\"`. Defaults to `\"json\"`\n */\n contentType: 'json' | 'graphql';\n /** The Storefront API access token. Refer to the [authentication](https://shopify.dev/api/storefront#authentication) documentation for more details. */\n storefrontToken?: string;\n }) => Record<string, string>;\n};\n"],"names":["ShopifyContext","createContext","storeDomain","storefrontToken","storefrontApiVersion","SFAPI_VERSION","country","isoCode","language","locale","getStorefrontApiUrl","getPublicTokenHeaders","ShopifyProvider","children","shopifyConfig","Error","console","warn","finalConfig","useMemo","replace","overrideProps","getPublicTokenHeadersRaw","contentType","_jsx","useShop","shopContext","useContext"],"mappings":";;;;AAKA,MAAMA,iBAAiBC,cAAmC;AAAA,EACxDC,aAAa;AAAA,EACbC,iBAAiB;AAAA,EACjBC,sBAAsBC;AAAAA,EACtBC,SAAS;AAAA,IACPC,SAAS;AAAA,EACX;AAAA,EACAC,UAAU;AAAA,IACRD,SAAS;AAAA,EACX;AAAA,EACAE,QAAQ;AAAA,EACRC,sBAAsB;AACb,WAAA;AAAA,EACT;AAAA,EACAC,wBAAwB;AACtB,WAAO;EACT;AACF,CAAC;AAKM,SAASC,gBAAgB;AAAA,EAC9BC;AAAAA,EACAC;AAIF,GAAG;AACD,MAAI,CAACA,eAAe;AACZ,UAAA,IAAIC,MACP,iEAAgE;AAAA,EAErE;AAEID,MAAAA,cAAcV,yBAAyBC,eAAe;AACxDW,YAAQC,KACL,6EAA4EZ,yDAAyDS,cAAcV,0HAA0H;AAAA,EAElR;AAEMc,QAAAA,cAAcC,QAA6B,MAAM;AACrD,UAAMjB,cAAcY,cAAcZ,YAAYkB,QAAQ,gBAAgB,EAAE;AACjE,WAAA;AAAA,MACL,GAAGN;AAAAA,MACHZ;AAAAA,MACAS,sBAAsBU,eAAe;;AAC5BC,eAAAA,yBACLD,cAAcE,aACdT,cAAcV,uBACdiB,mBAAclB,oBAAdkB,YAAiCP,cAAcX,eAAe;AAAA,MAElE;AAAA,MACAO,oBAAoBW,eAAe;;AACjC,eAAQ,YAAUA,oDAAenB,gBAAfmB,YAA8BnB,oBAC9CmB,oDAAejB,yBAAfiB,YACAP,cAAcV;AAAAA,MAElB;AAAA,IAAA;AAAA,EACF,GACC,CAACU,aAAa,CAAC;AAGhB,SAAAU,oBAAC,eAAe,UAAQ;AAAA,IAAC,OAAON;AAAAA,IAAY;AAAA,EAAA,CAElB;AAE9B;AAKO,SAASO,UAAU;AAClBC,QAAAA,cAAcC,WAAW3B,cAAc;AAC7C,MAAI,CAAC0B,aAAa;AACV,UAAA,IAAIX,MAAO,wDAAuD;AAAA,EAC1E;AACOW,SAAAA;AACT;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Video.mjs","sources":["../../src/Video.tsx"],"sourcesContent":["import {type HTMLAttributes} from 'react';\nimport {shopifyImageLoader} from './image-size.js';\nimport type {Video as VideoType} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\nexport interface VideoProps {\n /** An object with fields that correspond to the Storefront API's [Video object](https://shopify.dev/api/storefront/latest/objects/video). */\n data: PartialDeep<VideoType, {recurseIntoArrays: true}>;\n /** An object of image size options for the video's `previewImage`. Uses `shopifyImageLoader` to generate the `poster` URL. */\n previewImageOptions?: Parameters<typeof shopifyImageLoader>[0];\n /** Props that will be passed to the `video` element's `source` children elements. */\n sourceProps?: HTMLAttributes<HTMLSourceElement> & {\n 'data-testid'?: string;\n };\n}\n\n/**\n * The `Video` component renders a `video` for the Storefront API's [Video object](https://shopify.dev/api/storefront/reference/products/video).\n */\nexport function Video(props: JSX.IntrinsicElements['video'] & VideoProps) {\n const {\n data,\n previewImageOptions,\n id = data.id,\n playsInline = true,\n controls = true,\n sourceProps = {},\n ...passthroughProps\n } = props;\n\n const posterUrl = shopifyImageLoader({\n src: data.previewImage?.url ?? '',\n ...previewImageOptions,\n });\n\n if (!data.sources) {\n throw new Error(`<Video/> requires a 'data.sources' array`);\n }\n\n return (\n // eslint-disable-next-line jsx-a11y/media-has-caption\n <video\n {...passthroughProps}\n id={id}\n playsInline={playsInline}\n controls={controls}\n poster={posterUrl}\n >\n {data.sources.map((source) => {\n if (!(source?.url && source?.mimeType)) {\n throw new Error(`<Video/> needs 'source.url' and 'source.mimeType'`);\n }\n return (\n <source\n {...sourceProps}\n key={source.url}\n src={source.url}\n type={source.mimeType}\n />\n );\n })}\n </video>\n );\n}\n"],"names":["Video","props","data","previewImageOptions","id","playsInline","controls","sourceProps","passthroughProps","posterUrl","shopifyImageLoader","src","previewImage","url","sources","Error","map","source","mimeType"],"mappings":";;;AAmBO,SAASA,MAAMC,OAAoD;;AAClE,QAAA;AAAA,IACJC;AAAAA,IACAC;AAAAA,IACAC,KAAKF,KAAKE;AAAAA,IACVC,cAAc;AAAA,IACdC,WAAW;AAAA,IACXC,cAAc,
|
|
1
|
+
{"version":3,"file":"Video.mjs","sources":["../../src/Video.tsx"],"sourcesContent":["import {type HTMLAttributes} from 'react';\nimport {shopifyImageLoader} from './image-size.js';\nimport type {Video as VideoType} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\nexport interface VideoProps {\n /** An object with fields that correspond to the Storefront API's [Video object](https://shopify.dev/api/storefront/latest/objects/video). */\n data: PartialDeep<VideoType, {recurseIntoArrays: true}>;\n /** An object of image size options for the video's `previewImage`. Uses `shopifyImageLoader` to generate the `poster` URL. */\n previewImageOptions?: Parameters<typeof shopifyImageLoader>[0];\n /** Props that will be passed to the `video` element's `source` children elements. */\n sourceProps?: HTMLAttributes<HTMLSourceElement> & {\n 'data-testid'?: string;\n };\n}\n\n/**\n * The `Video` component renders a `video` for the Storefront API's [Video object](https://shopify.dev/api/storefront/reference/products/video).\n */\nexport function Video(props: JSX.IntrinsicElements['video'] & VideoProps) {\n const {\n data,\n previewImageOptions,\n id = data.id,\n playsInline = true,\n controls = true,\n sourceProps = {},\n ...passthroughProps\n } = props;\n\n const posterUrl = shopifyImageLoader({\n src: data.previewImage?.url ?? '',\n ...previewImageOptions,\n });\n\n if (!data.sources) {\n throw new Error(`<Video/> requires a 'data.sources' array`);\n }\n\n return (\n // eslint-disable-next-line jsx-a11y/media-has-caption\n <video\n {...passthroughProps}\n id={id}\n playsInline={playsInline}\n controls={controls}\n poster={posterUrl}\n >\n {data.sources.map((source) => {\n if (!(source?.url && source?.mimeType)) {\n throw new Error(`<Video/> needs 'source.url' and 'source.mimeType'`);\n }\n return (\n <source\n {...sourceProps}\n key={source.url}\n src={source.url}\n type={source.mimeType}\n />\n );\n })}\n </video>\n );\n}\n"],"names":["Video","props","data","previewImageOptions","id","playsInline","controls","sourceProps","passthroughProps","posterUrl","shopifyImageLoader","src","previewImage","url","sources","Error","map","source","mimeType"],"mappings":";;;AAmBO,SAASA,MAAMC,OAAoD;;AAClE,QAAA;AAAA,IACJC;AAAAA,IACAC;AAAAA,IACAC,KAAKF,KAAKE;AAAAA,IACVC,cAAc;AAAA,IACdC,WAAW;AAAA,IACXC,cAAc,CAAC;AAAA,OACZC;AAAAA,EACDP,IAAAA;AAEJ,QAAMQ,YAAYC,mBAAmB;AAAA,IACnCC,MAAKT,gBAAKU,iBAALV,mBAAmBW,QAAnBX,YAA0B;AAAA,IAC/B,GAAGC;AAAAA,EAAAA,CACJ;AAEG,MAAA,CAACD,KAAKY,SAAS;AACX,UAAA,IAAIC,MAAO,0CAAyC;AAAA,EAC5D;AAEA,6BAEE,SAAA;AAAA,IAAA,GACMP;AAAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQC;AAAAA,IAAU,UAEjBP,KAAKY,QAAQE,IAAKC,CAAW,WAAA;AAC5B,UAAI,GAAEA,iCAAQJ,SAAOI,iCAAQC,YAAW;AAChC,cAAA,IAAIH,MAAO,mDAAkD;AAAA,MACrE;AACA,2CACE,UAAA;AAAA,QAAA,GACMR;AAAAA,QACJ,KAAKU,OAAOJ;AAAAA,QACZ,KAAKI,OAAOJ;AAAAA,QACZ,MAAMI,OAAOC;AAAAA,MAAAA,CACb;AAAA,IAAA,CAEL;AAAA,EAAA,CAAC;AAGR;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-hooks.mjs","sources":["../../src/cart-hooks.tsx"],"sourcesContent":["import {useState, useCallback} from 'react';\nimport {useShop} from './ShopifyProvider.js';\nimport {flattenConnection} from './flatten-connection.js';\nimport {CartInput, Cart as CartType} from './storefront-api-types.js';\nimport {CartCreate, defaultCartFragment} from './cart-queries.js';\nimport {Cart} from './cart-types.js';\nimport {\n SHOPIFY_STOREFRONT_ID_HEADER,\n SHOPIFY_STOREFRONT_Y_HEADER,\n SHOPIFY_STOREFRONT_S_HEADER,\n SHOPIFY_Y,\n SHOPIFY_S,\n} from './cart-constants.js';\nimport {parse} from 'worktop/cookie';\nimport type {StorefrontApiResponseOkPartial} from './storefront-api-response.types.js';\n\nexport function useCartFetch() {\n const {storefrontId, getPublicTokenHeaders, getStorefrontApiUrl} = useShop();\n\n return useCallback(\n <ReturnDataGeneric,>({\n query,\n variables,\n }: {\n query: string;\n variables: Record<string, unknown>;\n }): Promise<StorefrontApiResponseOkPartial<ReturnDataGeneric>> => {\n const headers = getPublicTokenHeaders({contentType: 'json'});\n\n if (storefrontId) {\n headers[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;\n }\n\n // Find Shopify cookies\n const cookieData = parse(document.cookie);\n if (cookieData[SHOPIFY_Y] && cookieData[SHOPIFY_S]) {\n headers[SHOPIFY_STOREFRONT_Y_HEADER] = cookieData[SHOPIFY_Y];\n headers[SHOPIFY_STOREFRONT_S_HEADER] = cookieData[SHOPIFY_S];\n }\n\n return fetch(getStorefrontApiUrl(), {\n method: 'POST',\n headers,\n body: JSON.stringify({\n query: query.toString(),\n variables,\n }),\n })\n .then((res) => res.json())\n .catch((error) => {\n return {\n data: undefined,\n errors: error.toString(),\n };\n });\n },\n [getPublicTokenHeaders, storefrontId, getStorefrontApiUrl]\n );\n}\n\nexport function useInstantCheckout() {\n const [cart, updateCart] = useState<Cart | undefined>();\n const [checkoutUrl, updateCheckoutUrl] = useState<Cart['checkoutUrl']>();\n const [error, updateError] = useState<string | undefined>();\n\n const fetch = useCartFetch();\n\n const createInstantCheckout = useCallback(\n async (cartInput: CartInput) => {\n const {data, errors} = await fetch<{\n cartCreate: {cart: CartType};\n }>({\n query: CartCreate(defaultCartFragment),\n variables: {\n input: cartInput,\n },\n });\n\n if (errors) {\n updateError(errors.toString());\n updateCart(undefined);\n updateCheckoutUrl(undefined);\n }\n\n if (data?.cartCreate?.cart) {\n const dataCart = data.cartCreate.cart;\n updateCart({\n ...dataCart,\n lines: flattenConnection(dataCart.lines),\n note: dataCart.note ?? undefined,\n });\n updateCheckoutUrl(dataCart.checkoutUrl);\n }\n },\n [fetch]\n );\n\n return {cart, checkoutUrl, error, createInstantCheckout};\n}\n"],"names":["useCartFetch","storefrontId","getPublicTokenHeaders","getStorefrontApiUrl","useShop","useCallback","query","variables","headers","contentType","SHOPIFY_STOREFRONT_ID_HEADER","cookieData","parse","document","cookie","SHOPIFY_Y","SHOPIFY_S","SHOPIFY_STOREFRONT_Y_HEADER","SHOPIFY_STOREFRONT_S_HEADER","fetch","method","body","JSON","stringify","toString","then","res","json","catch","error","data","undefined","errors"],"mappings":";;;;AAgBO,SAASA,eAAe;AACvB,QAAA;AAAA,IAACC;AAAAA,IAAcC;AAAAA,IAAuBC;AAAAA,MAAuBC,
|
|
1
|
+
{"version":3,"file":"cart-hooks.mjs","sources":["../../src/cart-hooks.tsx"],"sourcesContent":["import {useState, useCallback} from 'react';\nimport {useShop} from './ShopifyProvider.js';\nimport {flattenConnection} from './flatten-connection.js';\nimport {CartInput, Cart as CartType} from './storefront-api-types.js';\nimport {CartCreate, defaultCartFragment} from './cart-queries.js';\nimport {Cart} from './cart-types.js';\nimport {\n SHOPIFY_STOREFRONT_ID_HEADER,\n SHOPIFY_STOREFRONT_Y_HEADER,\n SHOPIFY_STOREFRONT_S_HEADER,\n SHOPIFY_Y,\n SHOPIFY_S,\n} from './cart-constants.js';\nimport {parse} from 'worktop/cookie';\nimport type {StorefrontApiResponseOkPartial} from './storefront-api-response.types.js';\n\nexport function useCartFetch() {\n const {storefrontId, getPublicTokenHeaders, getStorefrontApiUrl} = useShop();\n\n return useCallback(\n <ReturnDataGeneric,>({\n query,\n variables,\n }: {\n query: string;\n variables: Record<string, unknown>;\n }): Promise<StorefrontApiResponseOkPartial<ReturnDataGeneric>> => {\n const headers = getPublicTokenHeaders({contentType: 'json'});\n\n if (storefrontId) {\n headers[SHOPIFY_STOREFRONT_ID_HEADER] = storefrontId;\n }\n\n // Find Shopify cookies\n const cookieData = parse(document.cookie);\n if (cookieData[SHOPIFY_Y] && cookieData[SHOPIFY_S]) {\n headers[SHOPIFY_STOREFRONT_Y_HEADER] = cookieData[SHOPIFY_Y];\n headers[SHOPIFY_STOREFRONT_S_HEADER] = cookieData[SHOPIFY_S];\n }\n\n return fetch(getStorefrontApiUrl(), {\n method: 'POST',\n headers,\n body: JSON.stringify({\n query: query.toString(),\n variables,\n }),\n })\n .then((res) => res.json())\n .catch((error) => {\n return {\n data: undefined,\n errors: error.toString(),\n };\n });\n },\n [getPublicTokenHeaders, storefrontId, getStorefrontApiUrl]\n );\n}\n\nexport function useInstantCheckout() {\n const [cart, updateCart] = useState<Cart | undefined>();\n const [checkoutUrl, updateCheckoutUrl] = useState<Cart['checkoutUrl']>();\n const [error, updateError] = useState<string | undefined>();\n\n const fetch = useCartFetch();\n\n const createInstantCheckout = useCallback(\n async (cartInput: CartInput) => {\n const {data, errors} = await fetch<{\n cartCreate: {cart: CartType};\n }>({\n query: CartCreate(defaultCartFragment),\n variables: {\n input: cartInput,\n },\n });\n\n if (errors) {\n updateError(errors.toString());\n updateCart(undefined);\n updateCheckoutUrl(undefined);\n }\n\n if (data?.cartCreate?.cart) {\n const dataCart = data.cartCreate.cart;\n updateCart({\n ...dataCart,\n lines: flattenConnection(dataCart.lines),\n note: dataCart.note ?? undefined,\n });\n updateCheckoutUrl(dataCart.checkoutUrl);\n }\n },\n [fetch]\n );\n\n return {cart, checkoutUrl, error, createInstantCheckout};\n}\n"],"names":["useCartFetch","storefrontId","getPublicTokenHeaders","getStorefrontApiUrl","useShop","useCallback","query","variables","headers","contentType","SHOPIFY_STOREFRONT_ID_HEADER","cookieData","parse","document","cookie","SHOPIFY_Y","SHOPIFY_S","SHOPIFY_STOREFRONT_Y_HEADER","SHOPIFY_STOREFRONT_S_HEADER","fetch","method","body","JSON","stringify","toString","then","res","json","catch","error","data","undefined","errors"],"mappings":";;;;AAgBO,SAASA,eAAe;AACvB,QAAA;AAAA,IAACC;AAAAA,IAAcC;AAAAA,IAAuBC;AAAAA,MAAuBC,QAAS;AAE5E,SAAOC,YACL,CAAqB;AAAA,IACnBC;AAAAA,IACAC;AAAAA,EAAAA,MAIgE;AAChE,UAAMC,UAAUN,sBAAsB;AAAA,MAACO,aAAa;AAAA,IAAA,CAAO;AAE3D,QAAIR,cAAc;AAChBO,cAAQE,gCAAgCT;AAAAA,IAC1C;AAGMU,UAAAA,aAAaC,MAAMC,SAASC,MAAM;AACpCH,QAAAA,WAAWI,cAAcJ,WAAWK,YAAY;AAClDR,cAAQS,+BAA+BN,WAAWI;AAClDP,cAAQU,+BAA+BP,WAAWK;AAAAA,IACpD;AAEOG,WAAAA,MAAMhB,uBAAuB;AAAA,MAClCiB,QAAQ;AAAA,MACRZ;AAAAA,MACAa,MAAMC,KAAKC,UAAU;AAAA,QACnBjB,OAAOA,MAAMkB,SAAU;AAAA,QACvBjB;AAAAA,MAAAA,CACD;AAAA,IAAA,CACF,EACEkB,KAAMC,CAAAA,QAAQA,IAAIC,MAAM,EACxBC,MAAOC,CAAU,UAAA;AACT,aAAA;AAAA,QACLC,MAAMC;AAAAA,QACNC,QAAQH,MAAML,SAAQ;AAAA,MAAA;AAAA,IACxB,CACD;AAAA,EAEL,GAAA,CAACtB,uBAAuBD,cAAcE,mBAAmB,CAAC;AAE9D;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-script.mjs","sources":["../../src/load-script.tsx"],"sourcesContent":["import {useState, useEffect} from 'react';\n\nconst SCRIPTS_LOADED: Record<string, Promise<boolean>> = {};\n\nexport function loadScript(\n src: string,\n options?: {module?: boolean; in?: 'head' | 'body'}\n): Promise<boolean> {\n const isScriptLoaded: Promise<boolean> = SCRIPTS_LOADED[src];\n\n if (isScriptLoaded) {\n return isScriptLoaded;\n }\n\n const promise = new Promise<boolean>((resolve, reject) => {\n const script = document.createElement('script');\n if (options?.module) {\n script.type = 'module';\n } else {\n script.type = 'text/javascript';\n }\n script.src = src;\n script.onload = () => {\n resolve(true);\n };\n script.onerror = () => {\n reject(false);\n };\n if (options?.in === 'head') {\n document.head.appendChild(script);\n } else {\n document.body.appendChild(script);\n }\n });\n\n SCRIPTS_LOADED[src] = promise;\n\n return promise;\n}\n\ntype LoadScriptParams = Parameters<typeof loadScript>;\n\n/**\n * The `useLoadScript` hook loads an external script tag in the browser. It allows React components to lazy-load large third-party dependencies.\n */\nexport function useLoadScript(\n url: LoadScriptParams[0],\n options?: LoadScriptParams[1]\n): ScriptState {\n const [status, setStatus] = useState<ScriptState>('loading');\n const stringifiedOptions = JSON.stringify(options);\n\n useEffect(() => {\n async function loadScriptWrapper() {\n try {\n setStatus('loading');\n await loadScript(url, options);\n setStatus('done');\n } catch (error) {\n setStatus('error');\n }\n }\n\n loadScriptWrapper();\n }, [url, stringifiedOptions, options]);\n\n return status;\n}\n\ntype ScriptState = 'loading' | 'done' | 'error';\n"],"names":["SCRIPTS_LOADED","loadScript","src","options","isScriptLoaded","promise","Promise","resolve","reject","script","document","createElement","module","type","onload","onerror","in","head","appendChild","body","useLoadScript","url","status","setStatus","useState","stringifiedOptions","JSON","stringify","useEffect","loadScriptWrapper","error"],"mappings":";AAEA,MAAMA,iBAAmD,CAAA;AAEzCC,SAAAA,WACdC,KACAC,SACkB;AAClB,QAAMC,iBAAmCJ,eAAeE;AAExD,MAAIE,gBAAgB;AACXA,WAAAA;AAAAA,
|
|
1
|
+
{"version":3,"file":"load-script.mjs","sources":["../../src/load-script.tsx"],"sourcesContent":["import {useState, useEffect} from 'react';\n\nconst SCRIPTS_LOADED: Record<string, Promise<boolean>> = {};\n\nexport function loadScript(\n src: string,\n options?: {module?: boolean; in?: 'head' | 'body'}\n): Promise<boolean> {\n const isScriptLoaded: Promise<boolean> = SCRIPTS_LOADED[src];\n\n if (isScriptLoaded) {\n return isScriptLoaded;\n }\n\n const promise = new Promise<boolean>((resolve, reject) => {\n const script = document.createElement('script');\n if (options?.module) {\n script.type = 'module';\n } else {\n script.type = 'text/javascript';\n }\n script.src = src;\n script.onload = () => {\n resolve(true);\n };\n script.onerror = () => {\n reject(false);\n };\n if (options?.in === 'head') {\n document.head.appendChild(script);\n } else {\n document.body.appendChild(script);\n }\n });\n\n SCRIPTS_LOADED[src] = promise;\n\n return promise;\n}\n\ntype LoadScriptParams = Parameters<typeof loadScript>;\n\n/**\n * The `useLoadScript` hook loads an external script tag in the browser. It allows React components to lazy-load large third-party dependencies.\n */\nexport function useLoadScript(\n url: LoadScriptParams[0],\n options?: LoadScriptParams[1]\n): ScriptState {\n const [status, setStatus] = useState<ScriptState>('loading');\n const stringifiedOptions = JSON.stringify(options);\n\n useEffect(() => {\n async function loadScriptWrapper() {\n try {\n setStatus('loading');\n await loadScript(url, options);\n setStatus('done');\n } catch (error) {\n setStatus('error');\n }\n }\n\n loadScriptWrapper();\n }, [url, stringifiedOptions, options]);\n\n return status;\n}\n\ntype ScriptState = 'loading' | 'done' | 'error';\n"],"names":["SCRIPTS_LOADED","loadScript","src","options","isScriptLoaded","promise","Promise","resolve","reject","script","document","createElement","module","type","onload","onerror","in","head","appendChild","body","useLoadScript","url","status","setStatus","useState","stringifiedOptions","JSON","stringify","useEffect","loadScriptWrapper","error"],"mappings":";AAEA,MAAMA,iBAAmD,CAAA;AAEzCC,SAAAA,WACdC,KACAC,SACkB;AAClB,QAAMC,iBAAmCJ,eAAeE;AAExD,MAAIE,gBAAgB;AACXA,WAAAA;AAAAA,EACT;AAEA,QAAMC,UAAU,IAAIC,QAAiB,CAACC,SAASC,WAAW;AAClDC,UAAAA,SAASC,SAASC,cAAc,QAAQ;AAC9C,QAAIR,mCAASS,QAAQ;AACnBH,aAAOI,OAAO;AAAA,IAAA,OACT;AACLJ,aAAOI,OAAO;AAAA,IAChB;AACAJ,WAAOP,MAAMA;AACbO,WAAOK,SAAS,MAAM;AACpBP,cAAQ,IAAI;AAAA,IAAA;AAEdE,WAAOM,UAAU,MAAM;AACrBP,aAAO,KAAK;AAAA,IAAA;AAEVL,SAAAA,mCAASa,QAAO,QAAQ;AACjBC,eAAAA,KAAKC,YAAYT,MAAM;AAAA,IAAA,OAC3B;AACIU,eAAAA,KAAKD,YAAYT,MAAM;AAAA,IAClC;AAAA,EAAA,CACD;AAEDT,iBAAeE,OAAOG;AAEfA,SAAAA;AACT;AAOgBe,SAAAA,cACdC,KACAlB,SACa;AACb,QAAM,CAACmB,QAAQC,SAAS,IAAIC,SAAsB,SAAS;AACrDC,QAAAA,qBAAqBC,KAAKC,UAAUxB,OAAO;AAEjDyB,YAAU,MAAM;AACd,mBAAeC,oBAAoB;AAC7B,UAAA;AACFN,kBAAU,SAAS;AACbtB,cAAAA,WAAWoB,KAAKlB,OAAO;AAC7BoB,kBAAU,MAAM;AAAA,eACTO;AACPP,kBAAU,OAAO;AAAA,MACnB;AAAA,IACF;AAEmB;EAClB,GAAA,CAACF,KAAKI,oBAAoBtB,OAAO,CAAC;AAE9BmB,SAAAA;AACT;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCartAPIStateMachine.mjs","sources":["../../src/useCartAPIStateMachine.tsx"],"sourcesContent":["import {useMachine} from '@xstate/react/fsm';\nimport {createMachine, assign, StateMachine} from '@xstate/fsm';\nimport {\n Cart,\n CartMachineActionEvent,\n CartMachineActions,\n CartMachineContext,\n CartMachineEvent,\n CartMachineFetchResultEvent,\n CartMachineTypeState,\n} from './cart-types.js';\nimport {flattenConnection} from './flatten-connection.js';\nimport {useCartActions} from './useCartActions.js';\nimport {useMemo} from 'react';\nimport {InitEvent} from '@xstate/fsm/lib/types.js';\nimport {CountryCode, Cart as CartType} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\nfunction invokeCart(\n action: keyof CartMachineActions,\n options?: {\n entryActions?: [keyof CartMachineActions];\n resolveTarget?: CartMachineTypeState['value'];\n errorTarget?: CartMachineTypeState['value'];\n exitActions?: [keyof CartMachineActions];\n }\n): StateMachine.Config<CartMachineContext, CartMachineEvent>['states']['on'] {\n return {\n entry: [\n ...(options?.entryActions || []),\n 'onCartActionEntry',\n 'onCartActionOptimisticUI',\n action,\n ],\n on: {\n RESOLVE: {\n target: options?.resolveTarget || 'idle',\n actions: [\n assign({\n prevCart: (context) => context?.cart,\n cart: (_, event) => event?.payload?.cart,\n rawCartResult: (_, event) => event?.payload?.rawCartResult,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n errors: (_) => undefined,\n }),\n ],\n },\n ERROR: {\n target: options?.errorTarget || 'error',\n actions: [\n assign({\n prevCart: (context) => context?.cart,\n cart: (context) => context?.lastValidCart,\n errors: (_, event) => event?.payload?.errors,\n }),\n ],\n },\n CART_COMPLETED: {\n target: 'cartCompleted',\n actions: assign({\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n prevCart: (_) => undefined,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n cart: (_) => undefined,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n lastValidCart: (_) => undefined,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n errors: (_) => undefined,\n }),\n },\n },\n exit: ['onCartActionComplete', ...(options?.exitActions || [])],\n };\n}\n\nconst INITIALIZING_CART_EVENTS: StateMachine.Machine<\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState\n>['config']['states']['uninitialized']['on'] = {\n CART_FETCH: {\n target: 'cartFetching',\n },\n CART_CREATE: {\n target: 'cartCreating',\n },\n CART_SET: {\n target: 'idle',\n actions: [\n assign({\n rawCartResult: (_, event) => event.payload.cart,\n cart: (_, event) => cartFromGraphQL(event.payload.cart),\n }),\n ],\n },\n};\n\nconst UPDATING_CART_EVENTS: StateMachine.Machine<\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState\n>['config']['states']['idle']['on'] = {\n CARTLINE_ADD: {\n target: 'cartLineAdding',\n },\n CARTLINE_UPDATE: {\n target: 'cartLineUpdating',\n },\n CARTLINE_REMOVE: {\n target: 'cartLineRemoving',\n },\n NOTE_UPDATE: {\n target: 'noteUpdating',\n },\n BUYER_IDENTITY_UPDATE: {\n target: 'buyerIdentityUpdating',\n },\n CART_ATTRIBUTES_UPDATE: {\n target: 'cartAttributesUpdating',\n },\n DISCOUNT_CODES_UPDATE: {\n target: 'discountCodesUpdating',\n },\n};\n\nfunction createCartMachine(\n initialCart?: PartialDeep<CartType, {recurseIntoArrays: true}>\n) {\n return createMachine<\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState\n >({\n id: 'Cart',\n initial: initialCart ? 'idle' : 'uninitialized',\n context: {\n cart: initialCart && cartFromGraphQL(initialCart),\n },\n states: {\n uninitialized: {\n on: INITIALIZING_CART_EVENTS,\n },\n cartCompleted: {\n on: INITIALIZING_CART_EVENTS,\n },\n initializationError: {\n on: INITIALIZING_CART_EVENTS,\n },\n idle: {\n on: {...INITIALIZING_CART_EVENTS, ...UPDATING_CART_EVENTS},\n },\n error: {\n on: {...INITIALIZING_CART_EVENTS, ...UPDATING_CART_EVENTS},\n },\n cartFetching: invokeCart('cartFetchAction', {\n errorTarget: 'initializationError',\n }),\n cartCreating: invokeCart('cartCreateAction', {\n errorTarget: 'initializationError',\n }),\n cartLineRemoving: invokeCart('cartLineRemoveAction'),\n cartLineUpdating: invokeCart('cartLineUpdateAction'),\n cartLineAdding: invokeCart('cartLineAddAction'),\n noteUpdating: invokeCart('noteUpdateAction'),\n buyerIdentityUpdating: invokeCart('buyerIdentityUpdateAction'),\n cartAttributesUpdating: invokeCart('cartAttributesUpdateAction'),\n discountCodesUpdating: invokeCart('discountCodesUpdateAction'),\n },\n });\n}\n\nexport function useCartAPIStateMachine({\n numCartLines,\n onCartActionEntry,\n onCartActionOptimisticUI,\n onCartActionComplete,\n data: cart,\n cartFragment,\n countryCode,\n}: {\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A callback that is invoked just before a Cart API action executes. */\n onCartActionEntry?: (\n context: CartMachineContext,\n event: CartMachineActionEvent\n ) => void;\n /** A callback that is invoked after executing the entry actions for optimistic UI changes. */\n onCartActionOptimisticUI?: (\n context: CartMachineContext,\n event: CartMachineEvent\n ) => Partial<CartMachineContext>;\n /** A callback that is invoked after a Cart API completes. */\n onCartActionComplete?: (\n context: CartMachineContext,\n event: CartMachineFetchResultEvent\n ) => void;\n /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart). */\n data?: PartialDeep<CartType, {recurseIntoArrays: true}>;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment: string;\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n}) {\n const {\n cartFetch,\n cartCreate,\n cartLineAdd,\n cartLineUpdate,\n cartLineRemove,\n noteUpdate,\n buyerIdentityUpdate,\n cartAttributesUpdate,\n discountCodesUpdate,\n } = useCartActions({\n numCartLines,\n cartFragment,\n countryCode,\n });\n\n const cartMachine = useMemo(() => createCartMachine(cart), [cart]);\n\n const [state, send, service] = useMachine(cartMachine, {\n actions: {\n cartFetchAction: async (_, event): Promise<void> => {\n if (event.type !== 'CART_FETCH') return;\n\n const {data, errors} = await cartFetch(event?.payload?.cartId);\n const resultEvent = eventFromFetchResult(event, data?.cart, errors);\n send(resultEvent);\n },\n cartCreateAction: async (_, event): Promise<void> => {\n if (event.type !== 'CART_CREATE') return;\n\n const {data, errors} = await cartCreate(event?.payload);\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartCreate?.cart,\n errors\n );\n send(resultEvent);\n },\n cartLineAddAction: async (context, event): Promise<void> => {\n if (event.type !== 'CARTLINE_ADD' || !context?.cart?.id) return;\n\n const {data, errors} = await cartLineAdd(\n context.cart.id,\n event.payload.lines\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartLinesAdd?.cart,\n errors\n );\n\n send(resultEvent);\n },\n cartLineUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'CARTLINE_UPDATE' || !context?.cart?.id) return;\n const {data, errors} = await cartLineUpdate(\n context.cart.id,\n event.payload.lines\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartLinesUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n cartLineRemoveAction: async (context, event): Promise<void> => {\n if (event.type !== 'CARTLINE_REMOVE' || !context?.cart?.id) return;\n const {data, errors} = await cartLineRemove(\n context.cart.id,\n event.payload.lines\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartLinesRemove?.cart,\n errors\n );\n\n send(resultEvent);\n },\n noteUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'NOTE_UPDATE' || !context?.cart?.id) return;\n const {data, errors} = await noteUpdate(\n context.cart.id,\n event.payload.note\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartNoteUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n buyerIdentityUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'BUYER_IDENTITY_UPDATE' || !context?.cart?.id)\n return;\n const {data, errors} = await buyerIdentityUpdate(\n context.cart.id,\n event.payload.buyerIdentity\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartBuyerIdentityUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n cartAttributesUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'CART_ATTRIBUTES_UPDATE' || !context?.cart?.id)\n return;\n const {data, errors} = await cartAttributesUpdate(\n context.cart.id,\n event.payload.attributes\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartAttributesUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n discountCodesUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'DISCOUNT_CODES_UPDATE' || !context?.cart?.id)\n return;\n const {data, errors} = await discountCodesUpdate(\n context.cart.id,\n event.payload.discountCodes\n );\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartDiscountCodesUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n ...(onCartActionEntry && {\n onCartActionEntry: (context, event) => {\n if (isCartActionEvent(event)) {\n onCartActionEntry(context, event);\n }\n },\n }),\n ...(onCartActionOptimisticUI && {\n onCartActionOptimisticUI: assign((context, event) => {\n return onCartActionOptimisticUI(context, event);\n }),\n }),\n ...(onCartActionComplete && {\n onCartActionComplete: (context, event) => {\n if (isCartFetchResultEvent(event)) {\n onCartActionComplete(context, event);\n }\n },\n }),\n } as CartMachineActions,\n });\n\n return useMemo(() => [state, send, service] as const, [state, send, service]);\n}\n\nexport function cartFromGraphQL(\n cart: PartialDeep<CartType, {recurseIntoArrays: true}>\n): Cart {\n return {\n ...cart,\n lines: flattenConnection(cart?.lines),\n note: cart.note ?? undefined,\n };\n}\n\nfunction eventFromFetchResult(\n cartActionEvent: CartMachineActionEvent,\n cart?: PartialDeep<CartType, {recurseIntoArrays: true}> | null,\n errors?: unknown\n): CartMachineFetchResultEvent {\n if (errors) {\n return {type: 'ERROR', payload: {errors, cartActionEvent}};\n }\n\n if (!cart) {\n return {\n type: 'CART_COMPLETED',\n payload: {\n cartActionEvent,\n },\n };\n }\n\n return {\n type: 'RESOLVE',\n payload: {\n cart: cartFromGraphQL(cart),\n rawCartResult: cart,\n cartActionEvent,\n },\n };\n}\n\nfunction isCartActionEvent(\n event: CartMachineEvent | InitEvent\n): event is CartMachineActionEvent {\n return (\n event.type === 'CART_CREATE' ||\n event.type === 'CARTLINE_ADD' ||\n event.type === 'CARTLINE_UPDATE' ||\n event.type === 'CARTLINE_REMOVE' ||\n event.type === 'NOTE_UPDATE' ||\n event.type === 'BUYER_IDENTITY_UPDATE' ||\n event.type === 'CART_ATTRIBUTES_UPDATE' ||\n event.type === 'DISCOUNT_CODES_UPDATE'\n );\n}\n\nfunction isCartFetchResultEvent(\n event: CartMachineEvent | InitEvent\n): event is CartMachineFetchResultEvent {\n return (\n event.type === 'RESOLVE' ||\n event.type === 'ERROR' ||\n event.type === 'CART_COMPLETED'\n );\n}\n"],"names":["invokeCart","action","options","entry","entryActions","on","RESOLVE","target","resolveTarget","actions","assign","prevCart","context","cart","_","event","payload","rawCartResult","errors","undefined","ERROR","errorTarget","lastValidCart","CART_COMPLETED","exit","exitActions","INITIALIZING_CART_EVENTS","CART_FETCH","CART_CREATE","CART_SET","cartFromGraphQL","UPDATING_CART_EVENTS","CARTLINE_ADD","CARTLINE_UPDATE","CARTLINE_REMOVE","NOTE_UPDATE","BUYER_IDENTITY_UPDATE","CART_ATTRIBUTES_UPDATE","DISCOUNT_CODES_UPDATE","createCartMachine","initialCart","createMachine","id","initial","states","uninitialized","cartCompleted","initializationError","idle","error","cartFetching","cartCreating","cartLineRemoving","cartLineUpdating","cartLineAdding","noteUpdating","buyerIdentityUpdating","cartAttributesUpdating","discountCodesUpdating","useCartAPIStateMachine","numCartLines","onCartActionEntry","onCartActionOptimisticUI","onCartActionComplete","data","cartFragment","countryCode","cartFetch","cartCreate","cartLineAdd","cartLineUpdate","cartLineRemove","noteUpdate","buyerIdentityUpdate","cartAttributesUpdate","discountCodesUpdate","useCartActions","cartMachine","useMemo","state","send","service","useMachine","cartFetchAction","type","cartId","resultEvent","eventFromFetchResult","cartCreateAction","cartLineAddAction","lines","cartLinesAdd","cartLineUpdateAction","cartLinesUpdate","cartLineRemoveAction","cartLinesRemove","noteUpdateAction","note","cartNoteUpdate","buyerIdentityUpdateAction","buyerIdentity","cartBuyerIdentityUpdate","cartAttributesUpdateAction","attributes","discountCodesUpdateAction","discountCodes","cartDiscountCodesUpdate","isCartActionEvent","isCartFetchResultEvent","flattenConnection","cartActionEvent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCartAPIStateMachine.mjs","sources":["../../src/useCartAPIStateMachine.tsx"],"sourcesContent":["import {useMachine} from '@xstate/react/fsm';\nimport {createMachine, assign, StateMachine} from '@xstate/fsm';\nimport {\n Cart,\n CartMachineActionEvent,\n CartMachineActions,\n CartMachineContext,\n CartMachineEvent,\n CartMachineFetchResultEvent,\n CartMachineTypeState,\n} from './cart-types.js';\nimport {flattenConnection} from './flatten-connection.js';\nimport {useCartActions} from './useCartActions.js';\nimport {useMemo} from 'react';\nimport {InitEvent} from '@xstate/fsm/lib/types.js';\nimport {CountryCode, Cart as CartType} from './storefront-api-types.js';\nimport type {PartialDeep} from 'type-fest';\n\nfunction invokeCart(\n action: keyof CartMachineActions,\n options?: {\n entryActions?: [keyof CartMachineActions];\n resolveTarget?: CartMachineTypeState['value'];\n errorTarget?: CartMachineTypeState['value'];\n exitActions?: [keyof CartMachineActions];\n }\n): StateMachine.Config<CartMachineContext, CartMachineEvent>['states']['on'] {\n return {\n entry: [\n ...(options?.entryActions || []),\n 'onCartActionEntry',\n 'onCartActionOptimisticUI',\n action,\n ],\n on: {\n RESOLVE: {\n target: options?.resolveTarget || 'idle',\n actions: [\n assign({\n prevCart: (context) => context?.cart,\n cart: (_, event) => event?.payload?.cart,\n rawCartResult: (_, event) => event?.payload?.rawCartResult,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n errors: (_) => undefined,\n }),\n ],\n },\n ERROR: {\n target: options?.errorTarget || 'error',\n actions: [\n assign({\n prevCart: (context) => context?.cart,\n cart: (context) => context?.lastValidCart,\n errors: (_, event) => event?.payload?.errors,\n }),\n ],\n },\n CART_COMPLETED: {\n target: 'cartCompleted',\n actions: assign({\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n prevCart: (_) => undefined,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n cart: (_) => undefined,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n lastValidCart: (_) => undefined,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n errors: (_) => undefined,\n }),\n },\n },\n exit: ['onCartActionComplete', ...(options?.exitActions || [])],\n };\n}\n\nconst INITIALIZING_CART_EVENTS: StateMachine.Machine<\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState\n>['config']['states']['uninitialized']['on'] = {\n CART_FETCH: {\n target: 'cartFetching',\n },\n CART_CREATE: {\n target: 'cartCreating',\n },\n CART_SET: {\n target: 'idle',\n actions: [\n assign({\n rawCartResult: (_, event) => event.payload.cart,\n cart: (_, event) => cartFromGraphQL(event.payload.cart),\n }),\n ],\n },\n};\n\nconst UPDATING_CART_EVENTS: StateMachine.Machine<\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState\n>['config']['states']['idle']['on'] = {\n CARTLINE_ADD: {\n target: 'cartLineAdding',\n },\n CARTLINE_UPDATE: {\n target: 'cartLineUpdating',\n },\n CARTLINE_REMOVE: {\n target: 'cartLineRemoving',\n },\n NOTE_UPDATE: {\n target: 'noteUpdating',\n },\n BUYER_IDENTITY_UPDATE: {\n target: 'buyerIdentityUpdating',\n },\n CART_ATTRIBUTES_UPDATE: {\n target: 'cartAttributesUpdating',\n },\n DISCOUNT_CODES_UPDATE: {\n target: 'discountCodesUpdating',\n },\n};\n\nfunction createCartMachine(\n initialCart?: PartialDeep<CartType, {recurseIntoArrays: true}>\n) {\n return createMachine<\n CartMachineContext,\n CartMachineEvent,\n CartMachineTypeState\n >({\n id: 'Cart',\n initial: initialCart ? 'idle' : 'uninitialized',\n context: {\n cart: initialCart && cartFromGraphQL(initialCart),\n },\n states: {\n uninitialized: {\n on: INITIALIZING_CART_EVENTS,\n },\n cartCompleted: {\n on: INITIALIZING_CART_EVENTS,\n },\n initializationError: {\n on: INITIALIZING_CART_EVENTS,\n },\n idle: {\n on: {...INITIALIZING_CART_EVENTS, ...UPDATING_CART_EVENTS},\n },\n error: {\n on: {...INITIALIZING_CART_EVENTS, ...UPDATING_CART_EVENTS},\n },\n cartFetching: invokeCart('cartFetchAction', {\n errorTarget: 'initializationError',\n }),\n cartCreating: invokeCart('cartCreateAction', {\n errorTarget: 'initializationError',\n }),\n cartLineRemoving: invokeCart('cartLineRemoveAction'),\n cartLineUpdating: invokeCart('cartLineUpdateAction'),\n cartLineAdding: invokeCart('cartLineAddAction'),\n noteUpdating: invokeCart('noteUpdateAction'),\n buyerIdentityUpdating: invokeCart('buyerIdentityUpdateAction'),\n cartAttributesUpdating: invokeCart('cartAttributesUpdateAction'),\n discountCodesUpdating: invokeCart('discountCodesUpdateAction'),\n },\n });\n}\n\nexport function useCartAPIStateMachine({\n numCartLines,\n onCartActionEntry,\n onCartActionOptimisticUI,\n onCartActionComplete,\n data: cart,\n cartFragment,\n countryCode,\n}: {\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A callback that is invoked just before a Cart API action executes. */\n onCartActionEntry?: (\n context: CartMachineContext,\n event: CartMachineActionEvent\n ) => void;\n /** A callback that is invoked after executing the entry actions for optimistic UI changes. */\n onCartActionOptimisticUI?: (\n context: CartMachineContext,\n event: CartMachineEvent\n ) => Partial<CartMachineContext>;\n /** A callback that is invoked after a Cart API completes. */\n onCartActionComplete?: (\n context: CartMachineContext,\n event: CartMachineFetchResultEvent\n ) => void;\n /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart). */\n data?: PartialDeep<CartType, {recurseIntoArrays: true}>;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment: string;\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n}) {\n const {\n cartFetch,\n cartCreate,\n cartLineAdd,\n cartLineUpdate,\n cartLineRemove,\n noteUpdate,\n buyerIdentityUpdate,\n cartAttributesUpdate,\n discountCodesUpdate,\n } = useCartActions({\n numCartLines,\n cartFragment,\n countryCode,\n });\n\n const cartMachine = useMemo(() => createCartMachine(cart), [cart]);\n\n const [state, send, service] = useMachine(cartMachine, {\n actions: {\n cartFetchAction: async (_, event): Promise<void> => {\n if (event.type !== 'CART_FETCH') return;\n\n const {data, errors} = await cartFetch(event?.payload?.cartId);\n const resultEvent = eventFromFetchResult(event, data?.cart, errors);\n send(resultEvent);\n },\n cartCreateAction: async (_, event): Promise<void> => {\n if (event.type !== 'CART_CREATE') return;\n\n const {data, errors} = await cartCreate(event?.payload);\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartCreate?.cart,\n errors\n );\n send(resultEvent);\n },\n cartLineAddAction: async (context, event): Promise<void> => {\n if (event.type !== 'CARTLINE_ADD' || !context?.cart?.id) return;\n\n const {data, errors} = await cartLineAdd(\n context.cart.id,\n event.payload.lines\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartLinesAdd?.cart,\n errors\n );\n\n send(resultEvent);\n },\n cartLineUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'CARTLINE_UPDATE' || !context?.cart?.id) return;\n const {data, errors} = await cartLineUpdate(\n context.cart.id,\n event.payload.lines\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartLinesUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n cartLineRemoveAction: async (context, event): Promise<void> => {\n if (event.type !== 'CARTLINE_REMOVE' || !context?.cart?.id) return;\n const {data, errors} = await cartLineRemove(\n context.cart.id,\n event.payload.lines\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartLinesRemove?.cart,\n errors\n );\n\n send(resultEvent);\n },\n noteUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'NOTE_UPDATE' || !context?.cart?.id) return;\n const {data, errors} = await noteUpdate(\n context.cart.id,\n event.payload.note\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartNoteUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n buyerIdentityUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'BUYER_IDENTITY_UPDATE' || !context?.cart?.id)\n return;\n const {data, errors} = await buyerIdentityUpdate(\n context.cart.id,\n event.payload.buyerIdentity\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartBuyerIdentityUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n cartAttributesUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'CART_ATTRIBUTES_UPDATE' || !context?.cart?.id)\n return;\n const {data, errors} = await cartAttributesUpdate(\n context.cart.id,\n event.payload.attributes\n );\n\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartAttributesUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n discountCodesUpdateAction: async (context, event): Promise<void> => {\n if (event.type !== 'DISCOUNT_CODES_UPDATE' || !context?.cart?.id)\n return;\n const {data, errors} = await discountCodesUpdate(\n context.cart.id,\n event.payload.discountCodes\n );\n const resultEvent = eventFromFetchResult(\n event,\n data?.cartDiscountCodesUpdate?.cart,\n errors\n );\n\n send(resultEvent);\n },\n ...(onCartActionEntry && {\n onCartActionEntry: (context, event) => {\n if (isCartActionEvent(event)) {\n onCartActionEntry(context, event);\n }\n },\n }),\n ...(onCartActionOptimisticUI && {\n onCartActionOptimisticUI: assign((context, event) => {\n return onCartActionOptimisticUI(context, event);\n }),\n }),\n ...(onCartActionComplete && {\n onCartActionComplete: (context, event) => {\n if (isCartFetchResultEvent(event)) {\n onCartActionComplete(context, event);\n }\n },\n }),\n } as CartMachineActions,\n });\n\n return useMemo(() => [state, send, service] as const, [state, send, service]);\n}\n\nexport function cartFromGraphQL(\n cart: PartialDeep<CartType, {recurseIntoArrays: true}>\n): Cart {\n return {\n ...cart,\n lines: flattenConnection(cart?.lines),\n note: cart.note ?? undefined,\n };\n}\n\nfunction eventFromFetchResult(\n cartActionEvent: CartMachineActionEvent,\n cart?: PartialDeep<CartType, {recurseIntoArrays: true}> | null,\n errors?: unknown\n): CartMachineFetchResultEvent {\n if (errors) {\n return {type: 'ERROR', payload: {errors, cartActionEvent}};\n }\n\n if (!cart) {\n return {\n type: 'CART_COMPLETED',\n payload: {\n cartActionEvent,\n },\n };\n }\n\n return {\n type: 'RESOLVE',\n payload: {\n cart: cartFromGraphQL(cart),\n rawCartResult: cart,\n cartActionEvent,\n },\n };\n}\n\nfunction isCartActionEvent(\n event: CartMachineEvent | InitEvent\n): event is CartMachineActionEvent {\n return (\n event.type === 'CART_CREATE' ||\n event.type === 'CARTLINE_ADD' ||\n event.type === 'CARTLINE_UPDATE' ||\n event.type === 'CARTLINE_REMOVE' ||\n event.type === 'NOTE_UPDATE' ||\n event.type === 'BUYER_IDENTITY_UPDATE' ||\n event.type === 'CART_ATTRIBUTES_UPDATE' ||\n event.type === 'DISCOUNT_CODES_UPDATE'\n );\n}\n\nfunction isCartFetchResultEvent(\n event: CartMachineEvent | InitEvent\n): event is CartMachineFetchResultEvent {\n return (\n event.type === 'RESOLVE' ||\n event.type === 'ERROR' ||\n event.type === 'CART_COMPLETED'\n );\n}\n"],"names":["invokeCart","action","options","entry","entryActions","on","RESOLVE","target","resolveTarget","actions","assign","prevCart","context","cart","_","event","payload","rawCartResult","errors","undefined","ERROR","errorTarget","lastValidCart","CART_COMPLETED","exit","exitActions","INITIALIZING_CART_EVENTS","CART_FETCH","CART_CREATE","CART_SET","cartFromGraphQL","UPDATING_CART_EVENTS","CARTLINE_ADD","CARTLINE_UPDATE","CARTLINE_REMOVE","NOTE_UPDATE","BUYER_IDENTITY_UPDATE","CART_ATTRIBUTES_UPDATE","DISCOUNT_CODES_UPDATE","createCartMachine","initialCart","createMachine","id","initial","states","uninitialized","cartCompleted","initializationError","idle","error","cartFetching","cartCreating","cartLineRemoving","cartLineUpdating","cartLineAdding","noteUpdating","buyerIdentityUpdating","cartAttributesUpdating","discountCodesUpdating","useCartAPIStateMachine","numCartLines","onCartActionEntry","onCartActionOptimisticUI","onCartActionComplete","data","cartFragment","countryCode","cartFetch","cartCreate","cartLineAdd","cartLineUpdate","cartLineRemove","noteUpdate","buyerIdentityUpdate","cartAttributesUpdate","discountCodesUpdate","useCartActions","cartMachine","useMemo","state","send","service","useMachine","cartFetchAction","type","cartId","resultEvent","eventFromFetchResult","cartCreateAction","cartLineAddAction","lines","cartLinesAdd","cartLineUpdateAction","cartLinesUpdate","cartLineRemoveAction","cartLinesRemove","noteUpdateAction","note","cartNoteUpdate","buyerIdentityUpdateAction","buyerIdentity","cartBuyerIdentityUpdate","cartAttributesUpdateAction","attributes","discountCodesUpdateAction","discountCodes","cartDiscountCodesUpdate","isCartActionEvent","isCartFetchResultEvent","flattenConnection","cartActionEvent"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCartActions.mjs","sources":["../../src/useCartActions.tsx"],"sourcesContent":["import {useCallback, useMemo} from 'react';\nimport {\n AttributeInput,\n CartBuyerIdentityInput,\n CartInput,\n CartLineInput,\n CartLineUpdateInput,\n CountryCode,\n Cart as CartType,\n MutationCartDiscountCodesUpdateArgs,\n MutationCartNoteUpdateArgs,\n} from './storefront-api-types.js';\nimport {\n CartAttributesUpdate,\n CartBuyerIdentityUpdate,\n CartCreate,\n CartDiscountCodesUpdate,\n CartLineAdd,\n CartLineRemove,\n CartLineUpdate,\n CartNoteUpdate,\n CartQuery,\n} from './cart-queries.js';\nimport {useCartFetch} from './cart-hooks.js';\nimport {PartialDeep} from 'type-fest';\n\ntype CartResponse = PartialDeep<CartType, {recurseIntoArrays: true}>;\n\n/**\n * The `useCartActions` hook returns helper graphql functions for Storefront Cart API\n *\n * See [cart API graphql mutations](https://shopify.dev/api/storefront/2022-10/objects/Cart)\n */\nexport function useCartActions({\n numCartLines,\n cartFragment,\n countryCode = 'US',\n}: {\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment: string;\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n}) {\n const fetchCart = useCartFetch();\n\n const cartFetch = useCallback(\n (cartId: string) => {\n return fetchCart<{cart: CartResponse}>({\n query: CartQuery(cartFragment),\n variables: {\n id: cartId,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [fetchCart, cartFragment, numCartLines, countryCode]\n );\n\n const cartCreate = useCallback(\n (cart: CartInput) => {\n return fetchCart<{cartCreate: {cart: CartResponse}}>({\n query: CartCreate(cartFragment),\n variables: {\n input: cart,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartLineAdd = useCallback(\n (cartId: string, lines: CartLineInput[]) => {\n return fetchCart<{cartLinesAdd: {cart: CartResponse}}>({\n query: CartLineAdd(cartFragment),\n variables: {\n cartId,\n lines,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartLineUpdate = useCallback(\n (cartId: string, lines: CartLineUpdateInput[]) => {\n return fetchCart<{cartLinesUpdate: {cart: CartResponse}}>({\n query: CartLineUpdate(cartFragment),\n variables: {\n cartId,\n lines,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartLineRemove = useCallback(\n (cartId: string, lines: string[]) => {\n return fetchCart<{cartLinesRemove: {cart: CartResponse}}>({\n query: CartLineRemove(cartFragment),\n variables: {\n cartId,\n lines,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const noteUpdate = useCallback(\n (cartId: string, note: MutationCartNoteUpdateArgs['note']) => {\n return fetchCart<{cartNoteUpdate: {cart: CartResponse}}>({\n query: CartNoteUpdate(cartFragment),\n variables: {\n cartId,\n note,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [fetchCart, cartFragment, numCartLines, countryCode]\n );\n\n const buyerIdentityUpdate = useCallback(\n (cartId: string, buyerIdentity: CartBuyerIdentityInput) => {\n return fetchCart<{cartBuyerIdentityUpdate: {cart: CartResponse}}>({\n query: CartBuyerIdentityUpdate(cartFragment),\n variables: {\n cartId,\n buyerIdentity,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartAttributesUpdate = useCallback(\n (cartId: string, attributes: AttributeInput[]) => {\n return fetchCart<{cartAttributesUpdate: {cart: CartResponse}}>({\n query: CartAttributesUpdate(cartFragment),\n variables: {\n cartId,\n attributes,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const discountCodesUpdate = useCallback(\n (\n cartId: string,\n discountCodes: MutationCartDiscountCodesUpdateArgs['discountCodes']\n ) => {\n return fetchCart<{cartDiscountCodesUpdate: {cart: CartResponse}}>({\n query: CartDiscountCodesUpdate(cartFragment),\n variables: {\n cartId,\n discountCodes,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n return useMemo(\n () => ({\n cartFetch,\n cartCreate,\n cartLineAdd,\n cartLineUpdate,\n cartLineRemove,\n noteUpdate,\n buyerIdentityUpdate,\n cartAttributesUpdate,\n discountCodesUpdate,\n cartFragment,\n }),\n [\n cartFetch,\n cartCreate,\n cartLineAdd,\n cartLineUpdate,\n cartLineRemove,\n noteUpdate,\n buyerIdentityUpdate,\n cartAttributesUpdate,\n discountCodesUpdate,\n cartFragment,\n ]\n );\n}\n"],"names":["useCartActions","numCartLines","cartFragment","countryCode","fetchCart","useCartFetch","cartFetch","useCallback","cartId","query","CartQuery","variables","id","country","cartCreate","cart","CartCreate","input","cartLineAdd","lines","CartLineAdd","cartLineUpdate","CartLineUpdate","cartLineRemove","CartLineRemove","noteUpdate","note","CartNoteUpdate","buyerIdentityUpdate","buyerIdentity","CartBuyerIdentityUpdate","cartAttributesUpdate","attributes","CartAttributesUpdate","discountCodesUpdate","discountCodes","CartDiscountCodesUpdate","useMemo"],"mappings":";;;AAiCO,SAASA,eAAe;AAAA,EAC7BC;AAAAA,EACAC;AAAAA,EACAC,cAAc;
|
|
1
|
+
{"version":3,"file":"useCartActions.mjs","sources":["../../src/useCartActions.tsx"],"sourcesContent":["import {useCallback, useMemo} from 'react';\nimport {\n AttributeInput,\n CartBuyerIdentityInput,\n CartInput,\n CartLineInput,\n CartLineUpdateInput,\n CountryCode,\n Cart as CartType,\n MutationCartDiscountCodesUpdateArgs,\n MutationCartNoteUpdateArgs,\n} from './storefront-api-types.js';\nimport {\n CartAttributesUpdate,\n CartBuyerIdentityUpdate,\n CartCreate,\n CartDiscountCodesUpdate,\n CartLineAdd,\n CartLineRemove,\n CartLineUpdate,\n CartNoteUpdate,\n CartQuery,\n} from './cart-queries.js';\nimport {useCartFetch} from './cart-hooks.js';\nimport {PartialDeep} from 'type-fest';\n\ntype CartResponse = PartialDeep<CartType, {recurseIntoArrays: true}>;\n\n/**\n * The `useCartActions` hook returns helper graphql functions for Storefront Cart API\n *\n * See [cart API graphql mutations](https://shopify.dev/api/storefront/2022-10/objects/Cart)\n */\nexport function useCartActions({\n numCartLines,\n cartFragment,\n countryCode = 'US',\n}: {\n /** Maximum number of cart lines to fetch. Defaults to 250 cart lines. */\n numCartLines?: number;\n /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/latest/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */\n cartFragment: string;\n /** The ISO country code for i18n. */\n countryCode?: CountryCode;\n}) {\n const fetchCart = useCartFetch();\n\n const cartFetch = useCallback(\n (cartId: string) => {\n return fetchCart<{cart: CartResponse}>({\n query: CartQuery(cartFragment),\n variables: {\n id: cartId,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [fetchCart, cartFragment, numCartLines, countryCode]\n );\n\n const cartCreate = useCallback(\n (cart: CartInput) => {\n return fetchCart<{cartCreate: {cart: CartResponse}}>({\n query: CartCreate(cartFragment),\n variables: {\n input: cart,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartLineAdd = useCallback(\n (cartId: string, lines: CartLineInput[]) => {\n return fetchCart<{cartLinesAdd: {cart: CartResponse}}>({\n query: CartLineAdd(cartFragment),\n variables: {\n cartId,\n lines,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartLineUpdate = useCallback(\n (cartId: string, lines: CartLineUpdateInput[]) => {\n return fetchCart<{cartLinesUpdate: {cart: CartResponse}}>({\n query: CartLineUpdate(cartFragment),\n variables: {\n cartId,\n lines,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartLineRemove = useCallback(\n (cartId: string, lines: string[]) => {\n return fetchCart<{cartLinesRemove: {cart: CartResponse}}>({\n query: CartLineRemove(cartFragment),\n variables: {\n cartId,\n lines,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const noteUpdate = useCallback(\n (cartId: string, note: MutationCartNoteUpdateArgs['note']) => {\n return fetchCart<{cartNoteUpdate: {cart: CartResponse}}>({\n query: CartNoteUpdate(cartFragment),\n variables: {\n cartId,\n note,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [fetchCart, cartFragment, numCartLines, countryCode]\n );\n\n const buyerIdentityUpdate = useCallback(\n (cartId: string, buyerIdentity: CartBuyerIdentityInput) => {\n return fetchCart<{cartBuyerIdentityUpdate: {cart: CartResponse}}>({\n query: CartBuyerIdentityUpdate(cartFragment),\n variables: {\n cartId,\n buyerIdentity,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const cartAttributesUpdate = useCallback(\n (cartId: string, attributes: AttributeInput[]) => {\n return fetchCart<{cartAttributesUpdate: {cart: CartResponse}}>({\n query: CartAttributesUpdate(cartFragment),\n variables: {\n cartId,\n attributes,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n const discountCodesUpdate = useCallback(\n (\n cartId: string,\n discountCodes: MutationCartDiscountCodesUpdateArgs['discountCodes']\n ) => {\n return fetchCart<{cartDiscountCodesUpdate: {cart: CartResponse}}>({\n query: CartDiscountCodesUpdate(cartFragment),\n variables: {\n cartId,\n discountCodes,\n numCartLines,\n country: countryCode,\n },\n });\n },\n [cartFragment, countryCode, fetchCart, numCartLines]\n );\n\n return useMemo(\n () => ({\n cartFetch,\n cartCreate,\n cartLineAdd,\n cartLineUpdate,\n cartLineRemove,\n noteUpdate,\n buyerIdentityUpdate,\n cartAttributesUpdate,\n discountCodesUpdate,\n cartFragment,\n }),\n [\n cartFetch,\n cartCreate,\n cartLineAdd,\n cartLineUpdate,\n cartLineRemove,\n noteUpdate,\n buyerIdentityUpdate,\n cartAttributesUpdate,\n discountCodesUpdate,\n cartFragment,\n ]\n );\n}\n"],"names":["useCartActions","numCartLines","cartFragment","countryCode","fetchCart","useCartFetch","cartFetch","useCallback","cartId","query","CartQuery","variables","id","country","cartCreate","cart","CartCreate","input","cartLineAdd","lines","CartLineAdd","cartLineUpdate","CartLineUpdate","cartLineRemove","CartLineRemove","noteUpdate","note","CartNoteUpdate","buyerIdentityUpdate","buyerIdentity","CartBuyerIdentityUpdate","cartAttributesUpdate","attributes","CartAttributesUpdate","discountCodesUpdate","discountCodes","CartDiscountCodesUpdate","useMemo"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMoney.mjs","sources":["../../src/useMoney.tsx"],"sourcesContent":["import {useMemo} from 'react';\nimport {useShop} from './ShopifyProvider.js';\nimport {CurrencyCode, MoneyV2} from './storefront-api-types.js';\n\nexport type UseMoneyValue = {\n /**\n * The currency code from the `MoneyV2` object.\n */\n currencyCode: CurrencyCode;\n /**\n * The name for the currency code, returned by `Intl.NumberFormat`.\n */\n currencyName?: string;\n /**\n * The currency symbol returned by `Intl.NumberFormat`.\n */\n currencySymbol?: string;\n /**\n * The currency narrow symbol returned by `Intl.NumberFormat`.\n */\n currencyNarrowSymbol?: string;\n /**\n * The localized amount, without any currency symbols or non-number types from the `Intl.NumberFormat.formatToParts` parts.\n */\n amount: string;\n /**\n * All parts returned by `Intl.NumberFormat.formatToParts`.\n */\n parts: Intl.NumberFormatPart[];\n /**\n * A string returned by `new Intl.NumberFormat` for the amount and currency code,\n * using the `locale` value in the [`LocalizationProvider` component](https://shopify.dev/api/hydrogen/components/localization/localizationprovider).\n */\n localizedString: string;\n /**\n * The `MoneyV2` object provided as an argument to the hook.\n */\n original: MoneyV2;\n /**\n * A string with trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.\n * For example, `$640.00` turns into `$640`.\n * `$640.42` remains `$640.42`.\n */\n withoutTrailingZeros: string;\n /**\n * A string without currency and without trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.\n * For example, `$640.00` turns into `640`.\n * `$640.42` turns into `640.42`.\n */\n withoutTrailingZerosAndCurrency: string;\n};\n\n/**\n * The `useMoney` hook takes a [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) and returns a\n * default-formatted string of the amount with the correct currency indicator, along with some of the parts provided by\n * [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat).\n * Uses `locale` from `ShopifyProvider`\n */\nexport function useMoney(money: MoneyV2): UseMoneyValue {\n const {locale} = useShop();\n\n if (!locale) {\n throw new Error(\n `useMoney(): Unable to get 'locale' from 'useShop()', which means that 'locale' was not passed to '<ShopifyProvider/>'. 'locale' is required for 'useMoney()' to work`\n );\n }\n\n const amount = parseFloat(money.amount);\n\n const options = useMemo(\n () => ({\n style: 'currency',\n currency: money.currencyCode,\n }),\n [money.currencyCode]\n );\n\n const defaultFormatter = useLazyFormatter(locale, options);\n\n const nameFormatter = useLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'name',\n });\n\n const narrowSymbolFormatter = useLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'narrowSymbol',\n });\n\n const withoutTrailingZerosFormatter = useLazyFormatter(locale, {\n ...options,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n });\n\n const withoutCurrencyFormatter = useLazyFormatter(locale);\n\n const withoutTrailingZerosOrCurrencyFormatter = useLazyFormatter(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n });\n\n const isPartCurrency = (part: Intl.NumberFormatPart) =>\n part.type === 'currency';\n\n // By wrapping these properties in functions, we only\n // create formatters if they are going to be used.\n const lazyFormatters = useMemo(\n () => ({\n original: () => money,\n currencyCode: () => money.currencyCode,\n\n localizedString: () => defaultFormatter().format(amount),\n\n parts: () => defaultFormatter().formatToParts(amount),\n\n withoutTrailingZeros: () =>\n amount % 1 === 0\n ? withoutTrailingZerosFormatter().format(amount)\n : defaultFormatter().format(amount),\n\n withoutTrailingZerosAndCurrency: () =>\n amount % 1 === 0\n ? withoutTrailingZerosOrCurrencyFormatter().format(amount)\n : withoutCurrencyFormatter().format(amount),\n\n currencyName: () =>\n nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"US dollars\"\n\n currencySymbol: () =>\n defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"USD\"\n\n currencyNarrowSymbol: () =>\n narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)\n ?.value ?? '', // e.g. \"$\"\n\n amount: () =>\n defaultFormatter()\n .formatToParts(amount)\n .filter((part) =>\n ['decimal', 'fraction', 'group', 'integer', 'literal'].includes(\n part.type\n )\n )\n .map((part) => part.value)\n .join(''),\n }),\n [\n money,\n amount,\n nameFormatter,\n defaultFormatter,\n narrowSymbolFormatter,\n withoutCurrencyFormatter,\n withoutTrailingZerosFormatter,\n withoutTrailingZerosOrCurrencyFormatter,\n ]\n );\n\n // Call functions automatically when the properties are accessed\n // to keep these functions as an implementation detail.\n return useMemo(\n () =>\n new Proxy(lazyFormatters as unknown as UseMoneyValue, {\n get: (target, key) => Reflect.get(target, key)?.call(null),\n }),\n [lazyFormatters]\n );\n}\n\nfunction useLazyFormatter(locale: string, options?: Intl.NumberFormatOptions) {\n return useMemo(() => {\n let memoized: Intl.NumberFormat;\n return () => (memoized ??= new Intl.NumberFormat(locale, options));\n }, [locale, options]);\n}\n"],"names":["useMoney","money","locale","useShop","Error","amount","parseFloat","options","useMemo","style","currency","currencyCode","defaultFormatter","useLazyFormatter","nameFormatter","currencyDisplay","narrowSymbolFormatter","withoutTrailingZerosFormatter","minimumFractionDigits","maximumFractionDigits","withoutCurrencyFormatter","withoutTrailingZerosOrCurrencyFormatter","isPartCurrency","part","type","lazyFormatters","original","localizedString","format","parts","formatToParts","withoutTrailingZeros","withoutTrailingZerosAndCurrency","currencyName","find","value","currencySymbol","currencyNarrowSymbol","filter","includes","map","join","Proxy","get","target","key","Reflect","call","memoized","Intl","NumberFormat"],"mappings":";;AA0DO,SAASA,SAASC,OAA+B;AAChD,QAAA;AAAA,IAACC;AAAAA,MAAUC,
|
|
1
|
+
{"version":3,"file":"useMoney.mjs","sources":["../../src/useMoney.tsx"],"sourcesContent":["import {useMemo} from 'react';\nimport {useShop} from './ShopifyProvider.js';\nimport {CurrencyCode, MoneyV2} from './storefront-api-types.js';\n\nexport type UseMoneyValue = {\n /**\n * The currency code from the `MoneyV2` object.\n */\n currencyCode: CurrencyCode;\n /**\n * The name for the currency code, returned by `Intl.NumberFormat`.\n */\n currencyName?: string;\n /**\n * The currency symbol returned by `Intl.NumberFormat`.\n */\n currencySymbol?: string;\n /**\n * The currency narrow symbol returned by `Intl.NumberFormat`.\n */\n currencyNarrowSymbol?: string;\n /**\n * The localized amount, without any currency symbols or non-number types from the `Intl.NumberFormat.formatToParts` parts.\n */\n amount: string;\n /**\n * All parts returned by `Intl.NumberFormat.formatToParts`.\n */\n parts: Intl.NumberFormatPart[];\n /**\n * A string returned by `new Intl.NumberFormat` for the amount and currency code,\n * using the `locale` value in the [`LocalizationProvider` component](https://shopify.dev/api/hydrogen/components/localization/localizationprovider).\n */\n localizedString: string;\n /**\n * The `MoneyV2` object provided as an argument to the hook.\n */\n original: MoneyV2;\n /**\n * A string with trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.\n * For example, `$640.00` turns into `$640`.\n * `$640.42` remains `$640.42`.\n */\n withoutTrailingZeros: string;\n /**\n * A string without currency and without trailing zeros removed from the fractional part, if any exist. If there are no trailing zeros, then the fractional part remains.\n * For example, `$640.00` turns into `640`.\n * `$640.42` turns into `640.42`.\n */\n withoutTrailingZerosAndCurrency: string;\n};\n\n/**\n * The `useMoney` hook takes a [MoneyV2 object](https://shopify.dev/api/storefront/reference/common-objects/moneyv2) and returns a\n * default-formatted string of the amount with the correct currency indicator, along with some of the parts provided by\n * [Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat).\n * Uses `locale` from `ShopifyProvider`\n */\nexport function useMoney(money: MoneyV2): UseMoneyValue {\n const {locale} = useShop();\n\n if (!locale) {\n throw new Error(\n `useMoney(): Unable to get 'locale' from 'useShop()', which means that 'locale' was not passed to '<ShopifyProvider/>'. 'locale' is required for 'useMoney()' to work`\n );\n }\n\n const amount = parseFloat(money.amount);\n\n const options = useMemo(\n () => ({\n style: 'currency',\n currency: money.currencyCode,\n }),\n [money.currencyCode]\n );\n\n const defaultFormatter = useLazyFormatter(locale, options);\n\n const nameFormatter = useLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'name',\n });\n\n const narrowSymbolFormatter = useLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'narrowSymbol',\n });\n\n const withoutTrailingZerosFormatter = useLazyFormatter(locale, {\n ...options,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n });\n\n const withoutCurrencyFormatter = useLazyFormatter(locale);\n\n const withoutTrailingZerosOrCurrencyFormatter = useLazyFormatter(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n });\n\n const isPartCurrency = (part: Intl.NumberFormatPart) =>\n part.type === 'currency';\n\n // By wrapping these properties in functions, we only\n // create formatters if they are going to be used.\n const lazyFormatters = useMemo(\n () => ({\n original: () => money,\n currencyCode: () => money.currencyCode,\n\n localizedString: () => defaultFormatter().format(amount),\n\n parts: () => defaultFormatter().formatToParts(amount),\n\n withoutTrailingZeros: () =>\n amount % 1 === 0\n ? withoutTrailingZerosFormatter().format(amount)\n : defaultFormatter().format(amount),\n\n withoutTrailingZerosAndCurrency: () =>\n amount % 1 === 0\n ? withoutTrailingZerosOrCurrencyFormatter().format(amount)\n : withoutCurrencyFormatter().format(amount),\n\n currencyName: () =>\n nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"US dollars\"\n\n currencySymbol: () =>\n defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"USD\"\n\n currencyNarrowSymbol: () =>\n narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)\n ?.value ?? '', // e.g. \"$\"\n\n amount: () =>\n defaultFormatter()\n .formatToParts(amount)\n .filter((part) =>\n ['decimal', 'fraction', 'group', 'integer', 'literal'].includes(\n part.type\n )\n )\n .map((part) => part.value)\n .join(''),\n }),\n [\n money,\n amount,\n nameFormatter,\n defaultFormatter,\n narrowSymbolFormatter,\n withoutCurrencyFormatter,\n withoutTrailingZerosFormatter,\n withoutTrailingZerosOrCurrencyFormatter,\n ]\n );\n\n // Call functions automatically when the properties are accessed\n // to keep these functions as an implementation detail.\n return useMemo(\n () =>\n new Proxy(lazyFormatters as unknown as UseMoneyValue, {\n get: (target, key) => Reflect.get(target, key)?.call(null),\n }),\n [lazyFormatters]\n );\n}\n\nfunction useLazyFormatter(locale: string, options?: Intl.NumberFormatOptions) {\n return useMemo(() => {\n let memoized: Intl.NumberFormat;\n return () => (memoized ??= new Intl.NumberFormat(locale, options));\n }, [locale, options]);\n}\n"],"names":["useMoney","money","locale","useShop","Error","amount","parseFloat","options","useMemo","style","currency","currencyCode","defaultFormatter","useLazyFormatter","nameFormatter","currencyDisplay","narrowSymbolFormatter","withoutTrailingZerosFormatter","minimumFractionDigits","maximumFractionDigits","withoutCurrencyFormatter","withoutTrailingZerosOrCurrencyFormatter","isPartCurrency","part","type","lazyFormatters","original","localizedString","format","parts","formatToParts","withoutTrailingZeros","withoutTrailingZerosAndCurrency","currencyName","find","value","currencySymbol","currencyNarrowSymbol","filter","includes","map","join","Proxy","get","target","key","Reflect","call","memoized","Intl","NumberFormat"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AddToCartButton.mjs","sources":["../../src/AddToCartButton.tsx"],"sourcesContent":["import {useCallback, useEffect, useState} from 'react';\n\nimport {useCart} from './CartProvider.js';\nimport {useProduct} from './ProductProvider.js';\nimport {BaseButton, BaseButtonProps} from './BaseButton.js';\n\nexport interface AddToCartButtonProps {\n /** An array of cart line attributes that belong to the item being added to the cart. */\n attributes?: {\n key: string;\n value: string;\n }[];\n /** The ID of the variant. */\n variantId?: string | null;\n /** The item quantity. */\n quantity?: number;\n /** The text that is announced by the screen reader when the item is being added to the cart. Used for accessibility purposes only and not displayed on the page. */\n accessibleAddingToCartLabel?: string;\n /** The selling plan ID of the subscription variant */\n sellingPlanId?: string;\n}\n\n/**\n * The `AddToCartButton` component renders a button that adds an item to the cart when pressed.\n * It must be a descendent of the `CartProvider` component.\n */\nexport function AddToCartButton<AsType extends React.ElementType = 'button'>(\n props: AddToCartButtonProps & BaseButtonProps<AsType>\n) {\n const [addingItem, setAddingItem] = useState<boolean>(false);\n const {\n variantId: explicitVariantId,\n quantity = 1,\n attributes,\n sellingPlanId,\n onClick,\n children,\n accessibleAddingToCartLabel,\n ...passthroughProps\n } = props;\n const {status, linesAdd} = useCart();\n const {selectedVariant} = useProduct();\n const variantId = explicitVariantId ?? selectedVariant?.id ?? '';\n const disabled =\n explicitVariantId === null ||\n variantId === '' ||\n selectedVariant === null ||\n addingItem ||\n passthroughProps.disabled;\n\n useEffect(() => {\n if (addingItem && status === 'idle') {\n setAddingItem(false);\n }\n }, [status, addingItem]);\n\n const handleAddItem = useCallback(() => {\n setAddingItem(true);\n linesAdd([\n {\n quantity,\n merchandiseId: variantId || '',\n attributes,\n sellingPlanId,\n },\n ]);\n }, [linesAdd, quantity, variantId, attributes, sellingPlanId]);\n\n return (\n <>\n <BaseButton\n {...passthroughProps}\n disabled={disabled}\n onClick={onClick}\n defaultOnClick={handleAddItem}\n >\n {children}\n </BaseButton>\n {accessibleAddingToCartLabel ? (\n <p\n style={{\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n borderWidth: '0',\n }}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {addingItem ? accessibleAddingToCartLabel : null}\n </p>\n ) : null}\n </>\n );\n}\n"],"names":["AddToCartButton","props","addingItem","setAddingItem","useState","variantId","explicitVariantId","quantity","attributes","sellingPlanId","onClick","children","accessibleAddingToCartLabel","passthroughProps","status","linesAdd","useCart","selectedVariant","useProduct","id","disabled","useEffect","handleAddItem","useCallback","merchandiseId","_Fragment","_jsx","position","width","height","padding","margin","overflow","clip","whiteSpace","borderWidth"],"mappings":";;;;;AA0BO,SAASA,gBACdC,OACA;;AACA,QAAM,CAACC,YAAYC,
|
|
1
|
+
{"version":3,"file":"AddToCartButton.mjs","sources":["../../src/AddToCartButton.tsx"],"sourcesContent":["import {useCallback, useEffect, useState} from 'react';\n\nimport {useCart} from './CartProvider.js';\nimport {useProduct} from './ProductProvider.js';\nimport {BaseButton, BaseButtonProps} from './BaseButton.js';\n\nexport interface AddToCartButtonProps {\n /** An array of cart line attributes that belong to the item being added to the cart. */\n attributes?: {\n key: string;\n value: string;\n }[];\n /** The ID of the variant. */\n variantId?: string | null;\n /** The item quantity. */\n quantity?: number;\n /** The text that is announced by the screen reader when the item is being added to the cart. Used for accessibility purposes only and not displayed on the page. */\n accessibleAddingToCartLabel?: string;\n /** The selling plan ID of the subscription variant */\n sellingPlanId?: string;\n}\n\n/**\n * The `AddToCartButton` component renders a button that adds an item to the cart when pressed.\n * It must be a descendent of the `CartProvider` component.\n */\nexport function AddToCartButton<AsType extends React.ElementType = 'button'>(\n props: AddToCartButtonProps & BaseButtonProps<AsType>\n) {\n const [addingItem, setAddingItem] = useState<boolean>(false);\n const {\n variantId: explicitVariantId,\n quantity = 1,\n attributes,\n sellingPlanId,\n onClick,\n children,\n accessibleAddingToCartLabel,\n ...passthroughProps\n } = props;\n const {status, linesAdd} = useCart();\n const {selectedVariant} = useProduct();\n const variantId = explicitVariantId ?? selectedVariant?.id ?? '';\n const disabled =\n explicitVariantId === null ||\n variantId === '' ||\n selectedVariant === null ||\n addingItem ||\n passthroughProps.disabled;\n\n useEffect(() => {\n if (addingItem && status === 'idle') {\n setAddingItem(false);\n }\n }, [status, addingItem]);\n\n const handleAddItem = useCallback(() => {\n setAddingItem(true);\n linesAdd([\n {\n quantity,\n merchandiseId: variantId || '',\n attributes,\n sellingPlanId,\n },\n ]);\n }, [linesAdd, quantity, variantId, attributes, sellingPlanId]);\n\n return (\n <>\n <BaseButton\n {...passthroughProps}\n disabled={disabled}\n onClick={onClick}\n defaultOnClick={handleAddItem}\n >\n {children}\n </BaseButton>\n {accessibleAddingToCartLabel ? (\n <p\n style={{\n position: 'absolute',\n width: '1px',\n height: '1px',\n padding: '0',\n margin: '-1px',\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n borderWidth: '0',\n }}\n role=\"alert\"\n aria-live=\"assertive\"\n >\n {addingItem ? accessibleAddingToCartLabel : null}\n </p>\n ) : null}\n </>\n );\n}\n"],"names":["AddToCartButton","props","addingItem","setAddingItem","useState","variantId","explicitVariantId","quantity","attributes","sellingPlanId","onClick","children","accessibleAddingToCartLabel","passthroughProps","status","linesAdd","useCart","selectedVariant","useProduct","id","disabled","useEffect","handleAddItem","useCallback","merchandiseId","_Fragment","_jsx","position","width","height","padding","margin","overflow","clip","whiteSpace","borderWidth"],"mappings":";;;;;AA0BO,SAASA,gBACdC,OACA;;AACA,QAAM,CAACC,YAAYC,aAAa,IAAIC,SAAkB,KAAK;AACrD,QAAA;AAAA,IACJC,WAAWC;AAAAA,IACXC,WAAW;AAAA,IACXC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,OACGC;AAAAA,EACDZ,IAAAA;AACE,QAAA;AAAA,IAACa;AAAAA,IAAQC;AAAAA,MAAYC,QAAS;AAC9B,QAAA;AAAA,IAACC;AAAAA,MAAmBC,WAAY;AAChCb,QAAAA,aAAYC,qDAAqBW,mDAAiBE,OAAtCb,YAA4C;AACxDc,QAAAA,WACJd,sBAAsB,QACtBD,cAAc,MACdY,oBAAoB,QACpBf,cACAW,iBAAiBO;AAEnBC,YAAU,MAAM;AACVnB,QAAAA,cAAcY,WAAW,QAAQ;AACnCX,oBAAc,KAAK;AAAA,IACrB;AAAA,EAAA,GACC,CAACW,QAAQZ,UAAU,CAAC;AAEjBoB,QAAAA,gBAAgBC,YAAY,MAAM;AACtCpB,kBAAc,IAAI;AAClBY,aAAS,CACP;AAAA,MACER;AAAAA,MACAiB,eAAenB,aAAa;AAAA,MAC5BG;AAAAA,MACAC;AAAAA,IACD,CAAA,CACF;AAAA,EAAA,GACA,CAACM,UAAUR,UAAUF,WAAWG,YAAYC,aAAa,CAAC;AAE7D,8BACEgB,UAAA;AAAA,IAAA,UAAA,CACEC,oBAAC,YAAU;AAAA,MAAA,GACLb;AAAAA,MACJ;AAAA,MACA;AAAA,MACA,gBAAgBS;AAAAA,MAAc;AAAA,IAAA,CAGnB,GACZV,8BACCc,oBAAA,KAAA;AAAA,MACE,OAAO;AAAA,QACLC,UAAU;AAAA,QACVC,OAAO;AAAA,QACPC,QAAQ;AAAA,QACRC,SAAS;AAAA,QACTC,QAAQ;AAAA,QACRC,UAAU;AAAA,QACVC,MAAM;AAAA,QACNC,YAAY;AAAA,QACZC,aAAa;AAAA,MACf;AAAA,MACA,MAAK;AAAA,MACL,aAAU;AAAA,MAAW,UAEpBjC,aAAaU,8BAA8B;AAAA,IAAI,CAAA,IAEhD,IAAI;AAAA,EAAA,CACP;AAEP;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseButton.mjs","sources":["../../src/BaseButton.tsx"],"sourcesContent":["import {ReactNode, Ref, useCallback} from 'react';\n\nexport interface CustomBaseButtonProps<AsType> {\n /** Provide a React element or component to render as the underlying button. Note: for accessibility compliance, almost always you should use a `button` element, or a component that renders an underlying button. */\n as?: AsType;\n /** Any ReactNode elements. */\n children: ReactNode;\n /** Click event handler. Default behaviour triggers unless prevented */\n onClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A default onClick behavior */\n defaultOnClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A ref to the underlying button */\n buttonRef?: Ref<HTMLButtonElement>;\n}\n\nexport type BaseButtonProps<AsType extends React.ElementType> =\n CustomBaseButtonProps<AsType> &\n Omit<\n React.ComponentPropsWithoutRef<AsType>,\n keyof CustomBaseButtonProps<AsType>\n >;\n\nexport function BaseButton<AsType extends React.ElementType = 'button'>(\n props: BaseButtonProps<AsType>\n) {\n const {\n as,\n onClick,\n defaultOnClick,\n children,\n buttonRef,\n ...passthroughProps\n } = props;\n\n const handleOnClick = useCallback(\n (event?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n if (onClick) {\n const clickShouldContinue = onClick(event);\n if (\n (typeof clickShouldContinue === 'boolean' &&\n clickShouldContinue === false) ||\n event?.defaultPrevented\n )\n return;\n }\n\n defaultOnClick?.(event);\n },\n [defaultOnClick, onClick]\n );\n\n const Component = as || 'button';\n\n return (\n <Component ref={buttonRef} onClick={handleOnClick} {...passthroughProps}>\n {children}\n </Component>\n );\n}\n"],"names":["BaseButton","props","as","onClick","defaultOnClick","children","buttonRef","passthroughProps","handleOnClick","useCallback","event","clickShouldContinue","defaultPrevented","Component"],"mappings":";;AA0BO,SAASA,WACdC,OACA;AACM,QAAA;AAAA,IACJC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,OACGC;AAAAA,EACDN,IAAAA;AAEEO,QAAAA,gBAAgBC,YACpB,CAACC,UAA4D;AAC3D,QAAIP,SAAS;AACLQ,YAAAA,sBAAsBR,QAAQO,
|
|
1
|
+
{"version":3,"file":"BaseButton.mjs","sources":["../../src/BaseButton.tsx"],"sourcesContent":["import {ReactNode, Ref, useCallback} from 'react';\n\nexport interface CustomBaseButtonProps<AsType> {\n /** Provide a React element or component to render as the underlying button. Note: for accessibility compliance, almost always you should use a `button` element, or a component that renders an underlying button. */\n as?: AsType;\n /** Any ReactNode elements. */\n children: ReactNode;\n /** Click event handler. Default behaviour triggers unless prevented */\n onClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A default onClick behavior */\n defaultOnClick?: (\n event?: React.MouseEvent<HTMLButtonElement, MouseEvent>\n ) => void | boolean;\n /** A ref to the underlying button */\n buttonRef?: Ref<HTMLButtonElement>;\n}\n\nexport type BaseButtonProps<AsType extends React.ElementType> =\n CustomBaseButtonProps<AsType> &\n Omit<\n React.ComponentPropsWithoutRef<AsType>,\n keyof CustomBaseButtonProps<AsType>\n >;\n\nexport function BaseButton<AsType extends React.ElementType = 'button'>(\n props: BaseButtonProps<AsType>\n) {\n const {\n as,\n onClick,\n defaultOnClick,\n children,\n buttonRef,\n ...passthroughProps\n } = props;\n\n const handleOnClick = useCallback(\n (event?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {\n if (onClick) {\n const clickShouldContinue = onClick(event);\n if (\n (typeof clickShouldContinue === 'boolean' &&\n clickShouldContinue === false) ||\n event?.defaultPrevented\n )\n return;\n }\n\n defaultOnClick?.(event);\n },\n [defaultOnClick, onClick]\n );\n\n const Component = as || 'button';\n\n return (\n <Component ref={buttonRef} onClick={handleOnClick} {...passthroughProps}>\n {children}\n </Component>\n );\n}\n"],"names":["BaseButton","props","as","onClick","defaultOnClick","children","buttonRef","passthroughProps","handleOnClick","useCallback","event","clickShouldContinue","defaultPrevented","Component"],"mappings":";;AA0BO,SAASA,WACdC,OACA;AACM,QAAA;AAAA,IACJC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,IACAC;AAAAA,OACGC;AAAAA,EACDN,IAAAA;AAEEO,QAAAA,gBAAgBC,YACpB,CAACC,UAA4D;AAC3D,QAAIP,SAAS;AACLQ,YAAAA,sBAAsBR,QAAQO,KAAK;AACzC,UACG,OAAOC,wBAAwB,aAC9BA,wBAAwB,UAC1BD,+BAAOE;AAEP;AAAA,IACJ;AAEAR,qDAAiBM;AAAAA,EAAK,GAExB,CAACN,gBAAgBD,OAAO,CAAC;AAG3B,QAAMU,YAAYX,MAAM;AAExB,6BACG,WAAS;AAAA,IAAC,KAAKI;AAAAA,IAAW,SAASE;AAAAA,IAAc,GAAKD;AAAAA,IAAgB;AAAA,EAAA,CAE3D;AAEhB;"}
|