@shopify/hydrogen-react 2025.10.0 → 2026.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/customer-account.schema.json +1 -1
  2. package/dist/browser-dev/CartLineProvider.mjs.map +1 -1
  3. package/dist/browser-dev/CartProvider.mjs.map +1 -1
  4. package/dist/browser-dev/Image.mjs.map +1 -1
  5. package/dist/browser-dev/ModelViewer.mjs.map +1 -1
  6. package/dist/browser-dev/Money.mjs.map +1 -1
  7. package/dist/browser-dev/Video.mjs.map +1 -1
  8. package/dist/browser-dev/cart-queries.mjs +1 -1
  9. package/dist/browser-dev/cart-queries.mjs.map +1 -1
  10. package/dist/browser-dev/codegen.helpers.mjs.map +1 -1
  11. package/dist/browser-dev/optionValueDecoder.mjs.map +1 -1
  12. package/dist/browser-dev/packages/hydrogen-react/package.json.mjs +1 -1
  13. package/dist/browser-dev/storefront-api-constants.mjs +1 -1
  14. package/dist/browser-dev/storefront-api-constants.mjs.map +1 -1
  15. package/dist/browser-dev/storefront-client.mjs +0 -1
  16. package/dist/browser-dev/storefront-client.mjs.map +1 -1
  17. package/dist/browser-dev/useCartAPIStateMachine.mjs.map +1 -1
  18. package/dist/browser-dev/useCartActions.mjs.map +1 -1
  19. package/dist/browser-dev/useMoney.mjs.map +1 -1
  20. package/dist/browser-prod/CartLineProvider.mjs.map +1 -1
  21. package/dist/browser-prod/CartProvider.mjs.map +1 -1
  22. package/dist/browser-prod/Image.mjs.map +1 -1
  23. package/dist/browser-prod/ModelViewer.mjs.map +1 -1
  24. package/dist/browser-prod/Money.mjs.map +1 -1
  25. package/dist/browser-prod/Video.mjs.map +1 -1
  26. package/dist/browser-prod/cart-queries.mjs +1 -1
  27. package/dist/browser-prod/cart-queries.mjs.map +1 -1
  28. package/dist/browser-prod/codegen.helpers.mjs.map +1 -1
  29. package/dist/browser-prod/optionValueDecoder.mjs.map +1 -1
  30. package/dist/browser-prod/packages/hydrogen-react/package.json.mjs +1 -1
  31. package/dist/browser-prod/storefront-api-constants.mjs +1 -1
  32. package/dist/browser-prod/storefront-api-constants.mjs.map +1 -1
  33. package/dist/browser-prod/storefront-client.mjs +0 -1
  34. package/dist/browser-prod/storefront-client.mjs.map +1 -1
  35. package/dist/browser-prod/useCartAPIStateMachine.mjs.map +1 -1
  36. package/dist/browser-prod/useCartActions.mjs.map +1 -1
  37. package/dist/browser-prod/useMoney.mjs.map +1 -1
  38. package/dist/node-dev/CartLineProvider.js.map +1 -1
  39. package/dist/node-dev/CartLineProvider.mjs.map +1 -1
  40. package/dist/node-dev/CartProvider.js.map +1 -1
  41. package/dist/node-dev/CartProvider.mjs.map +1 -1
  42. package/dist/node-dev/Image.js.map +1 -1
  43. package/dist/node-dev/Image.mjs.map +1 -1
  44. package/dist/node-dev/ModelViewer.js.map +1 -1
  45. package/dist/node-dev/ModelViewer.mjs.map +1 -1
  46. package/dist/node-dev/Money.js.map +1 -1
  47. package/dist/node-dev/Money.mjs.map +1 -1
  48. package/dist/node-dev/Video.js.map +1 -1
  49. package/dist/node-dev/Video.mjs.map +1 -1
  50. package/dist/node-dev/cart-queries.js +1 -1
  51. package/dist/node-dev/cart-queries.js.map +1 -1
  52. package/dist/node-dev/cart-queries.mjs +1 -1
  53. package/dist/node-dev/cart-queries.mjs.map +1 -1
  54. package/dist/node-dev/codegen.helpers.js.map +1 -1
  55. package/dist/node-dev/codegen.helpers.mjs.map +1 -1
  56. package/dist/node-dev/optionValueDecoder.js.map +1 -1
  57. package/dist/node-dev/optionValueDecoder.mjs.map +1 -1
  58. package/dist/node-dev/packages/hydrogen-react/package.json.js +1 -1
  59. package/dist/node-dev/packages/hydrogen-react/package.json.mjs +1 -1
  60. package/dist/node-dev/storefront-api-constants.js +1 -1
  61. package/dist/node-dev/storefront-api-constants.js.map +1 -1
  62. package/dist/node-dev/storefront-api-constants.mjs +1 -1
  63. package/dist/node-dev/storefront-api-constants.mjs.map +1 -1
  64. package/dist/node-dev/storefront-client.js +0 -1
  65. package/dist/node-dev/storefront-client.js.map +1 -1
  66. package/dist/node-dev/storefront-client.mjs +0 -1
  67. package/dist/node-dev/storefront-client.mjs.map +1 -1
  68. package/dist/node-dev/useCartAPIStateMachine.js.map +1 -1
  69. package/dist/node-dev/useCartAPIStateMachine.mjs.map +1 -1
  70. package/dist/node-dev/useCartActions.js.map +1 -1
  71. package/dist/node-dev/useCartActions.mjs.map +1 -1
  72. package/dist/node-dev/useMoney.js.map +1 -1
  73. package/dist/node-dev/useMoney.mjs.map +1 -1
  74. package/dist/node-prod/CartLineProvider.js.map +1 -1
  75. package/dist/node-prod/CartLineProvider.mjs.map +1 -1
  76. package/dist/node-prod/CartProvider.js.map +1 -1
  77. package/dist/node-prod/CartProvider.mjs.map +1 -1
  78. package/dist/node-prod/Image.js.map +1 -1
  79. package/dist/node-prod/Image.mjs.map +1 -1
  80. package/dist/node-prod/ModelViewer.js.map +1 -1
  81. package/dist/node-prod/ModelViewer.mjs.map +1 -1
  82. package/dist/node-prod/Money.js.map +1 -1
  83. package/dist/node-prod/Money.mjs.map +1 -1
  84. package/dist/node-prod/Video.js.map +1 -1
  85. package/dist/node-prod/Video.mjs.map +1 -1
  86. package/dist/node-prod/cart-queries.js +1 -1
  87. package/dist/node-prod/cart-queries.js.map +1 -1
  88. package/dist/node-prod/cart-queries.mjs +1 -1
  89. package/dist/node-prod/cart-queries.mjs.map +1 -1
  90. package/dist/node-prod/codegen.helpers.js.map +1 -1
  91. package/dist/node-prod/codegen.helpers.mjs.map +1 -1
  92. package/dist/node-prod/optionValueDecoder.js.map +1 -1
  93. package/dist/node-prod/optionValueDecoder.mjs.map +1 -1
  94. package/dist/node-prod/packages/hydrogen-react/package.json.js +1 -1
  95. package/dist/node-prod/packages/hydrogen-react/package.json.mjs +1 -1
  96. package/dist/node-prod/storefront-api-constants.js +1 -1
  97. package/dist/node-prod/storefront-api-constants.js.map +1 -1
  98. package/dist/node-prod/storefront-api-constants.mjs +1 -1
  99. package/dist/node-prod/storefront-api-constants.mjs.map +1 -1
  100. package/dist/node-prod/storefront-client.js +0 -1
  101. package/dist/node-prod/storefront-client.js.map +1 -1
  102. package/dist/node-prod/storefront-client.mjs +0 -1
  103. package/dist/node-prod/storefront-client.mjs.map +1 -1
  104. package/dist/node-prod/useCartAPIStateMachine.js.map +1 -1
  105. package/dist/node-prod/useCartAPIStateMachine.mjs.map +1 -1
  106. package/dist/node-prod/useCartActions.js.map +1 -1
  107. package/dist/node-prod/useCartActions.mjs.map +1 -1
  108. package/dist/node-prod/useMoney.js.map +1 -1
  109. package/dist/node-prod/useMoney.mjs.map +1 -1
  110. package/dist/types/CartLineProvider.d.ts +1 -1
  111. package/dist/types/CartProvider.d.ts +2 -2
  112. package/dist/types/Image.d.ts +1 -1
  113. package/dist/types/ModelViewer.d.ts +1 -1
  114. package/dist/types/Money.d.ts +4 -4
  115. package/dist/types/Video.d.ts +1 -1
  116. package/dist/types/codegen.helpers.d.ts +2 -2
  117. package/dist/types/customer-account-api-types.d.ts +643 -8
  118. package/dist/types/optionValueDecoder.d.ts +2 -2
  119. package/dist/types/storefront-api-constants.d.ts +1 -1
  120. package/dist/types/storefront-api-types.d.ts +48 -4
  121. package/dist/types/useCartAPIStateMachine.d.ts +2 -2
  122. package/dist/types/useCartActions.d.ts +2 -2
  123. package/dist/types/useMoney.d.ts +2 -2
  124. package/dist/umd/hydrogen-react.dev.js +3 -4
  125. package/dist/umd/hydrogen-react.dev.js.map +1 -1
  126. package/dist/umd/hydrogen-react.prod.js +9 -9
  127. package/dist/umd/hydrogen-react.prod.js.map +1 -1
  128. package/package.json +1 -1
  129. package/storefront.schema.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useMoney.js","sources":["../../src/useMoney.tsx"],"sourcesContent":["import {useMemo} from 'react';\nimport {useShop} from './ShopifyProvider.js';\nimport {\n CurrencyCode as StorefrontApiCurrencyCode,\n MoneyV2 as StorefrontApiMoneyV2,\n} from './storefront-api-types.js';\nimport type {\n MoneyV2 as CustomerAccountApiMoneyV2,\n CurrencyCode as CustomerAccountApiCurrencyCode,\n} from './customer-account-api-types.js';\n\n// Support MoneyV2 from both Storefront API and Customer Account API\n// The APIs may have different CurrencyCode enums\n/**\n * Supports MoneyV2 from both Storefront API and Customer Account API.\n * The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype MoneyV2 = StorefrontApiMoneyV2 | CustomerAccountApiMoneyV2;\n\n/**\n * Supports CurrencyCode from both Storefront API and Customer Account API. The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype CurrencyCode = StorefrontApiCurrencyCode | CustomerAccountApiCurrencyCode;\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 from the Storefront API](https://shopify.dev/docs/api/storefront/2025-10/objects/MoneyV2)\n * or a [MoneyV2 object from the Customer Account API](https://shopify.dev/docs/api/customer/2025-10/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 * &nbsp;\n * @see {@link https://shopify.dev/api/hydrogen/hooks/usemoney}\n * @example initialize the money object\n * ```ts\n * const money = useMoney({\n * amount: '100.00',\n * currencyCode: 'USD'\n * })\n * ```\n * &nbsp;\n *\n * @example basic usage, outputs: $100.00\n * ```ts\n * money.localizedString\n * ```\n * &nbsp;\n *\n * @example without currency, outputs: 100.00\n * ```ts\n * money.amount\n * ```\n * &nbsp;\n *\n * @example without trailing zeros, outputs: $100\n * ```ts\n * money.withoutTrailingZeros\n * ```\n * &nbsp;\n *\n * @example currency name, outputs: US dollars\n * ```ts\n * money.currencyCode\n * ```\n * &nbsp;\n *\n * @example currency symbol, outputs: $\n * ```ts\n * money.currencySymbol\n * ```\n * &nbsp;\n *\n * @example without currency and without trailing zeros, outputs: 100\n * ```ts\n * money.withoutTrailingZerosAndCurrency\n * ```\n */\nexport function useMoney(money: MoneyV2): UseMoneyValue {\n const {countryIsoCode, languageIsoCode} = useShop();\n const locale = languageIsoCode.includes('_')\n ? languageIsoCode.replace('_', '-')\n : `${languageIsoCode}-${countryIsoCode}`;\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 // Check if the currency code is supported by Intl.NumberFormat\n let isCurrencySupported = true;\n try {\n new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: money.currencyCode,\n });\n } catch (e) {\n if (e instanceof RangeError && e.message.includes('currency')) {\n isCurrencySupported = false;\n }\n }\n\n const {\n defaultFormatter,\n nameFormatter,\n narrowSymbolFormatter,\n withoutTrailingZerosFormatter,\n withoutCurrencyFormatter,\n withoutTrailingZerosOrCurrencyFormatter,\n } = useMemo(() => {\n // For unsupported currencies (like USDC cryptocurrency), use decimal formatting with 2 decimal places\n // We default to 2 decimal places based on research showing USDC displays like USD to reinforce its 1:1 peg\n const options = isCurrencySupported\n ? {\n style: 'currency' as const,\n currency: money.currencyCode,\n }\n : {\n style: 'decimal' as const,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n };\n\n return {\n defaultFormatter: getLazyFormatter(locale, options),\n nameFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'name',\n }),\n narrowSymbolFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'narrowSymbol',\n }),\n withoutTrailingZerosFormatter: getLazyFormatter(locale, {\n ...options,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n withoutCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }),\n withoutTrailingZerosOrCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n };\n }, [money.currencyCode, locale, isCurrencySupported]);\n\n const isPartCurrency = (part: Intl.NumberFormatPart): boolean =>\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: (): MoneyV2 => money,\n currencyCode: (): CurrencyCode => money.currencyCode,\n\n localizedString: (): string => {\n const formatted = defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n parts: (): Intl.NumberFormatPart[] => {\n const parts = defaultFormatter().formatToParts(amount);\n // For unsupported currencies, add currency code as a currency part\n if (!isCurrencySupported) {\n parts.push(\n {type: 'literal', value: ' '},\n {type: 'currency', value: money.currencyCode},\n );\n }\n return parts;\n },\n\n withoutTrailingZeros: (): string => {\n const formatted =\n amount % 1 === 0\n ? withoutTrailingZerosFormatter().format(amount)\n : defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n withoutTrailingZerosAndCurrency: (): string =>\n amount % 1 === 0\n ? withoutTrailingZerosOrCurrencyFormatter().format(amount)\n : withoutCurrencyFormatter().format(amount),\n\n currencyName: (): string =>\n nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"US dollars\"\n\n currencySymbol: (): string =>\n defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"USD\"\n\n currencyNarrowSymbol: (): string =>\n narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)\n ?.value ?? '', // e.g. \"$\"\n\n amount: (): string =>\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 isCurrencySupported,\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 // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n get: (target, key) => Reflect.get(target, key)?.call(null),\n }),\n [lazyFormatters],\n );\n}\n\nconst formatterCache = new Map<string, Intl.NumberFormat>();\n\nfunction getLazyFormatter(\n locale: string,\n options?: Intl.NumberFormatOptions,\n): () => Intl.NumberFormat {\n const key = JSON.stringify([locale, options]);\n\n return function (): Intl.NumberFormat {\n let formatter = formatterCache.get(key);\n if (!formatter) {\n try {\n formatter = new Intl.NumberFormat(locale, options);\n } catch (error) {\n // Handle unsupported currency codes (e.g., USDC from Customer Account API)\n // Fall back to formatting without currency\n if (error instanceof RangeError && error.message.includes('currency')) {\n const fallbackOptions = {...options};\n delete fallbackOptions.currency;\n delete fallbackOptions.currencyDisplay;\n delete fallbackOptions.currencySign;\n formatter = new Intl.NumberFormat(locale, fallbackOptions);\n } else {\n throw error;\n }\n }\n formatterCache.set(key, formatter);\n }\n return formatter;\n };\n}\n"],"names":["useShop","useMemo"],"mappings":"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"}
1
+ {"version":3,"file":"useMoney.js","sources":["../../src/useMoney.tsx"],"sourcesContent":["import {useMemo} from 'react';\nimport {useShop} from './ShopifyProvider.js';\nimport {\n CurrencyCode as StorefrontApiCurrencyCode,\n MoneyV2 as StorefrontApiMoneyV2,\n} from './storefront-api-types.js';\nimport type {\n MoneyV2 as CustomerAccountApiMoneyV2,\n CurrencyCode as CustomerAccountApiCurrencyCode,\n} from './customer-account-api-types.js';\n\n// Support MoneyV2 from both Storefront API and Customer Account API\n// The APIs may have different CurrencyCode enums\n/**\n * Supports MoneyV2 from both Storefront API and Customer Account API.\n * The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype MoneyV2 = StorefrontApiMoneyV2 | CustomerAccountApiMoneyV2;\n\n/**\n * Supports CurrencyCode from both Storefront API and Customer Account API. The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype CurrencyCode = StorefrontApiCurrencyCode | CustomerAccountApiCurrencyCode;\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 from the Storefront API](https://shopify.dev/docs/api/storefront/2026-01/objects/MoneyV2)\n * or a [MoneyV2 object from the Customer Account API](https://shopify.dev/docs/api/customer/2026-01/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 * &nbsp;\n * @see {@link https://shopify.dev/api/hydrogen/hooks/usemoney}\n * @example initialize the money object\n * ```ts\n * const money = useMoney({\n * amount: '100.00',\n * currencyCode: 'USD'\n * })\n * ```\n * &nbsp;\n *\n * @example basic usage, outputs: $100.00\n * ```ts\n * money.localizedString\n * ```\n * &nbsp;\n *\n * @example without currency, outputs: 100.00\n * ```ts\n * money.amount\n * ```\n * &nbsp;\n *\n * @example without trailing zeros, outputs: $100\n * ```ts\n * money.withoutTrailingZeros\n * ```\n * &nbsp;\n *\n * @example currency name, outputs: US dollars\n * ```ts\n * money.currencyCode\n * ```\n * &nbsp;\n *\n * @example currency symbol, outputs: $\n * ```ts\n * money.currencySymbol\n * ```\n * &nbsp;\n *\n * @example without currency and without trailing zeros, outputs: 100\n * ```ts\n * money.withoutTrailingZerosAndCurrency\n * ```\n */\nexport function useMoney(money: MoneyV2): UseMoneyValue {\n const {countryIsoCode, languageIsoCode} = useShop();\n const locale = languageIsoCode.includes('_')\n ? languageIsoCode.replace('_', '-')\n : `${languageIsoCode}-${countryIsoCode}`;\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 // Check if the currency code is supported by Intl.NumberFormat\n let isCurrencySupported = true;\n try {\n new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: money.currencyCode,\n });\n } catch (e) {\n if (e instanceof RangeError && e.message.includes('currency')) {\n isCurrencySupported = false;\n }\n }\n\n const {\n defaultFormatter,\n nameFormatter,\n narrowSymbolFormatter,\n withoutTrailingZerosFormatter,\n withoutCurrencyFormatter,\n withoutTrailingZerosOrCurrencyFormatter,\n } = useMemo(() => {\n // For unsupported currencies (like USDC cryptocurrency), use decimal formatting with 2 decimal places\n // We default to 2 decimal places based on research showing USDC displays like USD to reinforce its 1:1 peg\n const options = isCurrencySupported\n ? {\n style: 'currency' as const,\n currency: money.currencyCode,\n }\n : {\n style: 'decimal' as const,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n };\n\n return {\n defaultFormatter: getLazyFormatter(locale, options),\n nameFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'name',\n }),\n narrowSymbolFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'narrowSymbol',\n }),\n withoutTrailingZerosFormatter: getLazyFormatter(locale, {\n ...options,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n withoutCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }),\n withoutTrailingZerosOrCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n };\n }, [money.currencyCode, locale, isCurrencySupported]);\n\n const isPartCurrency = (part: Intl.NumberFormatPart): boolean =>\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: (): MoneyV2 => money,\n currencyCode: (): CurrencyCode => money.currencyCode,\n\n localizedString: (): string => {\n const formatted = defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n parts: (): Intl.NumberFormatPart[] => {\n const parts = defaultFormatter().formatToParts(amount);\n // For unsupported currencies, add currency code as a currency part\n if (!isCurrencySupported) {\n parts.push(\n {type: 'literal', value: ' '},\n {type: 'currency', value: money.currencyCode},\n );\n }\n return parts;\n },\n\n withoutTrailingZeros: (): string => {\n const formatted =\n amount % 1 === 0\n ? withoutTrailingZerosFormatter().format(amount)\n : defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n withoutTrailingZerosAndCurrency: (): string =>\n amount % 1 === 0\n ? withoutTrailingZerosOrCurrencyFormatter().format(amount)\n : withoutCurrencyFormatter().format(amount),\n\n currencyName: (): string =>\n nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"US dollars\"\n\n currencySymbol: (): string =>\n defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"USD\"\n\n currencyNarrowSymbol: (): string =>\n narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)\n ?.value ?? '', // e.g. \"$\"\n\n amount: (): string =>\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 isCurrencySupported,\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 // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n get: (target, key) => Reflect.get(target, key)?.call(null),\n }),\n [lazyFormatters],\n );\n}\n\nconst formatterCache = new Map<string, Intl.NumberFormat>();\n\nfunction getLazyFormatter(\n locale: string,\n options?: Intl.NumberFormatOptions,\n): () => Intl.NumberFormat {\n const key = JSON.stringify([locale, options]);\n\n return function (): Intl.NumberFormat {\n let formatter = formatterCache.get(key);\n if (!formatter) {\n try {\n formatter = new Intl.NumberFormat(locale, options);\n } catch (error) {\n // Handle unsupported currency codes (e.g., USDC from Customer Account API)\n // Fall back to formatting without currency\n if (error instanceof RangeError && error.message.includes('currency')) {\n const fallbackOptions = {...options};\n delete fallbackOptions.currency;\n delete fallbackOptions.currencyDisplay;\n delete fallbackOptions.currencySign;\n formatter = new Intl.NumberFormat(locale, fallbackOptions);\n } else {\n throw error;\n }\n }\n formatterCache.set(key, formatter);\n }\n return formatter;\n };\n}\n"],"names":["useShop","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 {\n CurrencyCode as StorefrontApiCurrencyCode,\n MoneyV2 as StorefrontApiMoneyV2,\n} from './storefront-api-types.js';\nimport type {\n MoneyV2 as CustomerAccountApiMoneyV2,\n CurrencyCode as CustomerAccountApiCurrencyCode,\n} from './customer-account-api-types.js';\n\n// Support MoneyV2 from both Storefront API and Customer Account API\n// The APIs may have different CurrencyCode enums\n/**\n * Supports MoneyV2 from both Storefront API and Customer Account API.\n * The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype MoneyV2 = StorefrontApiMoneyV2 | CustomerAccountApiMoneyV2;\n\n/**\n * Supports CurrencyCode from both Storefront API and Customer Account API. The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype CurrencyCode = StorefrontApiCurrencyCode | CustomerAccountApiCurrencyCode;\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 from the Storefront API](https://shopify.dev/docs/api/storefront/2025-10/objects/MoneyV2)\n * or a [MoneyV2 object from the Customer Account API](https://shopify.dev/docs/api/customer/2025-10/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 * &nbsp;\n * @see {@link https://shopify.dev/api/hydrogen/hooks/usemoney}\n * @example initialize the money object\n * ```ts\n * const money = useMoney({\n * amount: '100.00',\n * currencyCode: 'USD'\n * })\n * ```\n * &nbsp;\n *\n * @example basic usage, outputs: $100.00\n * ```ts\n * money.localizedString\n * ```\n * &nbsp;\n *\n * @example without currency, outputs: 100.00\n * ```ts\n * money.amount\n * ```\n * &nbsp;\n *\n * @example without trailing zeros, outputs: $100\n * ```ts\n * money.withoutTrailingZeros\n * ```\n * &nbsp;\n *\n * @example currency name, outputs: US dollars\n * ```ts\n * money.currencyCode\n * ```\n * &nbsp;\n *\n * @example currency symbol, outputs: $\n * ```ts\n * money.currencySymbol\n * ```\n * &nbsp;\n *\n * @example without currency and without trailing zeros, outputs: 100\n * ```ts\n * money.withoutTrailingZerosAndCurrency\n * ```\n */\nexport function useMoney(money: MoneyV2): UseMoneyValue {\n const {countryIsoCode, languageIsoCode} = useShop();\n const locale = languageIsoCode.includes('_')\n ? languageIsoCode.replace('_', '-')\n : `${languageIsoCode}-${countryIsoCode}`;\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 // Check if the currency code is supported by Intl.NumberFormat\n let isCurrencySupported = true;\n try {\n new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: money.currencyCode,\n });\n } catch (e) {\n if (e instanceof RangeError && e.message.includes('currency')) {\n isCurrencySupported = false;\n }\n }\n\n const {\n defaultFormatter,\n nameFormatter,\n narrowSymbolFormatter,\n withoutTrailingZerosFormatter,\n withoutCurrencyFormatter,\n withoutTrailingZerosOrCurrencyFormatter,\n } = useMemo(() => {\n // For unsupported currencies (like USDC cryptocurrency), use decimal formatting with 2 decimal places\n // We default to 2 decimal places based on research showing USDC displays like USD to reinforce its 1:1 peg\n const options = isCurrencySupported\n ? {\n style: 'currency' as const,\n currency: money.currencyCode,\n }\n : {\n style: 'decimal' as const,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n };\n\n return {\n defaultFormatter: getLazyFormatter(locale, options),\n nameFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'name',\n }),\n narrowSymbolFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'narrowSymbol',\n }),\n withoutTrailingZerosFormatter: getLazyFormatter(locale, {\n ...options,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n withoutCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }),\n withoutTrailingZerosOrCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n };\n }, [money.currencyCode, locale, isCurrencySupported]);\n\n const isPartCurrency = (part: Intl.NumberFormatPart): boolean =>\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: (): MoneyV2 => money,\n currencyCode: (): CurrencyCode => money.currencyCode,\n\n localizedString: (): string => {\n const formatted = defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n parts: (): Intl.NumberFormatPart[] => {\n const parts = defaultFormatter().formatToParts(amount);\n // For unsupported currencies, add currency code as a currency part\n if (!isCurrencySupported) {\n parts.push(\n {type: 'literal', value: ' '},\n {type: 'currency', value: money.currencyCode},\n );\n }\n return parts;\n },\n\n withoutTrailingZeros: (): string => {\n const formatted =\n amount % 1 === 0\n ? withoutTrailingZerosFormatter().format(amount)\n : defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n withoutTrailingZerosAndCurrency: (): string =>\n amount % 1 === 0\n ? withoutTrailingZerosOrCurrencyFormatter().format(amount)\n : withoutCurrencyFormatter().format(amount),\n\n currencyName: (): string =>\n nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"US dollars\"\n\n currencySymbol: (): string =>\n defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"USD\"\n\n currencyNarrowSymbol: (): string =>\n narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)\n ?.value ?? '', // e.g. \"$\"\n\n amount: (): string =>\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 isCurrencySupported,\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 // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n get: (target, key) => Reflect.get(target, key)?.call(null),\n }),\n [lazyFormatters],\n );\n}\n\nconst formatterCache = new Map<string, Intl.NumberFormat>();\n\nfunction getLazyFormatter(\n locale: string,\n options?: Intl.NumberFormatOptions,\n): () => Intl.NumberFormat {\n const key = JSON.stringify([locale, options]);\n\n return function (): Intl.NumberFormat {\n let formatter = formatterCache.get(key);\n if (!formatter) {\n try {\n formatter = new Intl.NumberFormat(locale, options);\n } catch (error) {\n // Handle unsupported currency codes (e.g., USDC from Customer Account API)\n // Fall back to formatting without currency\n if (error instanceof RangeError && error.message.includes('currency')) {\n const fallbackOptions = {...options};\n delete fallbackOptions.currency;\n delete fallbackOptions.currencyDisplay;\n delete fallbackOptions.currencySign;\n formatter = new Intl.NumberFormat(locale, fallbackOptions);\n } else {\n throw error;\n }\n }\n formatterCache.set(key, formatter);\n }\n return formatter;\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useMoney.mjs","sources":["../../src/useMoney.tsx"],"sourcesContent":["import {useMemo} from 'react';\nimport {useShop} from './ShopifyProvider.js';\nimport {\n CurrencyCode as StorefrontApiCurrencyCode,\n MoneyV2 as StorefrontApiMoneyV2,\n} from './storefront-api-types.js';\nimport type {\n MoneyV2 as CustomerAccountApiMoneyV2,\n CurrencyCode as CustomerAccountApiCurrencyCode,\n} from './customer-account-api-types.js';\n\n// Support MoneyV2 from both Storefront API and Customer Account API\n// The APIs may have different CurrencyCode enums\n/**\n * Supports MoneyV2 from both Storefront API and Customer Account API.\n * The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype MoneyV2 = StorefrontApiMoneyV2 | CustomerAccountApiMoneyV2;\n\n/**\n * Supports CurrencyCode from both Storefront API and Customer Account API. The APIs may have different CurrencyCode enums (e.g., Customer Account API added USDC in 2025-10, but Storefront API doesn't support USDC in 2025-10).\n * This union type ensures useMoney works with data from either API.\n */\ntype CurrencyCode = StorefrontApiCurrencyCode | CustomerAccountApiCurrencyCode;\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 from the Storefront API](https://shopify.dev/docs/api/storefront/2026-01/objects/MoneyV2)\n * or a [MoneyV2 object from the Customer Account API](https://shopify.dev/docs/api/customer/2026-01/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 * &nbsp;\n * @see {@link https://shopify.dev/api/hydrogen/hooks/usemoney}\n * @example initialize the money object\n * ```ts\n * const money = useMoney({\n * amount: '100.00',\n * currencyCode: 'USD'\n * })\n * ```\n * &nbsp;\n *\n * @example basic usage, outputs: $100.00\n * ```ts\n * money.localizedString\n * ```\n * &nbsp;\n *\n * @example without currency, outputs: 100.00\n * ```ts\n * money.amount\n * ```\n * &nbsp;\n *\n * @example without trailing zeros, outputs: $100\n * ```ts\n * money.withoutTrailingZeros\n * ```\n * &nbsp;\n *\n * @example currency name, outputs: US dollars\n * ```ts\n * money.currencyCode\n * ```\n * &nbsp;\n *\n * @example currency symbol, outputs: $\n * ```ts\n * money.currencySymbol\n * ```\n * &nbsp;\n *\n * @example without currency and without trailing zeros, outputs: 100\n * ```ts\n * money.withoutTrailingZerosAndCurrency\n * ```\n */\nexport function useMoney(money: MoneyV2): UseMoneyValue {\n const {countryIsoCode, languageIsoCode} = useShop();\n const locale = languageIsoCode.includes('_')\n ? languageIsoCode.replace('_', '-')\n : `${languageIsoCode}-${countryIsoCode}`;\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 // Check if the currency code is supported by Intl.NumberFormat\n let isCurrencySupported = true;\n try {\n new Intl.NumberFormat(locale, {\n style: 'currency',\n currency: money.currencyCode,\n });\n } catch (e) {\n if (e instanceof RangeError && e.message.includes('currency')) {\n isCurrencySupported = false;\n }\n }\n\n const {\n defaultFormatter,\n nameFormatter,\n narrowSymbolFormatter,\n withoutTrailingZerosFormatter,\n withoutCurrencyFormatter,\n withoutTrailingZerosOrCurrencyFormatter,\n } = useMemo(() => {\n // For unsupported currencies (like USDC cryptocurrency), use decimal formatting with 2 decimal places\n // We default to 2 decimal places based on research showing USDC displays like USD to reinforce its 1:1 peg\n const options = isCurrencySupported\n ? {\n style: 'currency' as const,\n currency: money.currencyCode,\n }\n : {\n style: 'decimal' as const,\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n };\n\n return {\n defaultFormatter: getLazyFormatter(locale, options),\n nameFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'name',\n }),\n narrowSymbolFormatter: getLazyFormatter(locale, {\n ...options,\n currencyDisplay: 'narrowSymbol',\n }),\n withoutTrailingZerosFormatter: getLazyFormatter(locale, {\n ...options,\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n withoutCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }),\n withoutTrailingZerosOrCurrencyFormatter: getLazyFormatter(locale, {\n minimumFractionDigits: 0,\n maximumFractionDigits: 0,\n }),\n };\n }, [money.currencyCode, locale, isCurrencySupported]);\n\n const isPartCurrency = (part: Intl.NumberFormatPart): boolean =>\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: (): MoneyV2 => money,\n currencyCode: (): CurrencyCode => money.currencyCode,\n\n localizedString: (): string => {\n const formatted = defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n parts: (): Intl.NumberFormatPart[] => {\n const parts = defaultFormatter().formatToParts(amount);\n // For unsupported currencies, add currency code as a currency part\n if (!isCurrencySupported) {\n parts.push(\n {type: 'literal', value: ' '},\n {type: 'currency', value: money.currencyCode},\n );\n }\n return parts;\n },\n\n withoutTrailingZeros: (): string => {\n const formatted =\n amount % 1 === 0\n ? withoutTrailingZerosFormatter().format(amount)\n : defaultFormatter().format(amount);\n // For unsupported currencies, append the currency code\n return isCurrencySupported\n ? formatted\n : `${formatted} ${money.currencyCode}`;\n },\n\n withoutTrailingZerosAndCurrency: (): string =>\n amount % 1 === 0\n ? withoutTrailingZerosOrCurrencyFormatter().format(amount)\n : withoutCurrencyFormatter().format(amount),\n\n currencyName: (): string =>\n nameFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"US dollars\"\n\n currencySymbol: (): string =>\n defaultFormatter().formatToParts(amount).find(isPartCurrency)?.value ??\n money.currencyCode, // e.g. \"USD\"\n\n currencyNarrowSymbol: (): string =>\n narrowSymbolFormatter().formatToParts(amount).find(isPartCurrency)\n ?.value ?? '', // e.g. \"$\"\n\n amount: (): string =>\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 isCurrencySupported,\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 // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call\n get: (target, key) => Reflect.get(target, key)?.call(null),\n }),\n [lazyFormatters],\n );\n}\n\nconst formatterCache = new Map<string, Intl.NumberFormat>();\n\nfunction getLazyFormatter(\n locale: string,\n options?: Intl.NumberFormatOptions,\n): () => Intl.NumberFormat {\n const key = JSON.stringify([locale, options]);\n\n return function (): Intl.NumberFormat {\n let formatter = formatterCache.get(key);\n if (!formatter) {\n try {\n formatter = new Intl.NumberFormat(locale, options);\n } catch (error) {\n // Handle unsupported currency codes (e.g., USDC from Customer Account API)\n // Fall back to formatting without currency\n if (error instanceof RangeError && error.message.includes('currency')) {\n const fallbackOptions = {...options};\n delete fallbackOptions.currency;\n delete fallbackOptions.currencyDisplay;\n delete fallbackOptions.currencySign;\n formatter = new Intl.NumberFormat(locale, fallbackOptions);\n } else {\n throw error;\n }\n }\n formatterCache.set(key, formatter);\n }\n return formatter;\n };\n}\n"],"names":[],"mappings":";;AA8HO,SAAS,SAAS,OAA+B;AACtD,QAAM,EAAC,gBAAgB,gBAAA,IAAmB,QAAA;AAC1C,QAAM,SAAS,gBAAgB,SAAS,GAAG,IACvC,gBAAgB,QAAQ,KAAK,GAAG,IAChC,GAAG,eAAe,IAAI,cAAc;AAExC,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR;AAAA,IAAA;AAAA,EAEJ;AAEA,QAAM,SAAS,WAAW,MAAM,MAAM;AAGtC,MAAI,sBAAsB;AAC1B,MAAI;AACF,QAAI,KAAK,aAAa,QAAQ;AAAA,MAC5B,OAAO;AAAA,MACP,UAAU,MAAM;AAAA,IAAA,CACjB;AAAA,EACH,SAAS,GAAG;AACV,QAAI,aAAa,cAAc,EAAE,QAAQ,SAAS,UAAU,GAAG;AAC7D,4BAAsB;AAAA,IACxB;AAAA,EACF;AAEA,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA,IACE,QAAQ,MAAM;AAGhB,UAAM,UAAU,sBACZ;AAAA,MACE,OAAO;AAAA,MACP,UAAU,MAAM;AAAA,IAAA,IAElB;AAAA,MACE,OAAO;AAAA,MACP,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,IAAA;AAG7B,WAAO;AAAA,MACL,kBAAkB,iBAAiB,QAAQ,OAAO;AAAA,MAClD,eAAe,iBAAiB,QAAQ;AAAA,QACtC,GAAG;AAAA,QACH,iBAAiB;AAAA,MAAA,CAClB;AAAA,MACD,uBAAuB,iBAAiB,QAAQ;AAAA,QAC9C,GAAG;AAAA,QACH,iBAAiB;AAAA,MAAA,CAClB;AAAA,MACD,+BAA+B,iBAAiB,QAAQ;AAAA,QACtD,GAAG;AAAA,QACH,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,MAAA,CACxB;AAAA,MACD,0BAA0B,iBAAiB,QAAQ;AAAA,QACjD,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,MAAA,CACxB;AAAA,MACD,yCAAyC,iBAAiB,QAAQ;AAAA,QAChE,uBAAuB;AAAA,QACvB,uBAAuB;AAAA,MAAA,CACxB;AAAA,IAAA;AAAA,EAEL,GAAG,CAAC,MAAM,cAAc,QAAQ,mBAAmB,CAAC;AAEpD,QAAM,iBAAiB,CAAC,SACtB,KAAK,SAAS;AAIhB,QAAM,iBAAiB;AAAA,IACrB,OAAO;AAAA,MACL,UAAU,MAAe;AAAA,MACzB,cAAc,MAAoB,MAAM;AAAA,MAExC,iBAAiB,MAAc;AAC7B,cAAM,YAAY,mBAAmB,OAAO,MAAM;AAElD,eAAO,sBACH,YACA,GAAG,SAAS,IAAI,MAAM,YAAY;AAAA,MACxC;AAAA,MAEA,OAAO,MAA+B;AACpC,cAAM,QAAQ,mBAAmB,cAAc,MAAM;AAErD,YAAI,CAAC,qBAAqB;AACxB,gBAAM;AAAA,YACJ,EAAC,MAAM,WAAW,OAAO,IAAA;AAAA,YACzB,EAAC,MAAM,YAAY,OAAO,MAAM,aAAA;AAAA,UAAY;AAAA,QAEhD;AACA,eAAO;AAAA,MACT;AAAA,MAEA,sBAAsB,MAAc;AAClC,cAAM,YACJ,SAAS,MAAM,IACX,8BAAA,EAAgC,OAAO,MAAM,IAC7C,mBAAmB,OAAO,MAAM;AAEtC,eAAO,sBACH,YACA,GAAG,SAAS,IAAI,MAAM,YAAY;AAAA,MACxC;AAAA,MAEA,iCAAiC,MAC/B,SAAS,MAAM,IACX,wCAAA,EAA0C,OAAO,MAAM,IACvD,2BAA2B,OAAO,MAAM;AAAA,MAE9C,cAAc,MAAA;;AACZ,sCAAgB,cAAc,MAAM,EAAE,KAAK,cAAc,MAAzD,mBAA4D,UAC5D,MAAM;AAAA;AAAA;AAAA,MAER,gBAAgB,MAAA;;AACd,yCAAmB,cAAc,MAAM,EAAE,KAAK,cAAc,MAA5D,mBAA+D,UAC/D,MAAM;AAAA;AAAA;AAAA,MAER,sBAAsB,MAAA;;AACpB,4CAAA,EAAwB,cAAc,MAAM,EAAE,KAAK,cAAc,MAAjE,mBACI,UAAS;AAAA;AAAA;AAAA,MAEf,QAAQ,MACN,iBAAA,EACG,cAAc,MAAM,EACpB;AAAA,QAAO,CAAC,SACP,CAAC,WAAW,YAAY,SAAS,WAAW,SAAS,EAAE;AAAA,UACrD,KAAK;AAAA,QAAA;AAAA,MACP,EAED,IAAI,CAAC,SAAS,KAAK,KAAK,EACxB,KAAK,EAAE;AAAA,IAAA;AAAA,IAEd;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EACF;AAKF,SAAO;AAAA,IACL,MACE,IAAI,MAAM,gBAA4C;AAAA;AAAA,MAEpD,KAAK,CAAC,QAAQ;;AAAQ,6BAAQ,IAAI,QAAQ,GAAG,MAAvB,mBAA0B,KAAK;AAAA;AAAA,IAAI,CAC1D;AAAA,IACH,CAAC,cAAc;AAAA,EAAA;AAEnB;AAEA,MAAM,qCAAqB,IAAA;AAE3B,SAAS,iBACP,QACA,SACyB;AACzB,QAAM,MAAM,KAAK,UAAU,CAAC,QAAQ,OAAO,CAAC;AAE5C,SAAO,WAA+B;AACpC,QAAI,YAAY,eAAe,IAAI,GAAG;AACtC,QAAI,CAAC,WAAW;AACd,UAAI;AACF,oBAAY,IAAI,KAAK,aAAa,QAAQ,OAAO;AAAA,MACnD,SAAS,OAAO;AAGd,YAAI,iBAAiB,cAAc,MAAM,QAAQ,SAAS,UAAU,GAAG;AACrE,gBAAM,kBAAkB,EAAC,GAAG,QAAA;AAC5B,iBAAO,gBAAgB;AACvB,iBAAO,gBAAgB;AACvB,iBAAO,gBAAgB;AACvB,sBAAY,IAAI,KAAK,aAAa,QAAQ,eAAe;AAAA,QAC3D,OAAO;AACL,gBAAM;AAAA,QACR;AAAA,MACF;AACA,qBAAe,IAAI,KAAK,SAAS;AAAA,IACnC;AACA,WAAO;AAAA,EACT;AACF;"}
@@ -6,7 +6,7 @@ type CartLinePartialDeep = PartialDeep<CartLine | ComponentizableCartLine, {
6
6
  }>;
7
7
  export declare const CartLineContext: import("react").Context<CartLinePartialDeep | null>;
8
8
  /**
9
- * The `useCartLine` hook provides access to the [CartLine object](https://shopify.dev/api/storefront/2025-10/objects/cartline) from the Storefront API. It must be a descendent of a `CartProvider` component.
9
+ * The `useCartLine` hook provides access to the [CartLine object](https://shopify.dev/api/storefront/2026-01/objects/cartline) from the Storefront API. It must be a descendent of a `CartProvider` component.
10
10
  */
11
11
  export declare function useCartLine(): CartLinePartialDeep;
12
12
  type CartLineProviderProps = {
@@ -43,11 +43,11 @@ type CartProviderProps = {
43
43
  onAttributesUpdateComplete?: () => void;
44
44
  /** A callback that is invoked when the process to update the cart discount codes completes */
45
45
  onDiscountCodesUpdateComplete?: () => void;
46
- /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/2025-10/objects/cart). */
46
+ /** An object with fields that correspond to the Storefront API's [Cart object](https://shopify.dev/api/storefront/2026-01/objects/cart). */
47
47
  data?: PartialDeep<CartType, {
48
48
  recurseIntoArrays: true;
49
49
  }>;
50
- /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/2025-10/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */
50
+ /** A fragment used to query the Storefront API's [Cart object](https://shopify.dev/api/storefront/2026-01/objects/cart) for all queries and mutations. A default value is used if no argument is provided. */
51
51
  cartFragment?: string;
52
52
  /** A customer access token that's accessible on the server if there's a customer login. */
53
53
  customerAccessToken?: CartBuyerIdentityInput['customerAccessToken'];
@@ -42,7 +42,7 @@ type HydrogenImageBaseProps = {
42
42
  * @defaultValue `center`
43
43
  */
44
44
  crop?: Crop;
45
- /** Data mapping to the [Storefront API `Image`](https://shopify.dev/docs/api/storefront/2025-10/objects/Image) object. Must be an Image object.
45
+ /** Data mapping to the [Storefront API `Image`](https://shopify.dev/docs/api/storefront/2026-01/objects/Image) object. Must be an Image object.
46
46
  *
47
47
  * @example
48
48
  * ```
@@ -14,7 +14,7 @@ type ModelViewerProps = Omit<PartialDeep<JSX.IntrinsicElements['model-viewer'],
14
14
  recurseIntoArrays: true;
15
15
  }>, 'src'> & ModelViewerBaseProps;
16
16
  type ModelViewerBaseProps = {
17
- /** An object with fields that correspond to the Storefront API's [Model3D object](https://shopify.dev/api/storefront/2025-10/objects/model3d). */
17
+ /** An object with fields that correspond to the Storefront API's [Model3D object](https://shopify.dev/api/storefront/2026-01/objects/model3d). */
18
18
  data: PartialDeep<Model3d, {
19
19
  recurseIntoArrays: true;
20
20
  }>;
@@ -11,7 +11,7 @@ type MoneyV2 = StorefrontApiMoneyV2 | CustomerAccountApiMoneyV2;
11
11
  export interface MoneyPropsBase<ComponentGeneric extends React.ElementType> {
12
12
  /** An HTML tag or React Component to be rendered as the base element wrapper. The default is `div`. */
13
13
  as?: ComponentGeneric;
14
- /** An object with fields that correspond to the [Storefront API's MoneyV2 object](https://shopify.dev/docs/api/storefront/2025-10/objects/MoneyV2) or [Customer Account API's MoneyV2 object](https://shopify.dev/docs/api/customer/2025-10/objects/moneyv2). */
14
+ /** An object with fields that correspond to the [Storefront API's MoneyV2 object](https://shopify.dev/docs/api/storefront/2026-01/objects/MoneyV2) or [Customer Account API's MoneyV2 object](https://shopify.dev/docs/api/customer/2026-01/objects/moneyv2). */
15
15
  data: PartialDeep<MoneyV2, {
16
16
  recurseIntoArrays: true;
17
17
  }>;
@@ -19,7 +19,7 @@ export interface MoneyPropsBase<ComponentGeneric extends React.ElementType> {
19
19
  withoutCurrency?: boolean;
20
20
  /** Whether to remove trailing zeros (fractional money) from the output. */
21
21
  withoutTrailingZeros?: boolean;
22
- /** A [UnitPriceMeasurement object](https://shopify.dev/api/storefront/2025-10/objects/unitpricemeasurement). */
22
+ /** A [UnitPriceMeasurement object](https://shopify.dev/api/storefront/2026-01/objects/unitpricemeasurement). */
23
23
  measurement?: PartialDeep<UnitPriceMeasurement, {
24
24
  recurseIntoArrays: true;
25
25
  }>;
@@ -28,8 +28,8 @@ export interface MoneyPropsBase<ComponentGeneric extends React.ElementType> {
28
28
  }
29
29
  export type MoneyProps<ComponentGeneric extends React.ElementType> = MoneyPropsBase<ComponentGeneric> & (ComponentGeneric extends keyof React.JSX.IntrinsicElements ? Omit<React.ComponentPropsWithoutRef<ComponentGeneric>, keyof MoneyPropsBase<ComponentGeneric>> : React.ComponentPropsWithoutRef<ComponentGeneric>);
30
30
  /**
31
- * The `Money` component renders a string of the [Storefront API's MoneyV2 object](https://shopify.dev/docs/api/storefront/2025-10/objects/MoneyV2)
32
- * or the [Customer Account API's MoneyV2 object](https://shopify.dev/docs/api/customer/2025-10/objects/moneyv2)
31
+ * The `Money` component renders a string of the [Storefront API's MoneyV2 object](https://shopify.dev/docs/api/storefront/2026-01/objects/MoneyV2)
32
+ * or the [Customer Account API's MoneyV2 object](https://shopify.dev/docs/api/customer/2026-01/objects/moneyv2)
33
33
  * according to the `locale` in the `ShopifyProvider` component.
34
34
  * &nbsp;
35
35
  * @see {@link https://shopify.dev/api/hydrogen/components/money}
@@ -3,7 +3,7 @@ import { shopifyLoader } from './Image.js';
3
3
  import type { Video as VideoType } from './storefront-api-types.js';
4
4
  import type { PartialDeep } from 'type-fest';
5
5
  export interface VideoProps {
6
- /** An object with fields that correspond to the Storefront API's [Video object](https://shopify.dev/api/storefront/2025-10/objects/video). */
6
+ /** An object with fields that correspond to the Storefront API's [Video object](https://shopify.dev/api/storefront/2026-01/objects/video). */
7
7
  data: PartialDeep<VideoType, {
8
8
  recurseIntoArrays: true;
9
9
  }>;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Meant to be used with GraphQL CodeGen to type the Storefront API's custom scalars correctly.
3
- * Reference for the GraphQL types: https://shopify.dev/docs/api/storefront/2025-10/scalars/HTML
3
+ * Reference for the GraphQL types: https://shopify.dev/docs/api/storefront/2026-01/scalars/HTML
4
4
  * Note: JSON is generated as 'unknown' by default.
5
5
  */
6
6
  export declare const storefrontApiCustomScalars: {
@@ -13,7 +13,7 @@ export declare const storefrontApiCustomScalars: {
13
13
  };
14
14
  /**
15
15
  * Meant to be used with GraphQL CodeGen to type the Storefront API's custom scalars correctly.
16
- * Reference for the GraphQL types: https://shopify.dev/docs/api/customer/2025-10/scalars/HTML
16
+ * Reference for the GraphQL types: https://shopify.dev/docs/api/customer/2026-01/scalars/HTML
17
17
  * Note: JSON is generated as 'unknown' by default.
18
18
  */
19
19
  export declare const customerAccountApiCustomScalars: {