@sonic-equipment/ui 201.0.0 → 203.0.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 (73) hide show
  1. package/dist/breadcrumbs/breadcrumb.js +7 -16
  2. package/dist/breadcrumbs/breadcrumb.module.css.js +1 -1
  3. package/dist/buttons/add-to-cart-button/add-to-cart-button.d.ts +1 -1
  4. package/dist/buttons/add-to-cart-button/add-to-cart-button.js +12 -13
  5. package/dist/buttons/button/button.js +1 -2
  6. package/dist/buttons/icon-button/icon-button.js +1 -2
  7. package/dist/buttons/link/link.js +1 -2
  8. package/dist/collapsables/accordion/accordion-item.js +6 -5
  9. package/dist/collapsables/accordion/accordion.module.css.js +1 -1
  10. package/dist/cookies/client-cookie-context.d.ts +3 -0
  11. package/dist/cookies/client-cookie-context.js +30 -0
  12. package/dist/cookies/cookie-context.d.ts +2 -0
  13. package/dist/cookies/cookie-context.js +6 -0
  14. package/dist/cookies/cookie-provider.d.ts +6 -0
  15. package/dist/cookies/cookie-provider.js +10 -0
  16. package/dist/cookies/readonly-cookie-reader.d.ts +2 -0
  17. package/dist/cookies/readonly-cookie-reader.js +18 -0
  18. package/dist/cookies/types.d.ts +14 -0
  19. package/dist/cookies/types.js +7 -0
  20. package/dist/{shared/hooks → cookies}/use-cookie.d.ts +1 -2
  21. package/dist/cookies/use-cookie.js +30 -0
  22. package/dist/country-select/hooks/use-countries.js +1 -1
  23. package/dist/country-selector/connected-country-selector.js +1 -1
  24. package/dist/country-selector/use-countries-languages.js +3 -11
  25. package/dist/exports.d.ts +8 -1
  26. package/dist/header/buttons/account/connected-account-button.js +1 -8
  27. package/dist/index.js +10 -3
  28. package/dist/media/image-grid/images-grid.d.ts +2 -1
  29. package/dist/media/image-grid/images-grid.js +2 -2
  30. package/dist/media/image-lightbox/image-lightbox.d.ts +2 -1
  31. package/dist/media/image-lightbox/image-lightbox.js +2 -2
  32. package/dist/pages/account/components/create-account-form/create-account-form.js +1 -1
  33. package/dist/pages/account/create-account-page/create-account-page.js +5 -3
  34. package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-layout.d.ts +2 -1
  35. package/dist/pages/account/layouts/sign-in-page-layout/sign-in-page-layout.js +2 -4
  36. package/dist/pages/account/sign-in-page/sign-in-page.js +2 -2
  37. package/dist/pages/checkout/cart-page/cart-page.js +1 -1
  38. package/dist/pages/checkout/order-confirmation-page/order-confirmation-page-content.js +1 -1
  39. package/dist/pages/my-sonic/widgets/connected-bill-to-address-widget.js +2 -1
  40. package/dist/pages/my-sonic/widgets/connected-ship-to-address-widget.js +2 -1
  41. package/dist/pages/product/product-details-page/components/product-details-images/product-detail-images.js +1 -3
  42. package/dist/pages/product/product-details-page/components/product-details-images/product-detail-images.module.css.js +1 -1
  43. package/dist/pages/product/product-details-page/product-details.js +5 -1
  44. package/dist/pages/product/product-listing-page/no-results/no-results.js +3 -1
  45. package/dist/shared/api/storefront/hooks/cart/use-fetch-current-cart-with-atp.js +6 -4
  46. package/dist/shared/api/storefront/hooks/product/use-mark-product-as-viewed.d.ts +5 -3
  47. package/dist/shared/api/storefront/hooks/product/use-mark-product-as-viewed.js +4 -8
  48. package/dist/shared/api/storefront/services/website-service.js +9 -0
  49. package/dist/shared/hooks/use-debounced-callback.d.ts +5 -1
  50. package/dist/shared/hooks/use-debounced-callback.js +10 -10
  51. package/dist/shared/providers/react-query-container.d.ts +8 -3
  52. package/dist/shared/providers/react-query-container.js +4 -4
  53. package/dist/shared/routing/route-context.d.ts +2 -0
  54. package/dist/shared/routing/route-context.js +6 -0
  55. package/dist/shared/routing/route-provider.d.ts +1 -0
  56. package/dist/shared/routing/route-provider.js +7 -8
  57. package/dist/shared/routing/types.d.ts +2 -1
  58. package/dist/shared/routing/use-location.d.ts +3 -3
  59. package/dist/shared/routing/use-location.js +5 -5
  60. package/dist/shared/routing/use-navigate.js +4 -7
  61. package/dist/shared/routing/use-paths.js +4 -5
  62. package/dist/shared/routing/use-route-link-element.d.ts +1 -1
  63. package/dist/shared/routing/use-route-link-element.js +5 -6
  64. package/dist/shared/routing/use-route-link.d.ts +1 -1
  65. package/dist/shared/routing/use-route-link.js +1 -0
  66. package/dist/shared/routing/use-router.d.ts +1 -0
  67. package/dist/shared/routing/use-router.js +13 -0
  68. package/dist/shared/routing/with-routing.d.ts +1 -0
  69. package/dist/shared/routing/with-routing.js +2 -1
  70. package/dist/sidebar/sidebar-provider.js +0 -2
  71. package/dist/styles.css +31 -1
  72. package/package.json +1 -1
  73. package/dist/shared/hooks/use-cookie.js +0 -34
@@ -2,7 +2,8 @@ import { ReactNode } from 'react';
2
2
  import { ImageType } from '../../../../shared/model/image';
3
3
  export interface SignInPageLayoutProps {
4
4
  children?: ReactNode;
5
+ 'data-test-selector': string;
5
6
  fullHeight?: boolean;
6
7
  image?: ImageType;
7
8
  }
8
- export declare function SignInPageLayout({ children, fullHeight, image, }: SignInPageLayoutProps): import("react/jsx-runtime").JSX.Element;
9
+ export declare function SignInPageLayout({ children, 'data-test-selector': dataTestSelector, fullHeight, image, }: SignInPageLayoutProps): import("react/jsx-runtime").JSX.Element;
@@ -1,14 +1,12 @@
1
1
  "use client";
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import clsx from 'clsx';
4
- import { useIsBreakpoint } from '../../../../shared/hooks/use-is-breakpoint.js';
5
4
  import { Image } from '../../../../media/image/image.js';
6
5
  import { SIGN_IN_PAGE_BACKGROUND_IMAGE } from './sign-in-page-background-image.js';
7
6
  import styles from './sign-in-page-layout.module.css.js';
8
7
 
9
- function SignInPageLayout({ children, fullHeight, image = SIGN_IN_PAGE_BACKGROUND_IMAGE, }) {
10
- const isLg = useIsBreakpoint('lg');
11
- return (jsxs("div", { className: clsx(styles['sign-in-page-layout'], fullHeight && styles['full-height']), children: [jsx("section", { className: styles.main, children: children }), isLg && (jsx("div", { className: styles.side, children: jsx("div", { className: styles.image, children: jsx(Image, { image: image, title: "" }) }) }))] }));
8
+ function SignInPageLayout({ children, 'data-test-selector': dataTestSelector, fullHeight, image = SIGN_IN_PAGE_BACKGROUND_IMAGE, }) {
9
+ return (jsxs("div", { className: clsx(styles['sign-in-page-layout'], fullHeight && styles['full-height']), "data-test-selector": dataTestSelector, children: [jsx("section", { className: styles.main, children: children }), jsx("div", { className: styles.side, children: jsx("div", { className: styles.image, children: jsx(Image, { image: image, title: "" }) }) })] }));
12
10
  }
13
11
 
14
12
  export { SignInPageLayout };
@@ -37,7 +37,7 @@ function SignInPage({ returnUrl } = {}) {
37
37
  navigate(returnUrl || paths.HOME, { reload: true });
38
38
  };
39
39
  const allowGuestSignIn = returnUrl === paths.CHECKOUT_SHIPPING;
40
- const createAccountPath = `${paths.ACCOUNT_CREATE}${returnUrl ? `?returnUrl=${returnUrl}` : ''}`;
40
+ const createAccountPath = `${paths.ACCOUNT_CREATE}${returnUrl ? `?returnUrl=${encodeURIComponent(returnUrl)}` : ''}`;
41
41
  const onSubmit = ({ data }) => {
42
42
  resetSignIn();
43
43
  resetCreateGuest();
@@ -57,7 +57,7 @@ function SignInPage({ returnUrl } = {}) {
57
57
  const onRecoverPasswordDialogOpen = () => {
58
58
  setRecoverPasswordDialogOpen(true);
59
59
  };
60
- return (jsxs(Fragment, { children: [jsx(SignInPageLayout, { fullHeight: true, children: jsx(SignInForm, { allowGuestSignIn: allowGuestSignIn, createAccountPath: createAccountPath, errorType: errorType, initialEmail: session?.isGuest ? '' : session?.email, initialRememberMe: session?.rememberMe, isDisabled: !session || isSuccess, isLoading: isLoading, isPendingGuestSignIn: isPendingCreateGuest, isPendingUserSignIn: isPendingSignIn, onRecoverPasswordDialogOpen: onRecoverPasswordDialogOpen, onSubmit: onSubmit }) }), jsx(RecoverPasswordDialog, { isOpen: isRecoverPasswordDialogOpen, onOpenChange: isOpen => setRecoverPasswordDialogOpen(isOpen) })] }));
60
+ return (jsxs(Fragment, { children: [jsx(SignInPageLayout, { fullHeight: true, "data-test-selector": "signInPage", children: jsx(SignInForm, { allowGuestSignIn: allowGuestSignIn, createAccountPath: createAccountPath, errorType: errorType, initialEmail: session?.isGuest ? '' : session?.email, initialRememberMe: session?.rememberMe, isDisabled: !session || isSuccess, isLoading: isLoading, isPendingGuestSignIn: isPendingCreateGuest, isPendingUserSignIn: isPendingSignIn, onRecoverPasswordDialogOpen: onRecoverPasswordDialogOpen, onSubmit: onSubmit }) }), jsx(RecoverPasswordDialog, { isOpen: isRecoverPasswordDialogOpen, onOpenChange: isOpen => setRecoverPasswordDialogOpen(isOpen) })] }));
61
61
  }
62
62
 
63
63
  export { SignInPage };
@@ -82,7 +82,7 @@ function CartContent({ cartLines }) {
82
82
  if (!currencyCode)
83
83
  throw new Error(`Currency code not found for symbol ${currentCart.currencySymbol}`);
84
84
  return (jsx(CheckoutPageLayout, { actions: {
85
- primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", href: "/CheckoutShipping", children: jsx(FormattedMessage, { id: "Start checkout" }) })),
85
+ primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutShippingCartTotalContinueButton", href: paths.CHECKOUT_SHIPPING, children: jsx(FormattedMessage, { id: "Start checkout" }) })),
86
86
  secondary: isAuthenticated ? (jsx(Button, { color: "secondary", "data-test-selector": "saveCartForLaterButton", onClick: () => {
87
87
  saveCartForLater.mutate({ cart: currentCart });
88
88
  }, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })) : (jsx(Button, { color: "secondary", "data-test-selector": "saveCartForLaterButton", href: paths.SIGN_IN, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })),
@@ -51,7 +51,7 @@ function OrderConfirmationPageContent({ cart, }) {
51
51
  label: t('Order confirmation'),
52
52
  },
53
53
  ], "data-test-selector": "orderConfirmationPage", title: t('Order confirmation'), children: jsx(CheckoutPageLayout, { actions: {
54
- primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutReviewAndSubmit_continueShopping", href: "/", children: jsx(FormattedMessage, { id: "Continue shopping" }) })),
54
+ primary: (jsx(Button, { withArrow: true, "data-test-selector": "checkoutReviewAndSubmit_continueShopping", href: paths.HOME, children: jsx(FormattedMessage, { id: "Continue shopping" }) })),
55
55
  secondary: (jsxs(Fragment, { children: [cart.canSaveOrder && (jsx(Button, { color: "secondary", onClick: () => {
56
56
  saveCartForLater.mutate({ cart });
57
57
  }, variant: "outline", children: jsx(FormattedMessage, { id: "Save order" }) })), jsx(PrintButton, {})] })),
@@ -9,7 +9,8 @@ import { AddressDataCard } from './components/address-data-card.js';
9
9
 
10
10
  function ConnectedBillToAddressWidget({ billToId = 'current', } = {}) {
11
11
  const paths = usePaths();
12
- const { href } = useLocation();
12
+ const { pathname, search } = useLocation();
13
+ const href = `${pathname}${search}`;
13
14
  const editAddressUrl = `${paths.ACCOUNT_EDIT_BILL_TO_ADDRESS}/${billToId}?returnUrl=${encodeURIComponent(href)}`;
14
15
  const { data: billToAddress, error, isLoading, } = useFetchBillToAddress({ billToId });
15
16
  return (jsx(AddressDataCard, { actions: [
@@ -9,7 +9,8 @@ import { AddressDataCard } from './components/address-data-card.js';
9
9
 
10
10
  function ConnectedShipToAddressWidget({ billToId = 'current', shipToId = 'current', } = {}) {
11
11
  const paths = usePaths();
12
- const { href } = useLocation();
12
+ const { pathname, search } = useLocation();
13
+ const href = `${pathname}${search}`;
13
14
  const editAddressUrl = `${paths.ACCOUNT_EDIT_BILL_TO_ADDRESS}/${billToId}${paths.ACCOUNT_EDIT_SHIP_TO_ADDRESS}/${shipToId}?returnUrl=${encodeURIComponent(href)}`;
14
15
  const createAddressUrl = `${paths.ACCOUNT_EDIT_BILL_TO_ADDRESS}/${billToId}${paths.ACCOUNT_EDIT_SHIP_TO_ADDRESS}/new?returnUrl=${encodeURIComponent(href)}`;
15
16
  const { data: shipToAddress, error, isLoading, } = useFetchShipToAddress({
@@ -6,7 +6,6 @@ import { ImageLightbox } from '../../../../../media/image-lightbox/image-lightbo
6
6
  import { ZoomImage } from '../../../../../media/zoom-image/zoom-image.js';
7
7
  import { Modal } from '../../../../../modals/modal/modal.js';
8
8
  import { useDisclosure } from '../../../../../shared/hooks/use-disclosure.js';
9
- import { useIsBreakpoint } from '../../../../../shared/hooks/use-is-breakpoint.js';
10
9
  import styles from './product-detail-images.module.css.js';
11
10
 
12
11
  const MAX_IMAGES = 5;
@@ -16,7 +15,6 @@ function ProductDetailImages({ images }) {
16
15
  const [scrollPercentage, setScrollPercentage] = useState(0);
17
16
  const { isOpen: isOpenModal, open: openModal, toggle: toggleModal, } = useDisclosure();
18
17
  const { close: closeZoom, isOpen: isOpenZoom, open: openZoom, } = useDisclosure();
19
- const isXl = useIsBreakpoint('xl');
20
18
  if (images.length > MAX_IMAGES) {
21
19
  images = images.slice(0, MAX_IMAGES);
22
20
  }
@@ -29,7 +27,7 @@ function ProductDetailImages({ images }) {
29
27
  setScrollPercentage(scrollPercentage);
30
28
  openZoom();
31
29
  }
32
- return (jsxs(Fragment, { children: [isXl ? (jsxs(Fragment, { children: [jsx(ImagesGrid, { images: images, onSelectImage: (image, _index) => handleOpenImage(image) }), jsx(Modal, { hasCloseButton: true, isDismissable: true, isFullScreen: true, isKeyboardDismissDisabled: false, isOpen: isOpenModal, onOpenChange: toggleModal, shouldCloseOnInteractOutside: false, children: jsx("div", { className: styles['image-lightbox-modal'], children: jsx(ImageLightbox, { images: images, initialSelectedIndex: selectedImageIndex, onZoom: onZoom, variant: "lg" }) }) })] })) : (jsx(ImageLightbox, { images: images, onZoom: onZoom })), isOpenZoom && (jsx(ZoomImage, { currentImage: images[selectedZoomImageIndex], isZoomed: isOpenZoom, onClose: closeZoom, scrollFromTopPercentage: scrollPercentage }))] }));
30
+ return (jsxs(Fragment, { children: [jsx(ImagesGrid, { className: styles['images-grid'], images: images, onSelectImage: (image, _index) => handleOpenImage(image) }), isOpenModal && (jsx(Modal, { hasCloseButton: true, isDismissable: true, isFullScreen: true, isKeyboardDismissDisabled: false, isOpen: isOpenModal, onOpenChange: toggleModal, shouldCloseOnInteractOutside: false, children: jsx("div", { className: styles['image-lightbox-modal'], children: jsx(ImageLightbox, { images: images, initialSelectedIndex: selectedImageIndex, onZoom: onZoom, variant: "lg" }) }) })), jsx(ImageLightbox, { className: styles['image-lightbox'], images: images, onZoom: onZoom }), isOpenZoom && (jsx(ZoomImage, { currentImage: images[selectedZoomImageIndex], isZoomed: isOpenZoom, onClose: closeZoom, scrollFromTopPercentage: scrollPercentage }))] }));
33
31
  }
34
32
 
35
33
  export { ProductDetailImages };
@@ -1,3 +1,3 @@
1
- var styles = {"image-lightbox-modal":"product-detail-images-module-ERzjA"};
1
+ var styles = {"image-lightbox-modal":"product-detail-images-module-ERzjA","images-grid":"product-detail-images-module-cdIHn","image-lightbox":"product-detail-images-module-0udrk"};
2
2
 
3
3
  export { styles as default };
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
+ import { useEffect } from 'react';
3
4
  import { ConnectedProductCard } from '../../../cards/product-card/connected-product-card.js';
4
5
  import { CardCarousel } from '../../../carousel/card-carousel/card-carousel.js';
5
6
  import { ProductUSPCarousel } from '../../../carousel/usp-carousel/product-usp-carousel.js';
@@ -15,7 +16,10 @@ import { ProductDetailsRecentlyViewedSection } from './components/product-detail
15
16
 
16
17
  function ProductDetails({ data, priceComponent, }) {
17
18
  const { breadCrumb, included, page, product, usps } = data;
18
- useMarkProductAsRecentlyViewed({ productId: product.id });
19
+ const { mutate } = useMarkProductAsRecentlyViewed();
20
+ useEffect(() => {
21
+ mutate({ productId: product.id });
22
+ }, [mutate, product]);
19
23
  useDataLayer({
20
24
  event: {
21
25
  event: 'view_item',
@@ -3,12 +3,14 @@ import { jsxs, jsx } from 'react/jsx-runtime';
3
3
  import { Button } from '../../../../buttons/button/button.js';
4
4
  import { FormattedMessage } from '../../../../intl/formatted-message.js';
5
5
  import { useIsBreakpoint } from '../../../../shared/hooks/use-is-breakpoint.js';
6
+ import { usePaths } from '../../../../shared/routing/use-paths.js';
6
7
  import { Heading } from '../../../../typography/heading/heading.js';
7
8
  import styles from './no-results.module.css.js';
8
9
 
9
10
  function NoResults({ content, title }) {
11
+ const paths = usePaths();
10
12
  const isLg = useIsBreakpoint('lg');
11
- return (jsxs("div", { className: styles['no-results'], children: [jsx(Heading, { bold: false, className: styles.title, size: isLg ? 's' : 'xs', tag: "h2", children: title }), jsx("p", { className: styles.body, children: content }), jsx("div", { className: styles.buttons, children: jsx(Button, { withArrow: true, "data-test-selector": "buttonContinueShopping", href: "/", size: "md", children: jsx(FormattedMessage, { id: "Continue shopping" }) }) })] }));
13
+ return (jsxs("div", { className: styles['no-results'], children: [jsx(Heading, { bold: false, className: styles.title, size: isLg ? 's' : 'xs', tag: "h2", children: title }), jsx("p", { className: styles.body, children: content }), jsx("div", { className: styles.buttons, children: jsx(Button, { withArrow: true, "data-test-selector": "buttonContinueShopping", href: paths.HOME, size: "md", children: jsx(FormattedMessage, { id: "Continue shopping" }) }) })] }));
12
14
  }
13
15
 
14
16
  export { NoResults };
@@ -12,10 +12,12 @@ function useFetchCurrentCartWithAtp({ forceRecalculation = true, select = cartMo
12
12
  select(atp
13
13
  ? {
14
14
  ...cartResult.data,
15
- cartLines: cartResult.data.cartLines?.map(line => ({
16
- ...line,
17
- atp: atp.find(a => a.productCode === line.erpNumber) || null,
18
- })),
15
+ cartLines: cartResult.data.cartLines?.map(line => {
16
+ const matchingAtp = atp.find(a => a.productCode === line.erpNumber);
17
+ if (!matchingAtp)
18
+ return line;
19
+ return { ...line, atp: matchingAtp };
20
+ }),
19
21
  }
20
22
  : cartResult.data),
21
23
  error: cartResult.error || error,
@@ -1,3 +1,5 @@
1
- export declare function useMarkProductAsRecentlyViewed({ productId, }: {
2
- productId?: string;
3
- }): import("@tanstack/react-query").UseQueryResult<void, Error>;
1
+ interface MarkProductAsRecentlyViewedParams {
2
+ productId: string;
3
+ }
4
+ export declare function useMarkProductAsRecentlyViewed(): import("@tanstack/react-query").UseMutationResult<void, Error, MarkProductAsRecentlyViewedParams, unknown>;
5
+ export {};
@@ -1,19 +1,15 @@
1
- import { useQueryClient, useQuery } from '@tanstack/react-query';
1
+ import { useQueryClient, useMutation } from '@tanstack/react-query';
2
2
  import { markProductAsRecentlyViewed } from '../../services/product-service.js';
3
3
 
4
- function useMarkProductAsRecentlyViewed({ productId, }) {
4
+ function useMarkProductAsRecentlyViewed() {
5
5
  const queryClient = useQueryClient();
6
- return useQuery({
7
- enabled: Boolean(productId),
8
- gcTime: 0,
9
- queryFn: () => {
6
+ return useMutation({
7
+ mutationFn: async ({ productId }) => {
10
8
  markProductAsRecentlyViewed({ productId: productId });
11
9
  queryClient.invalidateQueries({
12
10
  queryKey: ['products', 'recently-viewed'],
13
11
  });
14
12
  },
15
- queryKey: ['mark-product-as-recently-viewed', productId],
16
- staleTime: 0,
17
13
  });
18
14
  }
19
15
 
@@ -1,8 +1,13 @@
1
1
  import { config } from '../../../../config.js';
2
2
  import { request } from '../../../fetch/request.js';
3
+ import { TIME } from '../../../utils/time.js';
3
4
 
4
5
  async function fetchCountriesLanguages() {
5
6
  const { body } = await request({
7
+ next: {
8
+ revalidate: 1 * TIME.DAY,
9
+ tags: ['countries-languages'],
10
+ },
6
11
  url: `${config.SHOP_API_URL}/api/v1/websites/current?expand=languages%2Ccountries`,
7
12
  });
8
13
  return {
@@ -12,6 +17,10 @@ async function fetchCountriesLanguages() {
12
17
  }
13
18
  async function fetchCountriesWithLanguages() {
14
19
  const { body } = await request({
20
+ next: {
21
+ revalidate: 1 * TIME.DAY,
22
+ tags: ['countries-languages'],
23
+ },
15
24
  url: `${config.SHOP_API_URL}/api/v1/custom/countrylanguage`,
16
25
  });
17
26
  return body;
@@ -1 +1,5 @@
1
- export declare function useDebouncedCallback<T extends (...args: any[]) => any>(func: T, delay: number): (...args: Parameters<T>) => Promise<ReturnType<T>>;
1
+ export interface DebouncedCallback<T extends (...args: any[]) => any> {
2
+ (...args: Parameters<T>): Promise<ReturnType<T>>;
3
+ cancel: VoidFunction;
4
+ }
5
+ export declare function useDebouncedCallback<T extends (...args: any[]) => any>(func: T, delay: number): DebouncedCallback<T>;
@@ -4,16 +4,16 @@ import { useRef, useCallback } from 'react';
4
4
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
5
5
  function useDebouncedCallback(func, delay) {
6
6
  const timeoutId = useRef();
7
- return useCallback(function debounced(...args) {
8
- return new Promise(resolve => {
9
- if (typeof window === 'undefined')
10
- return resolve(func(...args));
11
- clearTimeout(timeoutId.current);
12
- timeoutId.current = setTimeout(() => {
13
- resolve(func(...args));
14
- }, delay);
15
- });
16
- }, [delay, func]);
7
+ const debounced = (...args) => new Promise(resolve => {
8
+ if (typeof window === 'undefined')
9
+ return resolve(func(...args));
10
+ clearTimeout(timeoutId.current);
11
+ timeoutId.current = setTimeout(() => {
12
+ resolve(func(...args));
13
+ }, delay);
14
+ });
15
+ debounced.cancel = () => clearTimeout(timeoutId.current);
16
+ return useCallback(debounced, [delay, func]);
17
17
  }
18
18
 
19
19
  export { useDebouncedCallback };
@@ -1,5 +1,10 @@
1
- import { ReactNode } from 'react';
2
- export declare function ReactQueryContainer({ children, enableDevTools, }: {
3
- children: ReactNode;
1
+ import { ReactElement, ReactNode } from 'react';
2
+ import { QueryClient } from '@tanstack/react-query';
3
+ export declare const globalQueryClient: QueryClient;
4
+ export declare function ReactQueryContainer({ children, enableDevTools, queryClient, }: {
5
+ children: ReactNode | ((args: {
6
+ queryClient: QueryClient;
7
+ }) => ReactNode | ReactElement);
4
8
  enableDevTools?: boolean;
9
+ queryClient?: QueryClient;
5
10
  }): import("react/jsx-runtime").JSX.Element;
@@ -5,7 +5,7 @@ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
5
5
  import { environment } from '../utils/environment.js';
6
6
  import { TIME } from '../utils/time.js';
7
7
 
8
- const queryClient = new QueryClient({
8
+ const globalQueryClient = new QueryClient({
9
9
  defaultOptions: {
10
10
  queries: {
11
11
  /* Set gcTime and staleTime to 0 to disable react query cache */
@@ -15,8 +15,8 @@ const queryClient = new QueryClient({
15
15
  },
16
16
  },
17
17
  });
18
- function ReactQueryContainer({ children, enableDevTools = environment !== 'production', }) {
19
- return (jsxs(QueryClientProvider, { client: queryClient, children: [enableDevTools && jsx(ReactQueryDevtools, { initialIsOpen: false }), children] }));
18
+ function ReactQueryContainer({ children, enableDevTools = environment !== 'production', queryClient = globalQueryClient, }) {
19
+ return (jsxs(QueryClientProvider, { client: queryClient, children: [enableDevTools && jsx(ReactQueryDevtools, { initialIsOpen: false }), children instanceof Function ? children({ queryClient }) : children] }));
20
20
  }
21
21
 
22
- export { ReactQueryContainer };
22
+ export { ReactQueryContainer, globalQueryClient };
@@ -0,0 +1,2 @@
1
+ import { RouteContextValue } from './types';
2
+ export declare const RouteContext: React.Context<RouteContextValue | undefined>;
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ import { createContext } from 'react';
3
+
4
+ const RouteContext = createContext(undefined);
5
+
6
+ export { RouteContext };
@@ -7,6 +7,7 @@ export interface RouteProviderProps {
7
7
  paths: Paths;
8
8
  url: {
9
9
  basePathname?: string;
10
+ href: string;
10
11
  pathname: string;
11
12
  search: string;
12
13
  };
@@ -1,17 +1,16 @@
1
1
  "use client";
2
- import { jsx, Fragment } from 'react/jsx-runtime';
3
- import { useGlobalState } from '../providers/global-state-provider.js';
4
- import { withRouting } from './with-routing.js';
2
+ import { jsx } from 'react/jsx-runtime';
3
+ import { useMemo } from 'react';
4
+ import { RouteContext } from './route-context.js';
5
5
 
6
- function RouteProvider({ children, Link = FallbackRouteLink, navigate, paths, url, }) {
7
- useGlobalState('routing', {
6
+ function RouteProvider({ children, Link, navigate, paths, url, }) {
7
+ const value = useMemo(() => ({
8
8
  Link,
9
9
  navigate,
10
10
  paths,
11
11
  url,
12
- });
13
- return jsx(Fragment, { children: children });
12
+ }), [Link, navigate, paths, url]);
13
+ return jsx(RouteContext.Provider, { value: value, children: children });
14
14
  }
15
- const FallbackRouteLink = withRouting('a');
16
15
 
17
16
  export { RouteProvider };
@@ -18,12 +18,13 @@ export interface Paths {
18
18
  REVIEW_AND_SUBMIT: string;
19
19
  SIGN_IN: string;
20
20
  }
21
- export interface RouteContext {
21
+ export interface RouteContextValue {
22
22
  Link?: ElementType<RouteLinkElementProps>;
23
23
  navigate: NavigateFunction;
24
24
  paths: Paths;
25
25
  url: {
26
26
  basePathname?: string;
27
+ href: string;
27
28
  pathname: string;
28
29
  search: string;
29
30
  };
@@ -1,9 +1,9 @@
1
1
  import qs from 'query-string';
2
2
  export declare function useLocation(): {
3
3
  basePathname: string | undefined;
4
- fullPathname: string | undefined;
4
+ fullPathname: string;
5
5
  href: string;
6
- pathname: string | undefined;
6
+ pathname: string;
7
7
  query: qs.ParsedQuery<string>;
8
- search: string | undefined;
8
+ search: string;
9
9
  };
@@ -1,15 +1,15 @@
1
+ "use client";
1
2
  import qs from 'query-string';
2
- import { useGlobalState } from '../providers/global-state-provider.js';
3
+ import { useRouter } from './use-router.js';
3
4
 
4
5
  function useLocation() {
5
- const [routeState] = useGlobalState('routing');
6
- const { url: { basePathname, pathname, search }, } = routeState || { url: {} };
6
+ const { url: { basePathname, href, pathname, search }, } = useRouter();
7
7
  const query = qs.parse(search || '');
8
8
  return {
9
9
  basePathname,
10
10
  fullPathname: pathname,
11
- href: `${pathname}${search}`,
12
- pathname: pathname?.replace(new RegExp(`^${basePathname}`), ''),
11
+ href,
12
+ pathname: pathname.replace(new RegExp(`^${basePathname}`), ''),
13
13
  query,
14
14
  search,
15
15
  };
@@ -1,22 +1,19 @@
1
1
  "use client";
2
2
  import { useRef, useCallback } from 'react';
3
- import { useGlobalState } from '../providers/global-state-provider.js';
4
3
  import { useOnNavigate } from './use-on-navigate.js';
4
+ import { useRouter } from './use-router.js';
5
5
 
6
6
  function useNavigate() {
7
7
  const isNavigatingRef = useRef(false);
8
- const [state] = useGlobalState('routing');
8
+ const routeState = useRouter();
9
9
  const trigger = useOnNavigate(() => {
10
10
  isNavigatingRef.current = false;
11
11
  });
12
- if (!state) {
13
- throw new Error('RouteProvider not found');
14
- }
15
12
  const navigate = useCallback((href, options) => {
16
13
  trigger(href, options);
17
14
  isNavigatingRef.current = true;
18
- return state.navigate(href, options);
19
- }, [state, trigger]);
15
+ return routeState.navigate(href, options);
16
+ }, [routeState, trigger]);
20
17
  return { isNavigating: isNavigatingRef.current, navigate };
21
18
  }
22
19
 
@@ -1,10 +1,9 @@
1
- import { useGlobalState } from '../providers/global-state-provider.js';
1
+ "use client";
2
+ import { useRouter } from './use-router.js';
2
3
 
3
4
  function usePaths() {
4
- const [routeState] = useGlobalState('routing');
5
- if (!routeState)
6
- throw new Error('usePaths must be used within a RouteProvider context');
7
- return routeState.paths;
5
+ const { paths } = useRouter();
6
+ return paths;
8
7
  }
9
8
 
10
9
  export { usePaths };
@@ -1 +1 @@
1
- export declare function useRouteLinkElement(): React.ElementType<import("./types").RouteLinkElementProps> | undefined;
1
+ export declare function useRouteLinkElement(): React.ElementType<import("./types").RouteLinkElementProps>;
@@ -1,11 +1,10 @@
1
- import { useGlobalState } from '../providers/global-state-provider.js';
1
+ "use client";
2
+ import { useRouter } from './use-router.js';
3
+ import { FallbackRouteLink } from './with-routing.js';
2
4
 
3
5
  function useRouteLinkElement() {
4
- const [state] = useGlobalState('routing');
5
- if (!state) {
6
- throw new Error('RouteProvider not found');
7
- }
8
- return state.Link;
6
+ const { Link } = useRouter();
7
+ return Link || FallbackRouteLink;
9
8
  }
10
9
 
11
10
  export { useRouteLinkElement };
@@ -1,6 +1,6 @@
1
1
  import { NavigateOptions } from './types';
2
2
  export declare function useRouteLink(): {
3
- RouteLinkElement: React.ElementType<import("./types").RouteLinkElementProps> | undefined;
3
+ RouteLinkElement: React.ElementType<import("./types").RouteLinkElementProps>;
4
4
  getRouteLinkProps: (href: string, route?: NavigateOptions) => {
5
5
  href: string;
6
6
  onNavigate: () => void;
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { useCallback } from 'react';
2
3
  import { buildHref } from './route-utils.js';
3
4
  import { useLocation } from './use-location.js';
@@ -0,0 +1 @@
1
+ export declare function useRouter(): import("./types").RouteContextValue;
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { useContext } from 'react';
3
+ import { RouteContext } from './route-context.js';
4
+
5
+ function useRouter() {
6
+ const context = useContext(RouteContext);
7
+ if (!context) {
8
+ throw new Error('useRouter must be used within a RouteProvider');
9
+ }
10
+ return context;
11
+ }
12
+
13
+ export { useRouter };
@@ -5,3 +5,4 @@ export interface WithRoutingProps {
5
5
  route?: NavigateOptions;
6
6
  }
7
7
  export declare function withRouting(component: ElementType<RouteLinkElementProps>): React.FunctionComponent<RouteLinkElementProps>;
8
+ export declare const FallbackRouteLink: React.FunctionComponent<RouteLinkElementProps>;
@@ -29,5 +29,6 @@ function withRouting(component) {
29
29
  Component.displayName = `WithRouting(${component.toString()})`;
30
30
  return Component;
31
31
  }
32
+ const FallbackRouteLink = withRouting('a');
32
33
 
33
- export { withRouting };
34
+ export { FallbackRouteLink, withRouting };
@@ -41,8 +41,6 @@ function SidebarProvider({ children }) {
41
41
  const { close, isDocked, isOpen, transition } = state;
42
42
  return (jsxs("div", { className: clsx(styles['sidebar-container'], {
43
43
  [styles['transition']]: transition,
44
- [styles['docked']]: isDocked,
45
- [styles['open']]: isOpen,
46
44
  }), children: [jsx(SidebarDetectBreakpoint, {}), children, jsx(BackgroundOverlay, { isOpen: isDocked && isOpen, onClick: close })] }));
47
45
  }
48
46
 
package/dist/styles.css CHANGED
@@ -479,7 +479,7 @@ html {
479
479
  grid-template-rows: 1fr;
480
480
  }
481
481
 
482
- .accordion-module-9WvAH .accordion-module-lf9d-:has(.accordion-module--Rwpb[disabled]) {
482
+ .accordion-module-9WvAH .accordion-module-lf9d-:has(.accordion-module--Rwpb[disabled]):not(.accordion-module-RnNRT) {
483
483
  border-color: var(--color-brand-light-gray);
484
484
  }
485
485
 
@@ -2218,6 +2218,21 @@ html {
2218
2218
  content: '/';
2219
2219
  margin-inline: 10px;
2220
2220
  }
2221
+ .breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-ToeDB {
2222
+ display: flex;
2223
+ }
2224
+ .breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-np5GK {
2225
+ display: none;
2226
+ }
2227
+ @media (width >= 768px) {
2228
+ .breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-ToeDB {
2229
+ display: none;
2230
+ }
2231
+
2232
+ .breadcrumb-module-CQGse .breadcrumb-module-hxhDY.breadcrumb-module-np5GK {
2233
+ display: flex;
2234
+ }
2235
+ }
2221
2236
  @media (width < 768px) {
2222
2237
  .breadcrumb-module-CQGse .breadcrumb-module-hxhDY::after {
2223
2238
  display: none;
@@ -3369,6 +3384,7 @@ html {
3369
3384
 
3370
3385
  .product-card-module-pLaiB .product-card-module-XzunM {
3371
3386
  z-index: var(--z-top);
3387
+ margin: 0;
3372
3388
  grid-area: sku;
3373
3389
  justify-self: start;
3374
3390
  -webkit-user-select: all;
@@ -8555,6 +8571,20 @@ button.swiper-pagination-bullet {
8555
8571
  padding: 64px 48px;
8556
8572
  }
8557
8573
 
8574
+ .product-detail-images-module-cdIHn {
8575
+ display: none;
8576
+ }
8577
+
8578
+ @media (width >= 1024px) {
8579
+ .product-detail-images-module-0udrk {
8580
+ display: none;
8581
+ }
8582
+
8583
+ .product-detail-images-module-cdIHn {
8584
+ display: grid;
8585
+ }
8586
+ }
8587
+
8558
8588
  .product-details-panel-module-MXfPm {
8559
8589
  display: flex;
8560
8590
  flex-direction: column;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonic-equipment/ui",
3
- "version": "201.0.0",
3
+ "version": "203.0.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "engines": {