@shopify/hydrogen 1.0.1 → 1.0.2
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/esnext/client.d.ts +4 -4
- package/dist/esnext/client.js +4 -4
- package/dist/esnext/components/AddToCartButton/AddToCartButton.client.js +1 -1
- package/dist/esnext/components/Image/Image.js +22 -13
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.d.ts +1 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationClientProvider.client.js +1 -1
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.d.ts +3 -2
- package/dist/esnext/components/LocalizationProvider/LocalizationProvider.server.js +6 -10
- package/dist/esnext/components/ProductOptionsProvider/context.d.ts +1 -1
- package/dist/esnext/components/ProductOptionsProvider/index.d.ts +0 -1
- package/dist/esnext/components/ProductOptionsProvider/index.js +0 -1
- package/dist/esnext/components/index.d.ts +1 -2
- package/dist/esnext/components/index.js +1 -2
- package/dist/esnext/foundation/Analytics/connectors/Shopify/ShopifyAnalytics.client.js +1 -1
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.d.ts +1 -2
- package/dist/esnext/foundation/HydrogenRequest/HydrogenRequest.server.js +1 -1
- package/dist/esnext/foundation/ServerPropsProvider/index.d.ts +1 -2
- package/dist/esnext/foundation/ServerPropsProvider/index.js +1 -1
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.client.d.ts +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.client.js +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.d.ts +4 -2
- package/dist/esnext/foundation/ShopifyProvider/ShopifyProvider.server.js +19 -2
- package/dist/esnext/foundation/ShopifyProvider/types.d.ts +17 -0
- package/dist/esnext/hooks/index.d.ts +1 -0
- package/dist/esnext/hooks/index.js +1 -0
- package/dist/esnext/hooks/useLocalization/useLocalization.d.ts +3 -2
- package/dist/esnext/hooks/useLocalization/useLocalization.js +2 -7
- package/dist/esnext/hooks/useProductOptions/helpers.js +1 -1
- package/dist/esnext/index.d.ts +6 -5
- package/dist/esnext/index.js +6 -5
- package/dist/esnext/utilities/image_size.d.ts +1 -0
- package/dist/esnext/utilities/image_size.js +27 -26
- package/dist/esnext/utilities/index.d.ts +1 -1
- package/dist/esnext/utilities/index.js +1 -1
- package/dist/esnext/version.d.ts +1 -1
- package/dist/esnext/version.js +1 -1
- package/package.json +2 -2
- package/CHANGELOG.md +0 -2206
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.d.ts +0 -9
- package/dist/esnext/components/LocalizationProvider/LocalizationContext.client.js +0 -2
package/dist/esnext/client.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from './components';
|
|
2
2
|
export * from './hooks';
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
3
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
4
|
+
export { useShop } from './foundation/useShop';
|
|
5
|
+
export { ServerPropsProvider, ServerPropsContext, type ServerProps, type ServerPropsContextValue, } from './foundation/ServerPropsProvider';
|
|
6
|
+
export { useUrl } from './foundation/useUrl';
|
|
7
7
|
export { Head } from './foundation/Head';
|
|
8
8
|
export * from './utilities';
|
|
9
9
|
export { gql } from './utilities/graphql-tag';
|
package/dist/esnext/client.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from './components';
|
|
2
2
|
export * from './hooks';
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
3
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
4
|
+
export { useShop } from './foundation/useShop';
|
|
5
|
+
export { ServerPropsProvider, ServerPropsContext, } from './foundation/ServerPropsProvider';
|
|
6
|
+
export { useUrl } from './foundation/useUrl';
|
|
7
7
|
export { Head } from './foundation/Head';
|
|
8
8
|
export * from './utilities';
|
|
9
9
|
export { gql } from './utilities/graphql-tag';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
2
2
|
import { useCart } from '../CartProvider';
|
|
3
|
-
import { useProductOptions } from '
|
|
3
|
+
import { useProductOptions } from '../../hooks/useProductOptions';
|
|
4
4
|
import { BaseButton } from '../BaseButton';
|
|
5
5
|
/**
|
|
6
6
|
* The `AddToCartButton` component renders a button that adds an item to the cart when pressed.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { getShopifyImageDimensions, shopifyImageLoader, addImageSizeParametersToUrl, } from '../../utilities';
|
|
2
|
+
import { getShopifyImageDimensions, shopifyImageLoader, addImageSizeParametersToUrl, IMG_SRC_SET_SIZES, } from '../../utilities';
|
|
3
3
|
/**
|
|
4
4
|
* The `Image` component renders an image for the Storefront API's
|
|
5
5
|
* [Image object](https://shopify.dev/api/storefront/reference/common-objects/image) by using the `data` prop, or a custom location by using the `src` prop. You can [customize this component](https://shopify.dev/api/hydrogen/components#customizing-hydrogen-components) using passthrough props.
|
|
@@ -34,7 +34,7 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
34
34
|
if (__HYDROGEN_DEV__ && !data.altText && !rest.alt) {
|
|
35
35
|
console.warn(`<Image/>: the 'data' prop should have the 'altText' property, or the 'alt' prop, and one of them should not be empty. ${`Image: ${data.id ?? data.url}`}`);
|
|
36
36
|
}
|
|
37
|
-
const { width:
|
|
37
|
+
const { width: imgElementWidth, height: imgElementHeight } = getShopifyImageDimensions({
|
|
38
38
|
data,
|
|
39
39
|
loaderOptions,
|
|
40
40
|
elementProps: {
|
|
@@ -42,7 +42,7 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
42
42
|
height,
|
|
43
43
|
},
|
|
44
44
|
});
|
|
45
|
-
if (__HYDROGEN_DEV__ && (!
|
|
45
|
+
if (__HYDROGEN_DEV__ && (!imgElementWidth || !imgElementHeight)) {
|
|
46
46
|
console.warn(`<Image/>: the 'data' prop requires either 'width' or 'data.width', and 'height' or 'data.height' properties. ${`Image: ${data.id ?? data.url}`}`);
|
|
47
47
|
}
|
|
48
48
|
let finalSrc = data.url;
|
|
@@ -50,8 +50,8 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
50
50
|
finalSrc = loader({
|
|
51
51
|
...loaderOptions,
|
|
52
52
|
src: data.url,
|
|
53
|
-
width:
|
|
54
|
-
height:
|
|
53
|
+
width: imgElementWidth,
|
|
54
|
+
height: imgElementHeight,
|
|
55
55
|
});
|
|
56
56
|
if (typeof finalSrc !== 'string' || !finalSrc) {
|
|
57
57
|
throw new Error(`<Image/>: 'loader' did not return a valid string. ${`Image: ${data.id ?? data.url}`}`);
|
|
@@ -59,17 +59,20 @@ function ShopifyImage({ data, width, height, loading, loader = shopifyImageLoade
|
|
|
59
59
|
}
|
|
60
60
|
// determining what the intended width of the image is. For example, if the width is specified and lower than the image width, then that is the maximum image width
|
|
61
61
|
// to prevent generating a srcset with widths bigger than needed or to generate images that would distort because of being larger than original
|
|
62
|
-
const maxWidth = width &&
|
|
62
|
+
const maxWidth = width && imgElementWidth && width < imgElementWidth
|
|
63
|
+
? width
|
|
64
|
+
: imgElementWidth;
|
|
63
65
|
const finalSrcset = rest.srcSet ??
|
|
64
66
|
internalImageSrcSet({
|
|
65
67
|
...loaderOptions,
|
|
66
68
|
widths,
|
|
67
69
|
src: data.url,
|
|
68
70
|
width: maxWidth,
|
|
71
|
+
height: imgElementHeight,
|
|
69
72
|
loader,
|
|
70
73
|
});
|
|
71
74
|
/* eslint-disable hydrogen/prefer-image-component */
|
|
72
|
-
return (React.createElement("img", { id: data.id ?? '', alt: data.altText ?? rest.alt ?? '', loading: loading ?? 'lazy', ...rest, src: finalSrc, width:
|
|
75
|
+
return (React.createElement("img", { id: data.id ?? '', alt: data.altText ?? rest.alt ?? '', loading: loading ?? 'lazy', ...rest, src: finalSrc, width: imgElementWidth ?? undefined, height: imgElementHeight ?? undefined, srcSet: finalSrcset }));
|
|
73
76
|
/* eslint-enable hydrogen/prefer-image-component */
|
|
74
77
|
}
|
|
75
78
|
function ExternalImage({ src, width, height, alt, loader, loaderOptions, widths, loading, ...rest }) {
|
|
@@ -112,23 +115,29 @@ function ExternalImage({ src, width, height, alt, loader, loaderOptions, widths,
|
|
|
112
115
|
height: loaderOptions?.height ?? height, alt: alt ?? '', loading: loading ?? 'lazy', srcSet: finalSrcset }));
|
|
113
116
|
/* eslint-enable hydrogen/prefer-image-component */
|
|
114
117
|
}
|
|
115
|
-
|
|
116
|
-
// reference: https://shopify.dev/api/liquid/filters/html-filters#image_tag
|
|
117
|
-
const IMG_SRC_SET_SIZES = [352, 832, 1200, 1920, 2560];
|
|
118
|
-
function internalImageSrcSet({ src, width, crop, scale, widths, loader, }) {
|
|
118
|
+
function internalImageSrcSet({ src, width, crop, scale, widths, loader, height, }) {
|
|
119
119
|
const hasCustomWidths = widths && Array.isArray(widths);
|
|
120
|
-
if (hasCustomWidths && widths.some((size) => isNaN(size)))
|
|
120
|
+
if (hasCustomWidths && widths.some((size) => isNaN(size))) {
|
|
121
121
|
throw new Error(`<Image/>: the 'widths' must be an array of numbers`);
|
|
122
|
+
}
|
|
123
|
+
let aspectRatio = 1;
|
|
124
|
+
if (width && height) {
|
|
125
|
+
aspectRatio = Number(height) / Number(width);
|
|
126
|
+
}
|
|
122
127
|
let setSizes = hasCustomWidths ? widths : IMG_SRC_SET_SIZES;
|
|
123
128
|
if (!hasCustomWidths &&
|
|
124
129
|
width &&
|
|
125
|
-
width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1])
|
|
130
|
+
width < IMG_SRC_SET_SIZES[IMG_SRC_SET_SIZES.length - 1]) {
|
|
126
131
|
setSizes = IMG_SRC_SET_SIZES.filter((size) => size <= width);
|
|
132
|
+
}
|
|
127
133
|
const srcGenerator = loader ? loader : addImageSizeParametersToUrl;
|
|
128
134
|
return setSizes
|
|
129
135
|
.map((size) => `${srcGenerator({
|
|
130
136
|
src,
|
|
131
137
|
width: size,
|
|
138
|
+
// height is not applied if there is no crop
|
|
139
|
+
// if there is crop, then height is applied as a ratio of the original width + height aspect ratio * size
|
|
140
|
+
height: crop ? Number(size) * aspectRatio : undefined,
|
|
132
141
|
crop,
|
|
133
142
|
scale,
|
|
134
143
|
})} ${size}w`)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { LocalizationContextValue } from '
|
|
2
|
+
import type { LocalizationContextValue } from '../../foundation/ShopifyProvider/types';
|
|
3
3
|
export default function LocalizationClientProvider({ localization, children, }: {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
localization: LocalizationContextValue;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { LocalizationContext
|
|
2
|
+
import { LocalizationContext } from '../../foundation/ShopifyProvider/ShopifyProvider.client';
|
|
3
3
|
export default function LocalizationClientProvider({ localization, children, }) {
|
|
4
4
|
return (React.createElement(LocalizationContext.Provider, { value: localization }, children));
|
|
5
5
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
+
import { CountryCode, LanguageCode } from '../../storefront-api-types';
|
|
2
3
|
export interface LocalizationProviderProps {
|
|
3
4
|
/** A `ReactNode` element. */
|
|
4
5
|
children: ReactNode;
|
|
5
6
|
/**
|
|
6
7
|
* Override the `isoCode` to define the active country
|
|
7
8
|
*/
|
|
8
|
-
countryCode?:
|
|
9
|
+
countryCode?: CountryCode;
|
|
9
10
|
/**
|
|
10
11
|
* Override the `languageCode` to define the active language
|
|
11
12
|
*/
|
|
12
|
-
languageCode?:
|
|
13
|
+
languageCode?: LanguageCode;
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
16
|
* The `LocalizationProvider` component automatically queries the Storefront API's
|
|
@@ -2,6 +2,8 @@ import React from 'react';
|
|
|
2
2
|
import LocalizationClientProvider from './LocalizationClientProvider.client';
|
|
3
3
|
import { useShop } from '../../foundation/useShop';
|
|
4
4
|
import { useServerRequest } from '../../foundation/ServerRequestProvider';
|
|
5
|
+
import { log } from '../../utilities/log';
|
|
6
|
+
import { getLocalizationContextValue } from '../../foundation/ShopifyProvider/ShopifyProvider.server';
|
|
5
7
|
/**
|
|
6
8
|
* The `LocalizationProvider` component automatically queries the Storefront API's
|
|
7
9
|
* [`localization`](https://shopify.dev/api/storefront/reference/common-objects/queryroot) field
|
|
@@ -10,18 +12,12 @@ import { useServerRequest } from '../../foundation/ServerRequestProvider';
|
|
|
10
12
|
* Any descendents of this provider can use the `useLocalization` hook.
|
|
11
13
|
*/
|
|
12
14
|
export function LocalizationProvider(props) {
|
|
15
|
+
if (import.meta.env.DEV) {
|
|
16
|
+
log.warn('<LocalizationProvider> is no longer necessary. Pass localization props directly to `<ShopifyProvider>` instead.');
|
|
17
|
+
}
|
|
13
18
|
const { defaultLanguageCode, defaultCountryCode } = useShop();
|
|
14
|
-
const languageCode = (props.languageCode ?? defaultLanguageCode).toUpperCase();
|
|
15
|
-
const countryCode = (props.countryCode ?? defaultCountryCode).toUpperCase();
|
|
16
19
|
const request = useServerRequest();
|
|
17
|
-
const localization =
|
|
18
|
-
country: {
|
|
19
|
-
isoCode: countryCode,
|
|
20
|
-
},
|
|
21
|
-
language: {
|
|
22
|
-
isoCode: languageCode,
|
|
23
|
-
},
|
|
24
|
-
};
|
|
20
|
+
const localization = getLocalizationContextValue(defaultLanguageCode, defaultCountryCode, props.languageCode, props.countryCode);
|
|
25
21
|
request.ctx.localization = localization;
|
|
26
22
|
return (React.createElement(LocalizationClientProvider, { localization: localization }, props.children));
|
|
27
23
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ProductOptionsHookValue } from '../../hooks';
|
|
1
|
+
import type { ProductOptionsHookValue } from '../../hooks';
|
|
2
2
|
export declare const ProductOptionsContext: import("react").Context<ProductOptionsHookValue | null>;
|
|
@@ -20,9 +20,8 @@ export { CartShopPayButton } from './CartShopPayButton';
|
|
|
20
20
|
export { CartCost } from './CartCost';
|
|
21
21
|
export { CartProvider, useCart, useInstantCheckout } from './CartProvider';
|
|
22
22
|
export type { State, Status, Cart, CartWithActions, CartAction, } from './CartProvider';
|
|
23
|
-
export { ProductOptionsProvider
|
|
23
|
+
export { ProductOptionsProvider } from './ProductOptionsProvider';
|
|
24
24
|
export { ProductPrice } from './ProductPrice';
|
|
25
25
|
export { BuyNowButton } from './BuyNowButton';
|
|
26
26
|
export { ShopPayButton } from './ShopPayButton';
|
|
27
|
-
export { useLocalization } from '../hooks/useLocalization/useLocalization';
|
|
28
27
|
export { Seo } from './Seo';
|
|
@@ -18,9 +18,8 @@ export { CartCheckoutButton } from './CartCheckoutButton';
|
|
|
18
18
|
export { CartShopPayButton } from './CartShopPayButton';
|
|
19
19
|
export { CartCost } from './CartCost';
|
|
20
20
|
export { CartProvider, useCart, useInstantCheckout } from './CartProvider';
|
|
21
|
-
export { ProductOptionsProvider
|
|
21
|
+
export { ProductOptionsProvider } from './ProductOptionsProvider';
|
|
22
22
|
export { ProductPrice } from './ProductPrice';
|
|
23
23
|
export { BuyNowButton } from './BuyNowButton';
|
|
24
24
|
export { ShopPayButton } from './ShopPayButton';
|
|
25
|
-
export { useLocalization } from '../hooks/useLocalization/useLocalization';
|
|
26
25
|
export { Seo } from './Seo';
|
|
@@ -52,7 +52,7 @@ function updateCookie(cookieName, value, maxage, cookieDomain) {
|
|
|
52
52
|
const cookieString = stringify(cookieName, value, {
|
|
53
53
|
maxage,
|
|
54
54
|
domain: getCookieDomain(cookieDomain),
|
|
55
|
-
secure:
|
|
55
|
+
secure: import.meta.env.PROD,
|
|
56
56
|
samesite: 'Lax',
|
|
57
57
|
path: '/',
|
|
58
58
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { ShopifyContextValue } from '../ShopifyProvider/types';
|
|
1
|
+
import type { ShopifyContextValue, LocalizationContextValue } from '../ShopifyProvider/types';
|
|
2
2
|
import type { QueryCacheControlHeaders } from '../../utilities/log/log-cache-header';
|
|
3
3
|
import type { QueryTiming } from '../../utilities/log/log-query-timeline';
|
|
4
4
|
import type { ResolvedHydrogenConfig, PreloadOptions, QueryKey, RuntimeContext } from '../../types';
|
|
5
5
|
import { HelmetData as HeadData } from 'react-helmet-async';
|
|
6
6
|
import { SessionSyncApi } from '../session/session';
|
|
7
|
-
import { LocalizationContextValue } from '../../components/LocalizationProvider/LocalizationContext.client';
|
|
8
7
|
export declare type PreloadQueryEntry = {
|
|
9
8
|
key: QueryKey;
|
|
10
9
|
fetcher: (request: HydrogenRequest) => Promise<unknown>;
|
|
@@ -130,7 +130,7 @@ export class HydrogenRequest extends Request {
|
|
|
130
130
|
}
|
|
131
131
|
async formData() {
|
|
132
132
|
// @ts-ignore
|
|
133
|
-
if (
|
|
133
|
+
if (__HYDROGEN_WORKER__ || super.formData)
|
|
134
134
|
return super.formData();
|
|
135
135
|
const contentType = this.headers.get('Content-Type') || '';
|
|
136
136
|
// If mimeType’s essence is "multipart/form-data", then:
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export { ServerPropsProvider, ServerPropsContext } from './ServerPropsProvider';
|
|
2
|
-
export type { ServerProps, ServerPropsContextValue } from './ServerPropsProvider';
|
|
1
|
+
export { ServerPropsProvider, ServerPropsContext, type ServerProps, type ServerPropsContextValue, } from './ServerPropsProvider';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ServerPropsProvider, ServerPropsContext } from './ServerPropsProvider';
|
|
1
|
+
export { ServerPropsProvider, ServerPropsContext, } from './ServerPropsProvider';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { ShopifyContextValue } from './types';
|
|
1
|
+
import type { ShopifyContextValue, LocalizationContextValue } from './types';
|
|
2
2
|
import React, { ReactNode } from 'react';
|
|
3
3
|
export declare const ShopifyContext: React.Context<ShopifyContextValue | null>;
|
|
4
|
-
export declare
|
|
4
|
+
export declare const LocalizationContext: React.Context<LocalizationContextValue | null>;
|
|
5
|
+
export declare function ShopifyProviderClient({ children, shopifyConfig, localization, }: {
|
|
5
6
|
children: ReactNode;
|
|
6
7
|
shopifyConfig: ShopifyContextValue;
|
|
8
|
+
localization: LocalizationContextValue;
|
|
7
9
|
}): JSX.Element;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React, { createContext } from 'react';
|
|
2
2
|
export const ShopifyContext = createContext(null);
|
|
3
|
-
export
|
|
3
|
+
export const LocalizationContext = createContext(null);
|
|
4
|
+
export function ShopifyProviderClient({ children, shopifyConfig, localization, }) {
|
|
4
5
|
if (!shopifyConfig) {
|
|
5
6
|
throw new Error('The `shopifyConfig` prop should be passed to `ShopifyProvider`');
|
|
6
7
|
}
|
|
7
|
-
return (React.createElement(ShopifyContext.Provider, { value: shopifyConfig },
|
|
8
|
+
return (React.createElement(ShopifyContext.Provider, { value: shopifyConfig },
|
|
9
|
+
React.createElement(LocalizationContext.Provider, { value: localization }, children)));
|
|
8
10
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { ShopifyProviderProps } from './types';
|
|
1
|
+
import type { ShopifyProviderProps, LocalizationContextValue } from './types';
|
|
2
|
+
import type { CountryCode, LanguageCode } from '../../storefront-api-types';
|
|
2
3
|
export declare const SHOPIFY_PROVIDER_CONTEXT_KEY: unique symbol;
|
|
3
4
|
/**
|
|
4
5
|
* The `ShopifyProvider` component wraps your entire app and provides support for hooks.
|
|
@@ -11,6 +12,7 @@ export declare function ShopifyProvider({
|
|
|
11
12
|
* Shopify connection information. Defaults to
|
|
12
13
|
* [the `shopify` property in the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
|
|
13
14
|
*/
|
|
14
|
-
shopifyConfig,
|
|
15
|
+
shopifyConfig, countryCode, languageCode,
|
|
15
16
|
/** Any `ReactNode` elements. */
|
|
16
17
|
children, }: ShopifyProviderProps): JSX.Element;
|
|
18
|
+
export declare function getLocalizationContextValue(defaultLanguageCode: `${LanguageCode}`, defaultCountryCode: `${CountryCode}`, languageCode?: `${LanguageCode}`, countryCode?: `${CountryCode}`): LocalizationContextValue;
|
|
@@ -30,7 +30,7 @@ export function ShopifyProvider({
|
|
|
30
30
|
* Shopify connection information. Defaults to
|
|
31
31
|
* [the `shopify` property in the `hydrogen.config.js` file](https://shopify.dev/custom-storefronts/hydrogen/framework/hydrogen-config).
|
|
32
32
|
*/
|
|
33
|
-
shopifyConfig,
|
|
33
|
+
shopifyConfig, countryCode, languageCode,
|
|
34
34
|
/** Any `ReactNode` elements. */
|
|
35
35
|
children, }) {
|
|
36
36
|
const request = useServerRequest();
|
|
@@ -55,6 +55,23 @@ children, }) {
|
|
|
55
55
|
actualShopifyConfig = shopifyConfig;
|
|
56
56
|
}
|
|
57
57
|
const shopifyProviderValue = useMemo(() => makeShopifyContext(actualShopifyConfig), [actualShopifyConfig]);
|
|
58
|
+
const localization = getLocalizationContextValue(shopifyProviderValue.defaultLanguageCode, shopifyProviderValue.defaultCountryCode, languageCode, countryCode);
|
|
59
|
+
request.ctx.localization = localization;
|
|
58
60
|
request.ctx.shopifyConfig = shopifyProviderValue;
|
|
59
|
-
return (React.createElement(ShopifyProviderClient, { shopifyConfig: shopifyProviderValue }, children));
|
|
61
|
+
return (React.createElement(ShopifyProviderClient, { shopifyConfig: shopifyProviderValue, localization: localization }, children));
|
|
62
|
+
}
|
|
63
|
+
export function getLocalizationContextValue(defaultLanguageCode, defaultCountryCode, languageCode, countryCode) {
|
|
64
|
+
return useMemo(() => {
|
|
65
|
+
const runtimeLanguageCode = (languageCode ?? defaultLanguageCode).toUpperCase();
|
|
66
|
+
const runtimeCountryCode = (countryCode ?? defaultCountryCode).toUpperCase();
|
|
67
|
+
return {
|
|
68
|
+
country: {
|
|
69
|
+
isoCode: runtimeCountryCode,
|
|
70
|
+
},
|
|
71
|
+
language: {
|
|
72
|
+
isoCode: runtimeLanguageCode,
|
|
73
|
+
},
|
|
74
|
+
locale: `${runtimeLanguageCode}-${runtimeCountryCode}`,
|
|
75
|
+
};
|
|
76
|
+
}, [defaultLanguageCode, defaultCountryCode, countryCode, languageCode]);
|
|
60
77
|
}
|
|
@@ -6,9 +6,26 @@ export interface ShopifyContextValue extends Omit<ShopifyConfig, 'defaultLanguag
|
|
|
6
6
|
defaultCountryCode: `${CountryCode}`;
|
|
7
7
|
storefrontId: string | null;
|
|
8
8
|
}
|
|
9
|
+
export interface LocalizationContextValue {
|
|
10
|
+
country: {
|
|
11
|
+
isoCode: `${CountryCode}`;
|
|
12
|
+
};
|
|
13
|
+
language: {
|
|
14
|
+
isoCode: `${LanguageCode}`;
|
|
15
|
+
};
|
|
16
|
+
locale: `${LanguageCode}-${CountryCode}`;
|
|
17
|
+
}
|
|
9
18
|
export declare type ShopifyProviderProps = {
|
|
10
19
|
/** Shopify connection information. Defaults to the `shopify` property in the `hydrogen.config.js` file. */
|
|
11
20
|
shopifyConfig?: ShopifyConfig | ShopifyConfigFetcher;
|
|
12
21
|
/** Any `ReactNode` elements. */
|
|
13
22
|
children?: ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Override the `isoCode` to define the active country
|
|
25
|
+
*/
|
|
26
|
+
countryCode?: `${CountryCode}`;
|
|
27
|
+
/**
|
|
28
|
+
* Override the `languageCode` to define the active language
|
|
29
|
+
*/
|
|
30
|
+
languageCode?: `${LanguageCode}`;
|
|
14
31
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { LocalizationContextValue } from '../../foundation/ShopifyProvider/types';
|
|
2
|
+
import { CountryCode, LanguageCode } from '../../storefront-api-types';
|
|
2
3
|
export declare function useLocalization(): LocalizationContextValue & {
|
|
3
|
-
locale:
|
|
4
|
+
locale: `${LanguageCode}-${CountryCode}`;
|
|
4
5
|
};
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { LocalizationContext, } from '../../components/LocalizationProvider/LocalizationContext.client';
|
|
1
|
+
import { LocalizationContext } from '../../foundation/ShopifyProvider/ShopifyProvider.client';
|
|
3
2
|
import { useEnvContext } from '../../foundation/ssr-interop';
|
|
4
3
|
export function useLocalization() {
|
|
5
4
|
const localization = useEnvContext((req) => req.ctx.localization, LocalizationContext);
|
|
6
5
|
if (localization == null) {
|
|
7
6
|
throw new Error('No Localization Context available');
|
|
8
7
|
}
|
|
9
|
-
|
|
10
|
-
...localization,
|
|
11
|
-
locale: localization.language.isoCode + '-' + localization.country.isoCode,
|
|
12
|
-
}), [localization]);
|
|
13
|
-
return localizationValue;
|
|
8
|
+
return localization;
|
|
14
9
|
}
|
|
@@ -19,7 +19,7 @@ export function getSelectedVariant(variants, choices) {
|
|
|
19
19
|
export function getOptions(variants) {
|
|
20
20
|
const map = variants.reduce((memo, variant) => {
|
|
21
21
|
if (!variant.selectedOptions) {
|
|
22
|
-
throw new Error(`getOptions requires 'variant.selectedOptions`);
|
|
22
|
+
throw new Error(`'getOptions' requires 'variant.selectedOptions'`);
|
|
23
23
|
}
|
|
24
24
|
variant?.selectedOptions?.forEach((opt) => {
|
|
25
25
|
memo[opt?.name ?? ''] = memo[opt?.name ?? ''] || new Set();
|
package/dist/esnext/index.d.ts
CHANGED
|
@@ -9,10 +9,12 @@ export * from './client';
|
|
|
9
9
|
* The following are exported from this file because they are intended to be available
|
|
10
10
|
* *only* on the server.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
12
|
+
export { ServerPropsProvider, ServerPropsContext, type ServerProps, type ServerPropsContextValue, } from './foundation/ServerPropsProvider';
|
|
13
|
+
export { useShop } from './foundation/useShop';
|
|
14
|
+
export { useUrl } from './foundation/useUrl';
|
|
15
|
+
export { useShopQuery, type UseShopQueryResponse, } from './hooks/useShopQuery/hooks';
|
|
16
|
+
export { useQuery, type HydrogenUseQueryOptions, } from './foundation/useQuery/hooks';
|
|
17
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
16
18
|
export { FileRoutes } from './foundation/FileRoutes/FileRoutes.server';
|
|
17
19
|
export { Route } from './foundation/Route/Route.server';
|
|
18
20
|
export { Router } from './foundation/Router/Router.server';
|
|
@@ -25,7 +27,6 @@ export { useServerAnalytics } from './foundation/Analytics/hook';
|
|
|
25
27
|
export { ShopifyAnalytics } from './foundation/Analytics/connectors/Shopify/ShopifyAnalytics.server';
|
|
26
28
|
export { ShopifyAnalyticsConstants } from './foundation/Analytics/connectors/Shopify/const';
|
|
27
29
|
export { useSession } from './foundation/useSession/useSession';
|
|
28
|
-
export { useLocalization } from './hooks/useLocalization/useLocalization';
|
|
29
30
|
export { Cookie } from './foundation/Cookie/Cookie';
|
|
30
31
|
/**
|
|
31
32
|
* Export server-only CartQuery here instead of `CartProvider.client` to prevent
|
package/dist/esnext/index.js
CHANGED
|
@@ -9,10 +9,12 @@ export * from './client';
|
|
|
9
9
|
* The following are exported from this file because they are intended to be available
|
|
10
10
|
* *only* on the server.
|
|
11
11
|
*/
|
|
12
|
-
export
|
|
13
|
-
export
|
|
14
|
-
export
|
|
15
|
-
export
|
|
12
|
+
export { ServerPropsProvider, ServerPropsContext, } from './foundation/ServerPropsProvider';
|
|
13
|
+
export { useShop } from './foundation/useShop';
|
|
14
|
+
export { useUrl } from './foundation/useUrl';
|
|
15
|
+
export { useShopQuery, } from './hooks/useShopQuery/hooks';
|
|
16
|
+
export { useQuery, } from './foundation/useQuery/hooks';
|
|
17
|
+
export { useServerProps } from './foundation/useServerProps';
|
|
16
18
|
export { FileRoutes } from './foundation/FileRoutes/FileRoutes.server';
|
|
17
19
|
export { Route } from './foundation/Route/Route.server';
|
|
18
20
|
export { Router } from './foundation/Router/Router.server';
|
|
@@ -25,7 +27,6 @@ export { useServerAnalytics } from './foundation/Analytics/hook';
|
|
|
25
27
|
export { ShopifyAnalytics } from './foundation/Analytics/connectors/Shopify/ShopifyAnalytics.server';
|
|
26
28
|
export { ShopifyAnalyticsConstants } from './foundation/Analytics/connectors/Shopify/const';
|
|
27
29
|
export { useSession } from './foundation/useSession/useSession';
|
|
28
|
-
export { useLocalization } from './hooks/useLocalization/useLocalization';
|
|
29
30
|
export { Cookie } from './foundation/Cookie/Cookie';
|
|
30
31
|
/**
|
|
31
32
|
* Export server-only CartQuery here instead of `CartProvider.client` to prevent
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Image as ImageType } from '../storefront-api-types';
|
|
2
2
|
import type { PartialDeep } from 'type-fest';
|
|
3
3
|
import type { ShopifyLoaderOptions, ShopifyLoaderParams } from '../components/Image';
|
|
4
|
+
export declare const IMG_SRC_SET_SIZES: number[];
|
|
4
5
|
/**
|
|
5
6
|
* Adds image size parameters to an image URL hosted by Shopify's CDN
|
|
6
7
|
*/
|
|
@@ -7,26 +7,31 @@ const PRODUCTION_CDN_HOSTNAMES = [
|
|
|
7
7
|
];
|
|
8
8
|
const LOCAL_CDN_HOSTNAMES = ['spin.dev'];
|
|
9
9
|
const ALL_CDN_HOSTNAMES = [...PRODUCTION_CDN_HOSTNAMES, ...LOCAL_CDN_HOSTNAMES];
|
|
10
|
+
// based on the default width sizes used by the Shopify liquid HTML tag img_tag plus a 2560 width to account for 2k resolutions
|
|
11
|
+
// reference: https://shopify.dev/api/liquid/filters/html-filters#image_tag
|
|
12
|
+
export const IMG_SRC_SET_SIZES = [352, 832, 1200, 1920, 2560];
|
|
10
13
|
/**
|
|
11
14
|
* Adds image size parameters to an image URL hosted by Shopify's CDN
|
|
12
15
|
*/
|
|
13
16
|
export function addImageSizeParametersToUrl({ src, width, height, crop, scale, }) {
|
|
14
|
-
if (scale) {
|
|
15
|
-
// Have to do this specifically for 'scale' because it doesn't currently work otherwise.
|
|
16
|
-
// I'm also intentionally leaving 'scale' as a searchParam because that way it'll "just work" in the future and we can just delete this whole section of code
|
|
17
|
-
// We assume here that the last `.` is the delimiter between the file name and the file type
|
|
18
|
-
const baseUrl = new URL(src);
|
|
19
|
-
const fileDelimiterIndex = baseUrl.pathname.lastIndexOf('.');
|
|
20
|
-
const fileName = baseUrl.pathname.slice(0, fileDelimiterIndex);
|
|
21
|
-
const fileType = baseUrl.pathname.slice(fileDelimiterIndex);
|
|
22
|
-
baseUrl.pathname = `${fileName}${`@${scale.toString()}x`}${fileType}`;
|
|
23
|
-
src = baseUrl.toString();
|
|
24
|
-
}
|
|
25
17
|
const newUrl = new URL(src);
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
const multipliedScale = scale ?? 1;
|
|
19
|
+
if (width) {
|
|
20
|
+
let finalWidth;
|
|
21
|
+
if (typeof width === 'string') {
|
|
22
|
+
finalWidth = (IMG_SRC_SET_SIZES[0] * multipliedScale).toString();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
finalWidth = (Number(width) * multipliedScale).toString();
|
|
26
|
+
}
|
|
27
|
+
newUrl.searchParams.append('width', finalWidth);
|
|
28
|
+
}
|
|
29
|
+
if (height && typeof height === 'number') {
|
|
30
|
+
newUrl.searchParams.append('height', (height * multipliedScale).toString());
|
|
31
|
+
}
|
|
28
32
|
crop && newUrl.searchParams.append('crop', crop);
|
|
29
|
-
|
|
33
|
+
// for now we intentionally leave off the scale param, and instead multiple width & height by scale instead
|
|
34
|
+
// scale && newUrl.searchParams.append('scale', scale.toString());
|
|
30
35
|
return newUrl.toString();
|
|
31
36
|
}
|
|
32
37
|
export function shopifyImageLoader(params) {
|
|
@@ -57,14 +62,12 @@ export function getShopifyImageDimensions({ data: sfapiImage, loaderOptions, ele
|
|
|
57
62
|
if (loaderOptions?.width || loaderOptions?.height) {
|
|
58
63
|
return {
|
|
59
64
|
width: loaderOptions?.width ??
|
|
60
|
-
(aspectRatio
|
|
61
|
-
?
|
|
62
|
-
Math.round(aspectRatio * loaderOptions.height)
|
|
65
|
+
(aspectRatio && typeof loaderOptions.height === 'number'
|
|
66
|
+
? Math.round(aspectRatio * loaderOptions.height)
|
|
63
67
|
: null),
|
|
64
68
|
height: loaderOptions?.height ??
|
|
65
|
-
(aspectRatio
|
|
66
|
-
?
|
|
67
|
-
Math.round(aspectRatio * loaderOptions.width)
|
|
69
|
+
(aspectRatio && typeof loaderOptions.width === 'number'
|
|
70
|
+
? Math.round(aspectRatio * loaderOptions.width)
|
|
68
71
|
: null),
|
|
69
72
|
};
|
|
70
73
|
}
|
|
@@ -72,14 +75,12 @@ export function getShopifyImageDimensions({ data: sfapiImage, loaderOptions, ele
|
|
|
72
75
|
if (elementProps?.width || elementProps?.height) {
|
|
73
76
|
return {
|
|
74
77
|
width: elementProps?.width ??
|
|
75
|
-
(aspectRatio
|
|
76
|
-
?
|
|
77
|
-
Math.round(aspectRatio * elementProps.height)
|
|
78
|
+
(aspectRatio && typeof elementProps.height === 'number'
|
|
79
|
+
? Math.round(aspectRatio * elementProps.height)
|
|
78
80
|
: null),
|
|
79
81
|
height: elementProps?.height ??
|
|
80
|
-
(aspectRatio
|
|
81
|
-
?
|
|
82
|
-
Math.round(aspectRatio * elementProps.width)
|
|
82
|
+
(aspectRatio && typeof elementProps.width === 'number'
|
|
83
|
+
? Math.round(aspectRatio * elementProps.width)
|
|
83
84
|
: null),
|
|
84
85
|
};
|
|
85
86
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { addImageSizeParametersToUrl, getShopifyImageDimensions, shopifyImageLoader, } from './image_size';
|
|
1
|
+
export { addImageSizeParametersToUrl, getShopifyImageDimensions, shopifyImageLoader, IMG_SRC_SET_SIZES, } from './image_size';
|
|
2
2
|
export { YouTube, Vimeo, addParametersToEmbeddedVideoUrl, useEmbeddedVideoUrl, } from './video_parameters';
|
|
3
3
|
export { loadScript } from './load_script';
|
|
4
4
|
export { wrapPromise } from './suspense';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { addImageSizeParametersToUrl, getShopifyImageDimensions, shopifyImageLoader, } from './image_size';
|
|
1
|
+
export { addImageSizeParametersToUrl, getShopifyImageDimensions, shopifyImageLoader, IMG_SRC_SET_SIZES, } from './image_size';
|
|
2
2
|
export { addParametersToEmbeddedVideoUrl, useEmbeddedVideoUrl, } from './video_parameters';
|
|
3
3
|
export { loadScript } from './load_script';
|
|
4
4
|
export { wrapPromise } from './suspense';
|
package/dist/esnext/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "1.0.
|
|
1
|
+
export declare const LIB_VERSION = "1.0.2";
|
package/dist/esnext/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LIB_VERSION = '1.0.
|
|
1
|
+
export const LIB_VERSION = '1.0.2';
|