@sonic-equipment/ui 0.0.26 → 0.0.27

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 (35) hide show
  1. package/dist/algolia/algolia-pagination.d.ts +5 -1
  2. package/dist/algolia/algolia-sonic-searchclient.d.ts +2 -0
  3. package/dist/buttons/icon-button/icon-button.d.ts +2 -1
  4. package/dist/cards/product-card/product-card.d.ts +5 -3
  5. package/dist/cards/product-card/product-card.stories.d.ts +2 -1
  6. package/dist/filters/pagination/pagination.d.ts +2 -2
  7. package/dist/icons/arrows/text-aligned-arrow-icon.d.ts +2 -0
  8. package/dist/icons/magnifying-glass/magnifying-glass-icon.d.ts +2 -0
  9. package/dist/icons/math/minus-filled-icon.d.ts +2 -0
  10. package/dist/icons/math/plus-filled-icon.d.ts +2 -0
  11. package/dist/icons/reset/reset-icon.d.ts +2 -0
  12. package/dist/icons/trash/trash-outlined-icon.d.ts +2 -0
  13. package/dist/index.d.ts +19 -7
  14. package/dist/index.js +107 -45
  15. package/dist/intl/translation-id.d.ts +1 -1
  16. package/dist/pages/product-listing-page/product-listing-page.stories.d.ts +2 -0
  17. package/dist/search/global-search/clear-icon.d.ts +2 -0
  18. package/dist/search/global-search/global-search.d.ts +19 -0
  19. package/dist/search/global-search/global-search.stories.d.ts +14 -0
  20. package/dist/search/global-search/highlight.d.ts +21 -0
  21. package/dist/search/global-search/plugins/categories-plugin.d.ts +10 -0
  22. package/dist/search/global-search/plugins/popular-categories-plugin.d.ts +11 -0
  23. package/dist/search/global-search/plugins/popular-searches-plugin.d.ts +12 -0
  24. package/dist/search/global-search/plugins/products-plugin.d.ts +23 -0
  25. package/dist/search/global-search/plugins/query-suggestions-plugin.d.ts +12 -0
  26. package/dist/search/global-search/plugins/quick-access-plugin.d.ts +13 -0
  27. package/dist/search/global-search/plugins/recent-searches-plugin.d.ts +7 -0
  28. package/dist/search/global-search/search-icon.d.ts +2 -0
  29. package/dist/search/global-search/types.d.ts +23 -0
  30. package/dist/search/search-input/search-input.d.ts +5 -0
  31. package/dist/search/search-input/search-input.stories.d.ts +6 -0
  32. package/dist/shared/hooks/use-scroll-to.d.ts +7 -0
  33. package/dist/styles.css +84 -24
  34. package/package.json +10 -6
  35. /package/dist/shared/hooks/{use-debounce-callback.d.ts → use-debounced-callback.d.ts} +0 -0
@@ -1 +1,5 @@
1
- export declare function AlgoliaPagination(): import("react/jsx-runtime").JSX.Element;
1
+ interface AlgoliaPaginationProps {
2
+ onChange: (pageNumber: number) => void;
3
+ }
4
+ export declare function AlgoliaPagination({ onChange }: AlgoliaPaginationProps): import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,2 @@
1
+ import { SearchClient } from 'algoliasearch/lite';
2
+ export declare const createSonicSearchClient: (url: string) => SearchClient;
@@ -6,5 +6,6 @@ export interface IconButtonProps {
6
6
  isDisabled?: boolean;
7
7
  onPress?: VoidFunction;
8
8
  size?: 'md' | 'lg';
9
+ type?: 'button' | 'submit' | 'reset';
9
10
  }
10
- export declare function IconButton({ children, className, color, isDisabled, onPress, size, }: IconButtonProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function IconButton({ children, className, color, isDisabled, onPress, size, type, }: IconButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,4 @@
1
- import { ReactElement } from 'react';
1
+ import { MouseEvent, ReactElement } from 'react';
2
2
  import { PressEvent } from 'react-aria-components';
3
3
  import { ImageProps } from 'media/image/image';
4
4
  import type { ProductPrice as ProductPriceType } from 'shared/types/price';
@@ -7,10 +7,12 @@ export interface ProductCardProps {
7
7
  favoriteButton?: ReactElement;
8
8
  href: string;
9
9
  image: ImageProps;
10
- onClick?: (e: PressEvent) => void;
10
+ /** @deprecated Use `onPress` instead */
11
+ onClick?: (e: MouseEvent) => void;
12
+ onPress?: (e: PressEvent) => void;
11
13
  price: ProductPriceType;
12
14
  sku: string;
13
15
  tag?: 'new' | 'sale';
14
16
  title: string;
15
17
  }
16
- export declare function ProductCard({ addToCartButton: AddToCartButton, favoriteButton: FavoriteButton, href, image: { alt, fit, src, title: imageTitle }, onClick, price, sku, tag, title, }: ProductCardProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function ProductCard({ addToCartButton: AddToCartButton, favoriteButton: FavoriteButton, href, image: { alt, fit, src, title: imageTitle }, onClick, onPress, price, sku, tag, title, }: ProductCardProps): import("react/jsx-runtime").JSX.Element;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { StoryObj } from '@storybook/react';
2
3
  import { ProductCard } from './product-card';
3
4
  declare const meta: {
@@ -11,7 +12,7 @@ declare const meta: {
11
12
  src: string;
12
13
  title: string;
13
14
  };
14
- onClick: import("@vitest/spy").Mock<[e: import("react-aria").PressEvent], void>;
15
+ onClick: import("@vitest/spy").Mock<[e: React.MouseEvent<Element, MouseEvent>], void>;
15
16
  sku: string;
16
17
  tag: "new";
17
18
  };
@@ -1,6 +1,6 @@
1
- export interface Props {
1
+ export interface PaginationProps {
2
2
  currentPage: number;
3
3
  onChange: (pageNumber: number) => void;
4
4
  totalPages: number;
5
5
  }
6
- export declare function Pagination({ currentPage, onChange, totalPages }: Props): import("react/jsx-runtime").JSX.Element;
6
+ export declare function Pagination({ currentPage, onChange, totalPages, }: PaginationProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function TextAlignedArrowIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function MagnifyingGlassIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function MinusFilledIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function PlusFilledIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function ResetIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export declare function TrashOutlinedIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- import { ReactElement, MutableRefObject, ReactNode, HTMLAttributeAnchorTarget, FormEventHandler, KeyboardEvent, ComponentType } from 'react';
2
+ import { ReactElement, MutableRefObject, ReactNode, HTMLAttributeAnchorTarget, MouseEvent, FormEventHandler, KeyboardEvent, ComponentType } from 'react';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
  import { PressEvent } from 'react-aria-components';
5
5
  import { SearchClient } from 'algoliasearch/lite';
@@ -205,8 +205,9 @@ interface IconButtonProps {
205
205
  isDisabled?: boolean;
206
206
  onPress?: VoidFunction;
207
207
  size?: 'md' | 'lg';
208
+ type?: 'button' | 'submit' | 'reset';
208
209
  }
209
- declare function IconButton({ children, className, color, isDisabled, onPress, size, }: IconButtonProps): react_jsx_runtime.JSX.Element;
210
+ declare function IconButton({ children, className, color, isDisabled, onPress, size, type, }: IconButtonProps): react_jsx_runtime.JSX.Element;
210
211
 
211
212
  interface LinkButtonProps {
212
213
  children?: React.ReactNode | string;
@@ -265,13 +266,15 @@ interface ProductCardProps {
265
266
  favoriteButton?: ReactElement;
266
267
  href: string;
267
268
  image: ImageProps$1;
268
- onClick?: (e: PressEvent) => void;
269
+ /** @deprecated Use `onPress` instead */
270
+ onClick?: (e: MouseEvent) => void;
271
+ onPress?: (e: PressEvent) => void;
269
272
  price: ProductPrice$1;
270
273
  sku: string;
271
274
  tag?: 'new' | 'sale';
272
275
  title: string;
273
276
  }
274
- declare function ProductCard({ addToCartButton: AddToCartButton, favoriteButton: FavoriteButton, href, image: { alt, fit, src, title: imageTitle }, onClick, price, sku, tag, title, }: ProductCardProps): react_jsx_runtime.JSX.Element;
277
+ declare function ProductCard({ addToCartButton: AddToCartButton, favoriteButton: FavoriteButton, href, image: { alt, fit, src, title: imageTitle }, onClick, onPress, price, sku, tag, title, }: ProductCardProps): react_jsx_runtime.JSX.Element;
275
278
 
276
279
  interface CategoryCardProps {
277
280
  href: string
@@ -437,6 +440,10 @@ interface TextFieldProps {
437
440
  */
438
441
  declare function TextField({ autoFocus, autoGrow, defaultValue, isDisabled, isInvalid, isMultiline, isReadOnly, isRequired, label, maxLength, onChange, onInput, onKeyUp, placeholder, rows, showLabel, size, value, }: TextFieldProps): react_jsx_runtime.JSX.Element;
439
442
 
443
+ declare function LeftArrowFilledIcon(props: React.SVGProps<SVGSVGElement>): react_jsx_runtime.JSX.Element;
444
+
445
+ declare function TextAlignedArrowIcon(props: React.SVGProps<SVGSVGElement>): react_jsx_runtime.JSX.Element;
446
+
440
447
  declare function RightArrowFilledIcon(props: React.SVGProps<SVGSVGElement>): react_jsx_runtime.JSX.Element;
441
448
 
442
449
  declare function CartFilledIcon(props: React.SVGProps<SVGSVGElement>): react_jsx_runtime.JSX.Element;
@@ -451,7 +458,7 @@ declare function FavoriteOutlinedIcon(props: React.SVGProps<SVGSVGElement>): rea
451
458
 
452
459
  declare function HashedOutlinedIcon(props: React.SVGProps<SVGSVGElement>): react_jsx_runtime.JSX.Element;
453
460
 
454
- type TranslationId = 'Chosen filters' | 'Clear filters' | 'Excl. VAT' | 'Hide filters' | 'Incl. VAT' | 'Show' | 'Show all' | 'Show filters' | 'Show less' | 'Sort' | 'articles' | 'article' | 'of';
461
+ type TranslationId = 'Chosen filters' | 'Clear' | 'Clear filters' | 'Excl. VAT' | 'Hide filters' | 'Incl. VAT' | 'Show' | 'Show all' | 'Show filters' | 'Show less' | 'Sort' | 'Submit' | 'articles' | 'article' | 'of';
455
462
 
456
463
  interface FormattedMessageProps {
457
464
  fallbackValue?: string;
@@ -568,7 +575,12 @@ interface AlgoliaMultiSelectFilterSectionProps {
568
575
  }
569
576
  declare function AlgoliaMultiSelectFilterSection({ attribute, }: AlgoliaMultiSelectFilterSectionProps): react_jsx_runtime.JSX.Element;
570
577
 
571
- declare function AlgoliaPagination(): react_jsx_runtime.JSX.Element;
578
+ interface AlgoliaPaginationProps {
579
+ onChange: (pageNumber: number) => void;
580
+ }
581
+ declare function AlgoliaPagination({ onChange }: AlgoliaPaginationProps): react_jsx_runtime.JSX.Element;
582
+
583
+ declare const createSonicSearchClient: (url: string) => SearchClient;
572
584
 
573
585
  interface AlgoliaContextType {
574
586
  online: boolean;
@@ -590,4 +602,4 @@ declare function AlgoliaResultsCount(): string | null;
590
602
 
591
603
  declare function AlgoliaSortBy(): react_jsx_runtime.JSX.Element | null;
592
604
 
593
- export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, type AlgoliaFilterPanelProps, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, type BreadcrumbProps, BreadcrumbProvider, Button, type ButtonProps, type Cart, CartFilledIcon, type CartLine, CartOutlinedIcon, CartProvider, CategoryCarousel, type CategoryCarouselProps, Checkbox, type CheckboxProps$1 as CheckboxProps, ColorCheckbox, type ColorCheckboxProps, ConnectedAddToCartButton, ConnectedBreadcrumb, DehashedOutlinedIcon, FavoriteButton, type FavoriteButtonProps, FavoriteFilledIcon, FavoriteOutlinedIcon, FavoriteProvider, type FilterOption, type Filters, FormattedMessage, type FormattedMessageFunction, type FormattedMessageProps, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, type IconButtonProps, Image, type ImageProps, IntlProvider, type Link$1 as Link, LinkButton, type LinkButtonProps, MultiSelect, type MultiSelectProps, NumberField, type NumberFieldSize, Page, PageLayout, type PageProps, type Product, ProductCard, type ProductCardProps, ProductListingPage, type ProductListingPageProps, ProductOverviewGrid, type ProductOverviewGridProps, ProductPrice, type ProductPriceProps, ProductSku, type ProductSkuProps, type RefinementListItem, RightArrowFilledIcon, Select, type SelectProps, ShowAll, type ShowAllProps, Sidebar, type SidebarProps, SidebarProvider, TextField, useAlgolia, useBreadcrumb, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFavorite, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
605
+ export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, type AlgoliaFilterPanelProps, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, type BreadcrumbProps, BreadcrumbProvider, Button, type ButtonProps, type Cart, CartFilledIcon, type CartLine, CartOutlinedIcon, CartProvider, CategoryCarousel, type CategoryCarouselProps, Checkbox, type CheckboxProps$1 as CheckboxProps, ColorCheckbox, type ColorCheckboxProps, ConnectedAddToCartButton, ConnectedBreadcrumb, DehashedOutlinedIcon, FavoriteButton, type FavoriteButtonProps, FavoriteFilledIcon, FavoriteOutlinedIcon, FavoriteProvider, type FilterOption, type Filters, FormattedMessage, type FormattedMessageFunction, type FormattedMessageProps, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, type IconButtonProps, Image, type ImageProps, IntlProvider, LeftArrowFilledIcon, type Link$1 as Link, LinkButton, type LinkButtonProps, MultiSelect, type MultiSelectProps, NumberField, type NumberFieldSize, Page, PageLayout, type PageProps, type Product, ProductCard, type ProductCardProps, ProductListingPage, type ProductListingPageProps, ProductOverviewGrid, type ProductOverviewGridProps, ProductPrice, type ProductPriceProps, ProductSku, type ProductSkuProps, type RefinementListItem, RightArrowFilledIcon, Select, type SelectProps, ShowAll, type ShowAllProps, Sidebar, type SidebarProps, SidebarProvider, TextAlignedArrowIcon, TextField, createSonicSearchClient, useAlgolia, useBreadcrumb, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFavorite, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
package/dist/index.js CHANGED
@@ -53,6 +53,8 @@ const useBreakpoint = () => {
53
53
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
54
54
  function useDebouncedCallback(func, delay) {
55
55
  const timeoutId = useRef();
56
+ if (typeof window === 'undefined')
57
+ return func;
56
58
  return function debounced(...args) {
57
59
  clearTimeout(timeoutId.current);
58
60
  timeoutId.current = setTimeout(() => {
@@ -274,23 +276,23 @@ function ConnectedBreadcrumb() {
274
276
  return jsx(Breadcrumb, { links: links });
275
277
  }
276
278
 
277
- function RightArrowFilledIcon(props) {
279
+ function TextAlignedArrowIcon(props) {
278
280
  return (jsx("svg", { height: "11", viewBox: "0 0 6 11", width: "6", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M.267 11a.263.263 0 0 1-.226-.402l3.463-5.467a1.2 1.2 0 0 0-.103-1.43L.602.432A.262.262 0 0 1 .805 0h2.181c.078 0 .153.034.203.093l2.081 2.43a3 3 0 0 1 .259 3.575L2.5 10.877a.267.267 0 0 1-.225.123H.266z", fill: "currentColor", fillRule: "evenodd" }) }));
279
281
  }
280
282
 
281
283
  var styles$w = {"button":"button-module-V4meK","icon":"button-module-XaNWz","sm":"button-module-Pbwz7","md":"button-module-GVTEW","condensed":"button-module-GKHQc","lg":"button-module-nyNY8","primary":"button-module-tmyk8","outline":"button-module-vq9GI","solid":"button-module-AjvlY","hover":"button-module-YzPAr","focus":"button-module--xzsY","active":"button-module-XMFzj","ghost":"button-module-f4UVe","right-arrow-icon":"button-module-ydQAo","secondary":"button-module--1bCH"};
282
284
 
283
285
  function Button({ _pseudo = 'none', children, className, color = 'primary', condensed, icon, iconPosition = 'left', isDisabled, onPress, size = 'lg', type = 'button', variant = 'solid', withArrow = false, }) {
284
- return (jsxs(Button$1, { className: clsx(className, styles$w.button, styles$w[variant], styles$w[size], styles$w[color], { [styles$w.condensed]: condensed }, { [styles$w.icon]: icon }, styles$w[_pseudo]), isDisabled: isDisabled, onPress: onPress, type: type, children: [icon && iconPosition === 'left' && (jsx("span", { className: styles$w.icon, children: icon })), children, withArrow && (jsx(RightArrowFilledIcon, { className: styles$w['right-arrow-icon'] })), icon && iconPosition === 'right' && (jsx("span", { className: styles$w.icon, children: icon }))] }));
286
+ return (jsxs(Button$1, { className: clsx(className, styles$w.button, styles$w[variant], styles$w[size], styles$w[color], { [styles$w.condensed]: condensed }, { [styles$w.icon]: icon }, styles$w[_pseudo]), isDisabled: isDisabled, onPress: onPress, type: type, children: [icon && iconPosition === 'left' && (jsx("span", { className: styles$w.icon, children: icon })), children, withArrow && (jsx(TextAlignedArrowIcon, { className: styles$w['right-arrow-icon'] })), icon && iconPosition === 'right' && (jsx("span", { className: styles$w.icon, children: icon }))] }));
285
287
  }
286
288
 
287
289
  var styles$v = {"icon-button":"icon-button-module-4PDK-","md":"icon-button-module-k3s9J","lg":"icon-button-module-agk6Y","primary":"icon-button-module-fTeP4","secondary":"icon-button-module-dM0eo"};
288
290
 
289
- function IconButton({ children, className, color = 'primary', isDisabled, onPress, size = 'md', }) {
291
+ function IconButton({ children, className, color = 'primary', isDisabled, onPress, size = 'md', type = 'button', }) {
290
292
  return (jsx(Button$1, { className: clsx(styles$v['icon-button'], styles$v[size], styles$v[color], className), isDisabled: isDisabled,
291
293
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
292
294
  // @ts-expect-error
293
- onClick: e => e.preventDefault(), onPress: onPress, children: children }));
295
+ onClick: e => e.preventDefault(), onPress: onPress, type: type, children: children }));
294
296
  }
295
297
 
296
298
  function FavoriteFilledIcon(props) {
@@ -351,20 +353,45 @@ function Label({ children, isRequired }) {
351
353
  return (jsxs(Label$1, { className: styles$q.label, children: [children, isRequired && jsx("span", { className: styles$q.required, children: "*" })] }));
352
354
  }
353
355
 
354
- var styles$p = {"field":"number-field-module-gmnog","button-input-container":"number-field-module-8Lvgh"};
356
+ function MinusFilledIcon(props) {
357
+ return (jsx("svg", { height: "2", viewBox: "0 0 8 2", width: "8", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M.12 0S0 .263 0 .668c0 .406.12.669.12.669h7.784S8 1.074 8 .668C8 .263 7.904 0 7.904 0H.12z", fill: "#000", fillRule: "nonzero" }) }));
358
+ }
359
+
360
+ function PlusFilledIcon(props) {
361
+ return (jsx("svg", { height: "8", viewBox: "0 0 8 8", width: "8", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M4.68.12S4.395 0 4.013 0c-.406 0-.693.12-.693.12v3.223H.12S0 3.606 0 4.012s.12.669.12.669h3.2v3.223S3.605 8 4.011 8c.406 0 .669-.096.669-.096V4.681h3.223S8 4.418 8 4.01c0-.405-.096-.668-.096-.668H4.681V.12z", fill: "currentColor", fillRule: "nonzero" }) }));
362
+ }
363
+
364
+ function TrashOutlinedIcon(props) {
365
+ return (jsx("svg", { height: "16", viewBox: "0 0 16 16", width: "16", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M5.182 4.03h.866V2.744c0-.18.058-.324.174-.433a.644.644 0 0 1 .46-.163h2.202c.195 0 .35.055.464.163a.57.57 0 0 1 .17.433V4.03h.872V2.696c0-.424-.13-.757-.39-1-.259-.242-.613-.363-1.063-.363H6.629c-.45 0-.803.121-1.06.364-.258.242-.387.575-.387.999v1.333zm-2.776.433h10.765c.112 0 .208-.04.287-.122a.407.407 0 0 0 .118-.295.4.4 0 0 0-.118-.29.387.387 0 0 0-.287-.121H2.406a.39.39 0 0 0-.284.121.395.395 0 0 0-.122.29.4.4 0 0 0 .122.295c.081.081.176.122.284.122zm2.64 10.204h5.49c.411 0 .747-.126 1.009-.379.261-.252.402-.585.422-.999l.437-8.937h-.88l-.419 8.852a.658.658 0 0 1-.197.455.631.631 0 0 1-.46.18H5.123a.62.62 0 0 1-.454-.183.662.662 0 0 1-.198-.452l-.435-8.851H3.18l.43 8.942c.021.414.162.746.423.996.26.25.599.376 1.013.376zm.955-1.909c.105 0 .19-.03.254-.09a.295.295 0 0 0 .09-.237l-.19-6.519a.32.32 0 0 0-.1-.232.344.344 0 0 0-.244-.088.344.344 0 0 0-.25.091.315.315 0 0 0-.094.237l.19 6.512c.004.1.037.18.099.239a.343.343 0 0 0 .245.087zm1.79 0c.106 0 .19-.03.254-.09a.311.311 0 0 0 .096-.237V5.92a.311.311 0 0 0-.096-.237.353.353 0 0 0-.253-.09c-.105 0-.19.03-.256.09a.306.306 0 0 0-.099.237v6.51c0 .098.033.177.1.238.065.06.15.09.255.09zm1.785.001c.102 0 .183-.03.246-.088a.323.323 0 0 0 .098-.232l.19-6.518a.314.314 0 0 0-.093-.237.346.346 0 0 0-.25-.09c-.1 0-.182.029-.245.087a.326.326 0 0 0-.1.238l-.19 6.513c0 .097.031.175.093.236.062.06.146.091.25.091z", fill: "currentColor", fillRule: "nonzero" }) }));
366
+ }
367
+
368
+ var styles$p = {"field":"number-field-module-gmnog","button-input-container":"number-field-module-8Lvgh","zoom-in-text":"number-field-module-OlEoa"};
355
369
 
356
370
  /**
357
371
  * This component is used to create a number field.
358
372
  * This field can also grow when a user types in text.
359
373
  */
360
374
  function NumberField({ autoFocus, autoGrow, defaultValue, formatOptions = { style: 'decimal', useGrouping: false }, isDisabled, isInvalid, isReadOnly, isRequired, label, maxLength, maxValue, minValue, name, onChange, onInput, onKeyUp, placeholder, showLabel = false, size = 'lg', value, withButtons, }) {
361
- return (jsxs(NumberField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles$p.field, styles$p[size]), defaultValue: defaultValue, formatOptions: formatOptions, isDisabled: isDisabled, isInvalid: isInvalid, isReadOnly: isReadOnly, isRequired: isRequired, maxValue: maxValue, minValue: minValue, name: name, onChange: onChange, onInput: onInput, onKeyUp: e => onKeyUp?.(e), value: value, children: [showLabel && jsx(Label, { isRequired: isRequired, children: label }), jsxs("div", { className: styles$p['button-input-container'], children: [withButtons && (
375
+ const inputRef = useRef(null);
376
+ const onFocusInput = useDebouncedCallback(() => {
377
+ if (!inputRef.current)
378
+ return;
379
+ inputRef.current.focus();
380
+ inputRef.current.selectionStart = inputRef.current.value.length || 0;
381
+ }, 500);
382
+ return (jsxs(NumberField$1, { "aria-label": label, autoFocus: autoFocus, className: clsx(styles$p.field, styles$p[size]), defaultValue: defaultValue, formatOptions: formatOptions, isDisabled: isDisabled, isInvalid: isInvalid, isReadOnly: isReadOnly, isRequired: isRequired, maxValue: maxValue, minValue: minValue, name: name, onChange: onChange, onInput: onInput, onKeyUp: e => onKeyUp?.(e), value: value, children: [showLabel && jsx(Label, { isRequired: isRequired, children: label }), jsxs("div", { className: styles$p['button-input-container'], children: [withButtons && (jsx(Button$1
362
383
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
363
384
  // @ts-expect-error
364
- jsx(Button$1, { onClick: e => e.preventDefault(), slot: "decrement", children: "-" })), jsx(Input, { autoGrow: autoGrow, maxLength: maxLength, placeholder: placeholder, size: size }), withButtons && (
385
+ , {
386
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
387
+ // @ts-expect-error
388
+ onClick: e => e.preventDefault(), onPressEnd: onFocusInput, onPressStart: e => e.target.focus(), slot: "decrement", children: (value || 0) <= 1 ? jsx(TrashOutlinedIcon, {}) : jsx(MinusFilledIcon, {}) })), jsx(Input, { ref: inputRef, autoGrow: autoGrow, maxLength: maxLength, placeholder: placeholder, size: size }), withButtons && (jsx(Button$1
365
389
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
366
390
  // @ts-expect-error
367
- jsx(Button$1, { onClick: e => e.preventDefault(), slot: "increment", children: "+" }))] }), jsx(FieldError, {})] }));
391
+ , {
392
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
393
+ // @ts-expect-error
394
+ onClick: e => e.preventDefault(), onPressEnd: onFocusInput, onPressStart: e => e.target.focus(), slot: "increment", children: jsx(PlusFilledIcon, {}) }))] }), jsx(FieldError, {})] }));
368
395
  }
369
396
 
370
397
  function CartFilledIcon(props) {
@@ -574,8 +601,11 @@ function Image({ alt, className, fallbackSrc = 'https://res.cloudinary.com/dkz9e
574
601
 
575
602
  var styles$j = {"product-card":"product-card-module-pLaiB","favorite-button":"product-card-module-tvEdz","content":"product-card-module-e0kMu","top":"product-card-module-Q0VvF","tag":"product-card-module-HkWBE","title":"product-card-module-CStNi","bottom":"product-card-module-kD2tU","image":"product-card-module-p-zoi","price":"product-card-module-irW0D","add-to-cart-button":"product-card-module-SnCvX"};
576
603
 
577
- function ProductCard({ addToCartButton: AddToCartButton, favoriteButton: FavoriteButton, href, image: { alt, fit, src, title: imageTitle }, onClick, price, sku, tag, title, }) {
578
- return (jsxs(Link, { className: styles$j['product-card'], href: href, onPress: onClick, children: [jsx("div", { className: styles$j.image, children: jsx(Image, { alt: alt, fit: fit, src: src, title: imageTitle }) }), jsx("div", { className: styles$j['favorite-button'], children: FavoriteButton && FavoriteButton }), jsxs("div", { className: styles$j.content, children: [jsxs("div", { className: styles$j.top, children: [jsx("div", { className: styles$j.tag, children: tag && (jsx(Tag, { children: jsx(FormattedMessage, { optional: true, id: tag }) })) }), jsx("h2", { className: styles$j.title, children: title }), jsx(ProductSku, { sku: sku })] }), jsxs("div", { className: styles$j.bottom, children: [jsx("div", { className: styles$j.price, children: jsx(ProductPrice, { current: price.current, includeVat: price.includeVat, original: price.original }) }), jsx("div", { className: styles$j['add-to-cart-button'], children: AddToCartButton })] })] })] }));
604
+ function ProductCard({ addToCartButton: AddToCartButton, favoriteButton: FavoriteButton, href, image: { alt, fit, src, title: imageTitle }, onClick, onPress, price, sku, tag, title, }) {
605
+ return (jsxs(Link, { className: styles$j['product-card'], href: href,
606
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
607
+ // @ts-expect-error
608
+ onClick: onClick, onPress: onPress, children: [jsx("div", { className: styles$j.image, children: jsx(Image, { alt: alt, fit: fit, src: src, title: imageTitle }) }), jsx("div", { className: styles$j['favorite-button'], children: FavoriteButton && FavoriteButton }), jsxs("div", { className: styles$j.content, children: [jsxs("div", { className: styles$j.top, children: [jsx("div", { className: styles$j.tag, children: tag && (jsx(Tag, { children: jsx(FormattedMessage, { optional: true, id: tag }) })) }), jsx("h2", { className: styles$j.title, children: title }), jsx(ProductSku, { sku: sku })] }), jsxs("div", { className: styles$j.bottom, children: [jsx("div", { className: styles$j.price, children: jsx(ProductPrice, { current: price.current, includeVat: price.includeVat, original: price.original }) }), jsx("div", { className: styles$j['add-to-cart-button'], children: AddToCartButton })] })] })] }));
579
609
  }
580
610
 
581
611
  var styles$i = {"category-card":"category-card-module-4NUjH","title":"category-card-module-LEhh3","is-selected":"category-card-module-vJ7vB","image-container":"category-card-module-oNTrK"};
@@ -5634,7 +5664,11 @@ function LeftArrowFilledIcon(props) {
5634
5664
  return (jsx("svg", { height: "13", viewBox: "0 0 13 13", width: "13", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M9.461 11.917c.227 0 .365-.224.245-.396L5.954 6.137a1.098 1.098 0 0 1 .112-1.409l3.032-3.219c.158-.168.025-.426-.22-.426H6.514a.303.303 0 0 0-.22.092L4.04 3.57c-.94.997-1.052 2.412-.28 3.52l3.28 4.706a.297.297 0 0 0 .245.122H9.46z", fill: "currentColor", fillRule: "evenodd" }) }));
5635
5665
  }
5636
5666
 
5637
- var styles$h = {"carousel":"carousel-module-ealh-","swiper":"carousel-module-IftbN","slide":"carousel-module-bUMlb","navigation-button-next":"carousel-module-T7bTr","navigation-button":"carousel-module-kcqEE","is-dragging":"carousel-module-34OWD","navigation-button-prev":"carousel-module-984Rr","navigation-buttons":"carousel-module-k7Z4S","navigation-button-wrapper":"carousel-module-Hi-0z","icon":"carousel-module-p5oAL","top":"carousel-module-nL-O8","center":"carousel-module-5SGYn"};
5667
+ function RightArrowFilledIcon(props) {
5668
+ return (jsx("svg", { height: "13", viewBox: "0 0 13 13", width: "13", xmlns: "http://www.w3.org/2000/svg", ...props, children: jsx("path", { d: "M3.539 11.917c-.227 0-.365-.224-.245-.396l3.752-5.384a1.098 1.098 0 0 0-.112-1.409L3.902 1.509c-.158-.168-.025-.426.22-.426h2.363c.085 0 .165.034.22.092L8.96 3.57c.94.997 1.052 2.412.28 3.52l-3.28 4.706a.297.297 0 0 1-.245.122H3.54z", fill: "currentColor", fillRule: "evenodd" }) }));
5669
+ }
5670
+
5671
+ var styles$h = {"carousel":"carousel-module-ealh-","swiper":"carousel-module-IftbN","slide":"carousel-module-bUMlb","navigation-button-next":"carousel-module-T7bTr","navigation-button":"carousel-module-kcqEE","is-dragging":"carousel-module-34OWD","navigation-button-prev":"carousel-module-984Rr","navigation-buttons":"carousel-module-k7Z4S","navigation-button-wrapper":"carousel-module-Hi-0z","top":"carousel-module-nL-O8","center":"carousel-module-5SGYn"};
5638
5672
 
5639
5673
  function CarouselNavigationButton({ direction, isDisabled = false, }) {
5640
5674
  const swiper = useSwiper();
@@ -5646,7 +5680,7 @@ function CarouselNavigationButton({ direction, isDisabled = false, }) {
5646
5680
  swiper.slidePrev();
5647
5681
  }
5648
5682
  }
5649
- return (jsx(Button$1, { className: styles$h['navigation-button'], isDisabled: isDisabled, onPress: handleNavigation, children: jsx(LeftArrowFilledIcon, { className: styles$h.icon }) }));
5683
+ return (jsx(Button$1, { className: styles$h['navigation-button'], isDisabled: isDisabled, onPress: handleNavigation, children: direction === 'previous' ? (jsx(LeftArrowFilledIcon, {})) : (jsx(RightArrowFilledIcon, {})) }));
5650
5684
  }
5651
5685
 
5652
5686
  function Carousel({ breakpoints, hasNavigation = true, navigationButtonsPosition = 'top', slides, slidesPerView = 'auto', spaceBetween = 8, }) {
@@ -5836,10 +5870,10 @@ function ProductOverviewGrid({ children }) {
5836
5870
  return (jsx("div", { className: styles$9['product-grid'], children: Children.map(children, (child, index) => (jsx("div", { className: styles$9['grid-item'], children: child }, index))) }));
5837
5871
  }
5838
5872
 
5839
- var styles$8 = {"page-layout":"page-layout-module-osQ2n"};
5873
+ var styles$8 = {"page-container":"page-layout-module-sSsgZ","page-layout":"page-layout-module-osQ2n"};
5840
5874
 
5841
5875
  function PageLayout({ children, className, }) {
5842
- return (jsx("div", { className: clsx(styles$8['page-layout'], className), children: children }));
5876
+ return (jsx("div", { className: styles$8['page-container'], children: jsx("div", { className: clsx(styles$8['page-layout'], className), children: children }) }));
5843
5877
  }
5844
5878
 
5845
5879
  var styles$7 = {"heading":"heading-module-pMC65","uppercase":"heading-module-6spgX","italic":"heading-module-XXMDM","xxl":"heading-module-Kn3ZN","xl":"heading-module--hZs-","l":"heading-module-WrJRY","m":"heading-module-hTexc","s":"heading-module-7W29m","xs":"heading-module-SgaLB","xxs":"heading-module-33en7"};
@@ -5965,13 +5999,17 @@ function ChevronRightFilledIcon(props) {
5965
5999
 
5966
6000
  var styles$3 = {"pagination":"pagination-module-k4OgY","page-number-container":"pagination-module-oq89A"};
5967
6001
 
5968
- function Pagination({ currentPage, onChange, totalPages }) {
6002
+ function Pagination({ currentPage, onChange, totalPages, }) {
5969
6003
  return (jsxs("div", { className: styles$3.pagination, children: [jsx(IconButton, { isDisabled: currentPage === 1, onPress: () => onChange(currentPage - 1), children: jsx(ChevronLeftFilledIcon, {}) }), jsxs("div", { className: styles$3['page-number-container'], children: [jsx(NumberField, { autoGrow: true, label: "current-page", maxValue: totalPages, minValue: 1, onChange: onChange, value: currentPage }), jsx(FormattedMessage, { id: "of" }), jsx("div", { children: totalPages })] }), jsx(IconButton, { isDisabled: currentPage >= totalPages, onPress: () => onChange(currentPage + 1), children: jsx(ChevronRightFilledIcon, {}) })] }));
5970
6004
  }
5971
6005
 
5972
- function AlgoliaPagination() {
6006
+ function AlgoliaPagination({ onChange }) {
5973
6007
  const { currentRefinement, nbPages, refine } = usePagination();
5974
- return (jsx(Pagination, { currentPage: currentRefinement + 1, onChange: pageNumber => refine(pageNumber - 1), totalPages: nbPages }));
6008
+ function handlePageChange(pageNumber) {
6009
+ refine(pageNumber - 1);
6010
+ onChange(pageNumber);
6011
+ }
6012
+ return (jsx(Pagination, { currentPage: currentRefinement + 1, onChange: pageNumber => handlePageChange(pageNumber), totalPages: nbPages }));
5975
6013
  }
5976
6014
 
5977
6015
  function AlgoliaSortBy() {
@@ -5994,6 +6032,18 @@ function ConnectedProductCart({ productId, ...props }) {
5994
6032
  return (jsx(ProductCard, { ...props, addToCartButton: jsx(ConnectedAddToCartButton, { productId: productId }) }));
5995
6033
  }
5996
6034
 
6035
+ const useScrollTo = (ref, scrollOptions) => () => {
6036
+ if (!ref.current)
6037
+ return;
6038
+ const rect = ref.current.getBoundingClientRect();
6039
+ const scrollPadding = 12;
6040
+ const scrollY = window.scrollY + rect.top - scrollPadding;
6041
+ window.scrollTo({
6042
+ behavior: 'smooth',
6043
+ top: scrollY,
6044
+ });
6045
+ };
6046
+
5997
6047
  const SidebarContext = createContext({
5998
6048
  isOpen: false,
5999
6049
  toggle: () => { },
@@ -6027,7 +6077,7 @@ const ToggleSidebarButton = () => {
6027
6077
  return (jsx(Button, { color: "secondary", icon: jsx(FilterOutlinedIcon, {}), onPress: toggle, size: "sm", variant: "outline", children: isOpen ? (jsx(FormattedMessage, { id: "Hide filters" })) : (jsx(FormattedMessage, { id: "Show filters" })) }));
6028
6078
  };
6029
6079
 
6030
- var styles$1 = {"product-listing":"product-listing-page-module-dmIHF","header":"product-listing-page-module-Oz76Z","action-bar":"product-listing-page-module-XxGrr","count":"product-listing-page-module-zx79v","categories":"product-listing-page-module-R4aOl","product-grid-container":"product-listing-page-module-ICkKg","product-grid":"product-listing-page-module-LHE7z","pagination":"product-listing-page-module-xsRaj"};
6080
+ var styles$1 = {"product-listing":"product-listing-page-module-dmIHF","header":"product-listing-page-module-Oz76Z","action-bar":"product-listing-page-module-XxGrr","sort":"product-listing-page-module-aQzHr","count":"product-listing-page-module-zx79v","categories":"product-listing-page-module-R4aOl","product-grid-container":"product-listing-page-module-ICkKg","product-grid":"product-listing-page-module-LHE7z","pagination":"product-listing-page-module-xsRaj"};
6031
6081
 
6032
6082
  const categories = Array.from({ length: 20 }, () => ({
6033
6083
  href: '#',
@@ -6046,31 +6096,33 @@ function ProductListingPage({ category, isLoading = false, }) {
6046
6096
  const { toggle } = useSidebar();
6047
6097
  const { hits: productHits } = useHits();
6048
6098
  const baseUrl = location.href.split('?')[0];
6049
- return (jsxs(Page, { className: styles$1['product-listing'], title: category.slice().pop(), children: [categories?.length > 0 && (jsx("section", { className: styles$1.categories, children: jsx(CategoryCarousel, { categories: categories }) })), jsxs("section", { className: styles$1['action-bar'], children: [jsx(ToggleSidebarButton, {}), jsx("span", { className: styles$1.count, children: jsx(AlgoliaResultsCount, {}) }), jsx(AlgoliaSortBy, {})] }), jsx("section", { children: isLoading ? (jsx("p", { children: "Loading..." })) : (jsxs("div", { className: styles$1['product-grid-container'], children: [jsx(Sidebar, { children: jsx(AlgoliaFilterPanel, { onShowProducts: toggle }) }), jsxs("div", { className: styles$1['product-grid'], children: [jsx(ProductOverviewGrid, { children: productHits.map(productHit => (jsx(ConnectedProductCart, { href: `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}${productHit.id}-${productHit.name.replace(/ /g, '-')}`, image: {
6050
- alt: productHit.name,
6051
- fit: 'contain',
6052
- sizes: { lg: 288, md: 204, sm: 122 },
6053
- src: productHit.images?.find(image => image.quality === 'large')?.url || '',
6054
- srcSet: [
6055
- {
6056
- url: productHit.images?.find(image => image.quality === 'small')?.url || '',
6057
- width: 122,
6058
- },
6059
- {
6060
- url: productHit.images?.find(image => image.quality === 'medium')?.url || '',
6061
- width: 204,
6062
- },
6063
- {
6064
- url: productHit.images?.find(image => image.quality === 'large')?.url || '',
6065
- width: 288,
6066
- },
6067
- ],
6068
- title: productHit.name,
6069
- }, price: {
6070
- current: productHit.discountedPrice,
6071
- includeVat: false,
6072
- original: productHit.price,
6073
- }, productId: productHit.id, sku: productHit.ean, tag: "new", title: productHit.name }, productHit.id))) }), jsx("div", { className: styles$1.pagination, children: jsx(AlgoliaPagination, {}) })] })] })) })] }));
6099
+ const productGrid = useRef(null);
6100
+ const scrollToTopOfProductGrid = useScrollTo(productGrid);
6101
+ return (jsxs(Page, { className: styles$1['product-listing'], title: category.slice().pop(), children: [categories?.length > 0 && (jsx("section", { className: styles$1.categories, children: jsx(CategoryCarousel, { categories: categories }) })), jsxs("div", { ref: productGrid, children: [jsxs("section", { className: styles$1['action-bar'], children: [jsx("div", { children: jsx(ToggleSidebarButton, {}) }), jsx("span", { className: styles$1.count, children: jsx(AlgoliaResultsCount, {}) }), jsx("div", { className: styles$1.sort, children: jsx(AlgoliaSortBy, {}) })] }), jsx("section", { children: isLoading ? (jsx("p", { children: "Loading..." })) : (jsxs("div", { className: styles$1['product-grid-container'], children: [jsx(Sidebar, { children: jsx(AlgoliaFilterPanel, { onShowProducts: toggle }) }), jsxs("div", { className: styles$1['product-grid'], children: [jsx(ProductOverviewGrid, { children: productHits.map(productHit => (jsx(ConnectedProductCart, { href: `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}${productHit.id}-${productHit.name.replace(/ /g, '-')}`, image: {
6102
+ alt: productHit.name,
6103
+ fit: 'contain',
6104
+ sizes: { lg: 288, md: 204, sm: 122 },
6105
+ src: productHit.images?.find(image => image.quality === 'large')?.url || '',
6106
+ srcSet: [
6107
+ {
6108
+ url: productHit.images?.find(image => image.quality === 'small')?.url || '',
6109
+ width: 122,
6110
+ },
6111
+ {
6112
+ url: productHit.images?.find(image => image.quality === 'medium')?.url || '',
6113
+ width: 204,
6114
+ },
6115
+ {
6116
+ url: productHit.images?.find(image => image.quality === 'large')?.url || '',
6117
+ width: 288,
6118
+ },
6119
+ ],
6120
+ title: productHit.name,
6121
+ }, price: {
6122
+ current: productHit.discountedPrice,
6123
+ includeVat: false,
6124
+ original: productHit.price,
6125
+ }, productId: productHit.id, sku: productHit.ean, tag: "new", title: productHit.name }, productHit.id))) }), jsx("div", { className: styles$1.pagination, children: jsx(AlgoliaPagination, { onChange: scrollToTopOfProductGrid }) })] })] })) })] })] }));
6074
6126
  }
6075
6127
 
6076
6128
  var styles = {"sidebar-container":"sidebar-provider-module-rjeCL","transition":"sidebar-provider-module-C0cKR","sidebar-background":"sidebar-provider-module-VRgS9","is-open":"sidebar-provider-module-lxq2-"};
@@ -6112,6 +6164,16 @@ function SidebarProvider({ children }) {
6112
6164
  }), onClick: closeTransitions }), children] }) }));
6113
6165
  }
6114
6166
 
6167
+ const createSonicSearchClient = (url) => ({
6168
+ async search(requests) {
6169
+ return fetch(url, {
6170
+ body: JSON.stringify({ requests }),
6171
+ headers: { 'Content-Type': 'application/json' },
6172
+ method: 'post',
6173
+ }).then(res => res.json());
6174
+ },
6175
+ });
6176
+
6115
6177
  const queryStringRouting = {
6116
6178
  router: history({
6117
6179
  cleanUrlOnDispose: true,
@@ -6177,7 +6239,7 @@ function AlgoliaProvider({ category, children, offlineSearchClient, online: _onl
6177
6239
  }, children: jsxs(InstantSearch, { future: {
6178
6240
  persistHierarchicalRootCount: true,
6179
6241
  preserveSharedStateOnUnmount: true,
6180
- }, indexName: "dev_sonic_products_en", routing: routing, searchClient: online ? searchClient : offlineSearchClient || searchClient, children: [jsx(Configure, { analytics: false, filters: category && category.length
6242
+ }, indexName: "dev_sonic_products_en", routing: routing, searchClient: online ? searchClient : offlineSearchClient || searchClient, children: [jsx(Configure, { analytics: false, filters: category.length
6181
6243
  ? `categoryPages: '${category.join(' > ')}'`
6182
6244
  : undefined, hitsPerPage: 9, maxValuesPerFacet: 100, ruleContexts: ['storefront'] }), children] }) }));
6183
6245
  }
@@ -6185,4 +6247,4 @@ function useAlgolia() {
6185
6247
  return useContext(AlgoliaContext);
6186
6248
  }
6187
6249
 
6188
- export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, BreadcrumbProvider, Button, CartFilledIcon, CartOutlinedIcon, CartProvider, CategoryCarousel, Checkbox, ColorCheckbox, ConnectedAddToCartButton, ConnectedBreadcrumb, DehashedOutlinedIcon, FavoriteButton, FavoriteFilledIcon, FavoriteOutlinedIcon, FavoriteProvider, FormattedMessage, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, Image, IntlProvider, LinkButton, MultiSelect, NumberField, Page, PageLayout, ProductCard, ProductListingPage, ProductOverviewGrid, ProductPrice, ProductSku, RightArrowFilledIcon, Select, ShowAll, Sidebar, SidebarProvider, TextField, useAlgolia, useBreadcrumb, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFavorite, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
6250
+ export { Accordion, AddToCartButton, AlgoliaCategories, AlgoliaFilterPanel, AlgoliaFilterSection, AlgoliaMultiSelectFilterSection, AlgoliaPagination, AlgoliaProvider, AlgoliaResultsCount, AlgoliaSortBy, Breadcrumb, BreadcrumbProvider, Button, CartFilledIcon, CartOutlinedIcon, CartProvider, CategoryCarousel, Checkbox, ColorCheckbox, ConnectedAddToCartButton, ConnectedBreadcrumb, DehashedOutlinedIcon, FavoriteButton, FavoriteFilledIcon, FavoriteOutlinedIcon, FavoriteProvider, FormattedMessage, GlobalStateProvider, GlobalStateProviderContext, HashedOutlinedIcon, IconButton, Image, IntlProvider, LeftArrowFilledIcon, LinkButton, MultiSelect, NumberField, Page, PageLayout, ProductCard, ProductListingPage, ProductOverviewGrid, ProductPrice, ProductSku, RightArrowFilledIcon, Select, ShowAll, Sidebar, SidebarProvider, TextAlignedArrowIcon, TextField, createSonicSearchClient, useAlgolia, useBreadcrumb, useBreakpoint, useCart, useDebouncedCallback, useDisclosure, useFavorite, useFormattedMessage, useGlobalState, useProductCartLine, useScrollLock };
@@ -1 +1 @@
1
- export type TranslationId = 'Chosen filters' | 'Clear filters' | 'Excl. VAT' | 'Hide filters' | 'Incl. VAT' | 'Show' | 'Show all' | 'Show filters' | 'Show less' | 'Sort' | 'articles' | 'article' | 'of';
1
+ export type TranslationId = 'Chosen filters' | 'Clear' | 'Clear filters' | 'Excl. VAT' | 'Hide filters' | 'Incl. VAT' | 'Show' | 'Show all' | 'Show filters' | 'Show less' | 'Sort' | 'Submit' | 'articles' | 'article' | 'of';
@@ -3,6 +3,7 @@ import { StoryObj } from '@storybook/react';
3
3
  import { ProductListingPage } from './product-listing-page';
4
4
  declare const meta: {
5
5
  args: {
6
+ BFF: true;
6
7
  category: string[];
7
8
  isLoading: false;
8
9
  online: false;
@@ -15,6 +16,7 @@ declare const meta: {
15
16
  };
16
17
  export default meta;
17
18
  type StoryProps = ComponentProps<typeof ProductListingPage> & {
19
+ BFF: boolean;
18
20
  online: boolean;
19
21
  };
20
22
  type Story = StoryObj<StoryProps>;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare function ClearIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from 'react';
2
+ import { SearchClient } from 'algoliasearch/lite';
3
+ import { Autocomplete } from './types';
4
+ /**
5
+ * Global search using algolia autocomplete with a custom renderer
6
+ * https://www.algolia.com/doc/ui-libraries/autocomplete/guides/creating-a-renderer/
7
+ *
8
+ * Highly influenced by the two column layout sandbox which
9
+ * uses the autocomplete widgets
10
+ * https://codesandbox.io/p/sandbox/github/algolia/autocomplete/tree/next/examples/two-column-layout
11
+ */
12
+ export declare function GlobalSearch(props: {
13
+ searchClient: SearchClient;
14
+ }): import("react/jsx-runtime").JSX.Element;
15
+ export declare function SearchForm(): import("react/jsx-runtime").JSX.Element;
16
+ export declare function GlobalSearchProvider({ children, searchClient, }: {
17
+ children?: ReactNode | ((autocomplete: Autocomplete) => ReactNode);
18
+ searchClient: SearchClient;
19
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import { ComponentProps } from 'react';
2
+ import { StoryObj } from '@storybook/react';
3
+ import { GlobalSearch } from './global-search';
4
+ declare const meta: {
5
+ args: {
6
+ searchClient: import("algoliasearch/lite").SearchClient;
7
+ };
8
+ component: typeof GlobalSearch;
9
+ title: string;
10
+ };
11
+ export default meta;
12
+ type StoryProps = ComponentProps<typeof GlobalSearch>;
13
+ type Story = StoryObj<StoryProps>;
14
+ export declare const Default: Story;
@@ -0,0 +1,21 @@
1
+ import { HighlightedHit } from '@algolia/autocomplete-preset-algolia';
2
+ type HighlightHitParams<THit> = {
3
+ /**
4
+ * The attribute to retrieve the highlighted parts from.
5
+ *
6
+ * You can use the array syntax to reference nested attributes.
7
+ */
8
+ attribute: keyof THit | string[];
9
+ /**
10
+ * The Algolia hit whose attribute to retrieve the highlighted parts from.
11
+ */
12
+ hit: THit;
13
+ /**
14
+ * The tag name to use for highlighted parts.
15
+ *
16
+ * @default "mark"
17
+ */
18
+ tagName?: string;
19
+ };
20
+ export declare function Highlight<THit extends HighlightedHit<unknown>>({ attribute, hit, tagName, }: HighlightHitParams<THit>): JSX.Element;
21
+ export {};
@@ -0,0 +1,10 @@
1
+ import { AutocompletePlugin } from '@algolia/autocomplete-core';
2
+ import { Hit } from '@algolia/client-search';
3
+ import { SearchClient } from 'algoliasearch/lite';
4
+ export type CategoryHit = Hit<{
5
+ listCategories: string[];
6
+ }>;
7
+ export declare const categoriesPlugin: ({ productsIndexName, searchClient, }: {
8
+ productsIndexName: string;
9
+ searchClient: SearchClient;
10
+ }) => AutocompletePlugin<CategoryHit, unknown>;
@@ -0,0 +1,11 @@
1
+ import { AutocompletePlugin } from '@algolia/autocomplete-core';
2
+ import { Hit } from '@algolia/client-search';
3
+ import { SearchClient } from 'algoliasearch/lite';
4
+ export type PopularCategoryHit = Hit<{
5
+ count: number;
6
+ label: string;
7
+ }>;
8
+ export declare const popularCategoriesPlugin: ({ productsIndexName, searchClient, }: {
9
+ productsIndexName: string;
10
+ searchClient: SearchClient;
11
+ }) => AutocompletePlugin<PopularCategoryHit, unknown>;
@@ -0,0 +1,12 @@
1
+ import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';
2
+ import { Hit } from '@algolia/client-search';
3
+ import { SearchClient } from 'algoliasearch/lite';
4
+ export type PopularSearchHit = Hit<{
5
+ nb_words: number;
6
+ popularity: number;
7
+ query: string;
8
+ }>;
9
+ export declare const popularSearchesPlugin: ({ searchClient, suggestionsIndexName, }: {
10
+ searchClient: SearchClient;
11
+ suggestionsIndexName: string;
12
+ }) => ReturnType<typeof createQuerySuggestionsPlugin>;
@@ -0,0 +1,23 @@
1
+ import { AutocompletePlugin } from '@algolia/autocomplete-core';
2
+ import { Hit } from '@algolia/client-search';
3
+ import { SearchClient } from 'algoliasearch/lite';
4
+ export type ProductHit = Hit<{
5
+ brand: string;
6
+ categories: string[];
7
+ discountedPrice: number;
8
+ ean: string;
9
+ id: string;
10
+ image: string;
11
+ images: {
12
+ quality: string;
13
+ url: string;
14
+ }[];
15
+ name: string;
16
+ objectID: string;
17
+ price: number;
18
+ slug: string;
19
+ }>;
20
+ export declare const productsPlugin: ({ productsIndexName, searchClient, }: {
21
+ productsIndexName: string;
22
+ searchClient: SearchClient;
23
+ }) => AutocompletePlugin<ProductHit, unknown>;
@@ -0,0 +1,12 @@
1
+ import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions';
2
+ import { Hit } from '@algolia/client-search';
3
+ import { SearchClient } from 'algoliasearch/lite';
4
+ export type QuerySuggestionHit = Hit<{
5
+ nb_words: number;
6
+ popularity: number;
7
+ query: string;
8
+ }>;
9
+ export declare const querySuggestionsPlugin: ({ searchClient, suggestionsIndexName, }: {
10
+ searchClient: SearchClient;
11
+ suggestionsIndexName: string;
12
+ }) => ReturnType<typeof createQuerySuggestionsPlugin>;
@@ -0,0 +1,13 @@
1
+ import { AutocompletePlugin } from '@algolia/autocomplete-core';
2
+ import { Hit } from '@algolia/client-search';
3
+ import { SearchClient } from 'algoliasearch/lite';
4
+ export type QuickAccessHit = Hit<{
5
+ id: number;
6
+ image: string;
7
+ title: string;
8
+ url: string;
9
+ }>;
10
+ export declare const quickAccessPlugin: ({ productsIndexName, searchClient, }: {
11
+ productsIndexName: string;
12
+ searchClient: SearchClient;
13
+ }) => AutocompletePlugin<QuickAccessHit, unknown>;
@@ -0,0 +1,7 @@
1
+ import { createLocalStorageRecentSearchesPlugin } from '@algolia/autocomplete-plugin-recent-searches';
2
+ import { Hit } from '@algolia/client-search';
3
+ export type RecentSearchHit = Hit<{
4
+ id: string;
5
+ label: string;
6
+ }>;
7
+ export declare const recentSearchesPlugin: ReturnType<typeof createLocalStorageRecentSearchesPlugin>;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare function SearchIcon(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,23 @@
1
+ /// <reference types="react" />
2
+ import { AutocompleteApi, AutocompleteState as _AutocompleteState } from '@algolia/autocomplete-core';
3
+ import { SearchClient } from 'algoliasearch/lite';
4
+ import { CategoryHit } from './plugins/categories-plugin';
5
+ import { PopularCategoryHit } from './plugins/popular-categories-plugin';
6
+ import { PopularSearchHit } from './plugins/popular-searches-plugin';
7
+ import { ProductHit } from './plugins/products-plugin';
8
+ import { QuerySuggestionHit } from './plugins/query-suggestions-plugin';
9
+ import { QuickAccessHit } from './plugins/quick-access-plugin';
10
+ import { RecentSearchHit } from './plugins/recent-searches-plugin';
11
+ export type AutocompleteItem = ProductHit | QuerySuggestionHit | PopularCategoryHit | QuickAccessHit | RecentSearchHit | CategoryHit | PopularSearchHit;
12
+ export type Autocomplete = AutocompleteApi<AutocompleteItem, React.BaseSyntheticEvent, React.MouseEvent, React.KeyboardEvent>;
13
+ export type AutocompleteState = _AutocompleteState<AutocompleteItem>;
14
+ export type GlobalSearchContextValue = {
15
+ autocomplete: Autocomplete;
16
+ formRef: React.RefObject<HTMLFormElement>;
17
+ inputRef: React.RefObject<HTMLInputElement>;
18
+ panelRef: React.RefObject<HTMLDivElement>;
19
+ productsIndexName: string;
20
+ productsQuerySuggestionsIndexName: string;
21
+ searchClient: SearchClient;
22
+ state: AutocompleteState;
23
+ };
@@ -0,0 +1,5 @@
1
+ import { Autocomplete } from 'search/global-search/types';
2
+ export interface SearchInputProps {
3
+ autocomplete?: Autocomplete;
4
+ }
5
+ export declare function SearchInput({ autocomplete }: SearchInputProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { SearchInput } from './search-input';
3
+ declare const meta: Meta<typeof SearchInput>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof meta>;
6
+ export declare const Default: Story;
@@ -0,0 +1,7 @@
1
+ import { RefObject } from 'react';
2
+ interface ScrollOptions {
3
+ behavior?: ScrollBehavior;
4
+ scrollPadding?: number;
5
+ }
6
+ export declare const useScrollTo: (ref: RefObject<HTMLElement>, scrollOptions?: ScrollOptions) => () => void;
7
+ export {};
package/dist/styles.css CHANGED
@@ -131,6 +131,7 @@
131
131
 
132
132
  /* Neutrals */
133
133
  --color-gray-50: #fbfbfb;
134
+ --color-gray-75: #f6f6f6;
134
135
  --color-gray-100: #ededed;
135
136
  --color-gray-500: #bcbcbc;
136
137
  --color-gray-900: #6f6f6f;
@@ -254,6 +255,7 @@
254
255
  font-weight: var(--font-weight-bold);
255
256
  }
256
257
  .breadcrumb-module-CQGse .breadcrumb-module-hxhDY:not(:last-of-type)::after {
258
+ color: var(--color-brand-medium-gray);
257
259
  content: '/';
258
260
  margin-inline: 10px;
259
261
  }
@@ -618,18 +620,61 @@
618
620
  justify-content: space-between;
619
621
  }
620
622
 
623
+ .number-field-module-gmnog .number-field-module-8Lvgh input {
624
+ min-width: var(--space-36);
625
+ transition: font-size 0.5s ease;
626
+ }
627
+
628
+ .number-field-module-gmnog .number-field-module-8Lvgh:has(button[data-pressed]) input {
629
+ animation: number-field-module-OlEoa 100ms infinite;
630
+ }
631
+
621
632
  .number-field-module-gmnog .number-field-module-8Lvgh button {
622
633
  all: unset;
634
+ position: relative;
635
+ display: flex;
623
636
  width: var(--space-32);
637
+ align-items: center;
638
+ justify-content: center;
624
639
  cursor: pointer;
625
- font-size: var(--font-size-24);
640
+ font-size: var(--font-size-32);
641
+ -webkit-tap-highlight-color: transparent;
626
642
  text-align: center;
643
+ -webkit-user-select: none;
644
+ -moz-user-select: none;
645
+ user-select: none;
627
646
  }
628
647
 
648
+ .number-field-module-gmnog .number-field-module-8Lvgh button[data-pressed]::before {
649
+ position: absolute;
650
+ z-index: -1;
651
+ top: 50%;
652
+ left: 50%;
653
+ display: block;
654
+ width: 24px;
655
+ height: 24px;
656
+ border-radius: 50%;
657
+ margin-top: -12px;
658
+ margin-left: -12px;
659
+ background-color: var(--color-brand-light-gray);
660
+ content: '';
661
+ }
662
+
629
663
  .number-field-module-gmnog span:empty {
630
664
  display: none;
631
665
  }
632
666
 
667
+ @keyframes number-field-module-OlEoa {
668
+ 0%,
669
+ 100% {
670
+ transform: scale(1);
671
+ }
672
+
673
+ 50% {
674
+ transform: scale(1.3);
675
+ }
676
+ }
677
+
633
678
  .add-to-cart-button-module-AWFvQ {
634
679
  display: inline-flex;
635
680
  flex-direction: row;
@@ -1293,9 +1338,6 @@
1293
1338
  right: 0;
1294
1339
  transform: translate(50%, 0);
1295
1340
  }
1296
- .carousel-module-ealh- .carousel-module-k7Z4S .carousel-module-Hi-0z.carousel-module-T7bTr .carousel-module-p5oAL {
1297
- transform: rotate(180deg);
1298
- }
1299
1341
  .carousel-module-ealh- .carousel-module-k7Z4S .carousel-module-Hi-0z .carousel-module-kcqEE {
1300
1342
  width: 44px;
1301
1343
  height: 44px;
@@ -1311,8 +1353,8 @@
1311
1353
  background-color: var(--color-brand-light-gray);
1312
1354
  }
1313
1355
  .carousel-module-ealh- .carousel-module-k7Z4S .carousel-module-Hi-0z .carousel-module-kcqEE[data-disabled] {
1356
+ color: #bcbcbc66;
1314
1357
  cursor: default;
1315
- opacity: 0.4;
1316
1358
  }
1317
1359
  .carousel-module-ealh- .carousel-module-k7Z4S.carousel-module-nL-O8 .carousel-module-Hi-0z {
1318
1360
  top: var(--space-24);
@@ -1625,8 +1667,8 @@
1625
1667
 
1626
1668
  all: unset;
1627
1669
  position: relative;
1628
- display: grid;
1629
- width: 100%;
1670
+ display: inline-flex;
1671
+ box-sizing: border-box;
1630
1672
  gap: var(--space-4);
1631
1673
  }
1632
1674
 
@@ -1867,26 +1909,34 @@
1867
1909
  }
1868
1910
  }
1869
1911
 
1870
- .page-layout-module-osQ2n {
1871
- --page-layout-padding: 1rem;
1872
-
1873
- position: relative;
1874
- box-sizing: border-box;
1875
- padding: var(--page-layout-padding);
1876
- padding-bottom: var(--space-64);
1912
+ .page-layout-module-sSsgZ {
1913
+ overflow: hidden;
1877
1914
  }
1878
1915
 
1879
- @media (width >= 768px) {.page-layout-module-osQ2n {
1880
- max-width: calc(806px + (2 * var(--page-layout-padding)));
1881
- margin: 0 auto
1882
- }
1916
+ .page-layout-module-sSsgZ .page-layout-module-osQ2n {
1917
+ --page-layout-padding: 10px;
1918
+
1919
+ position: relative;
1920
+ box-sizing: border-box;
1921
+ padding: var(--page-layout-padding);
1922
+ padding-bottom: var(--space-64);
1883
1923
  }
1884
1924
 
1885
- @media (width >= 1440px) {.page-layout-module-osQ2n {
1886
- max-width: calc(1222px + (2 * var(--page-layout-padding)));
1887
- padding-bottom: var(--space-96)
1888
- }
1925
+ @media (width >= 768px) {
1926
+
1927
+ .page-layout-module-sSsgZ .page-layout-module-osQ2n {
1928
+ max-width: calc(806px + (2 * var(--page-layout-padding)));
1929
+ margin: 0 auto
1930
+ }
1931
+ }
1932
+
1933
+ @media (width >= 1440px) {
1934
+
1935
+ .page-layout-module-sSsgZ .page-layout-module-osQ2n {
1936
+ max-width: calc(1222px + (2 * var(--page-layout-padding)));
1937
+ padding-bottom: var(--space-96)
1889
1938
  }
1939
+ }
1890
1940
 
1891
1941
  .heading-module-pMC65 {
1892
1942
  padding: 0;
@@ -2142,11 +2192,16 @@
2142
2192
  margin-bottom: 44px;
2143
2193
  }
2144
2194
  .product-listing-page-module-dmIHF .product-listing-page-module-XxGrr {
2145
- display: grid;
2195
+ display: flex;
2196
+ flex-wrap: wrap;
2146
2197
  align-items: center;
2198
+ justify-content: space-between;
2147
2199
  margin-bottom: var(--space-24);
2148
- grid-template-columns: auto 1fr auto;
2149
2200
  }
2201
+ .product-listing-page-module-dmIHF .product-listing-page-module-XxGrr .product-listing-page-module-aQzHr {
2202
+ display: flex;
2203
+ justify-content: flex-end;
2204
+ }
2150
2205
  .product-listing-page-module-dmIHF .product-listing-page-module-XxGrr .product-listing-page-module-zx79v {
2151
2206
  margin: auto;
2152
2207
  }
@@ -2166,6 +2221,11 @@
2166
2221
  grid-column: span 2;
2167
2222
  }
2168
2223
  @media (width >= 1440px) {
2224
+ .product-listing-page-module-dmIHF .product-listing-page-module-XxGrr {
2225
+ display: grid;
2226
+ grid-template-columns: repeat(3, 1fr);
2227
+ }
2228
+
2169
2229
  .product-listing-page-module-dmIHF .product-listing-page-module-ICkKg {
2170
2230
  grid-template-columns: auto 1fr;
2171
2231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonic-equipment/ui",
3
- "version": "0.0.26",
3
+ "version": "0.0.27",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "engines": {
@@ -31,16 +31,16 @@
31
31
  "start": "http-server ./storybook-static",
32
32
  "stylelint": "stylelint --config .stylelintrc.cjs \"src/**/*.css\"",
33
33
  "stylelint:fix": "stylelint --config .stylelintrc.cjs \"src/**/*.css\" --formatter verbose --fix",
34
- "test:all": "npx concurrently -g --names \"TSC,ESLINT,STYLELINT\" -c auto --kill-others-on-fail \"pnpm test:types\" \"pnpm lint\" \"pnpm stylelint\"",
34
+ "test:all": "npx concurrently -g --names \"TSC,ESLINT,STYLELINT\" -c auto --kill-others-on-fail \"npm run test:types\" \"npm run lint\" \"npm run stylelint\"",
35
35
  "test:types": "tsc --noEmit --pretty false",
36
36
  "update-packages": "npx npm-check-updates -u"
37
37
  },
38
38
  "peerDependencies": {
39
- "react": "^18",
40
- "react-dom": "^18",
41
- "qs": "^6",
42
39
  "algoliasearch": "^4",
43
40
  "instantsearch.js": "^4",
41
+ "qs": "^6",
42
+ "react": "^18",
43
+ "react-dom": "^18",
44
44
  "react-instantsearch": "^7",
45
45
  "react-instantsearch-core": "^7"
46
46
  },
@@ -108,10 +108,14 @@
108
108
  "vite-tsconfig-paths": "^4.3.2"
109
109
  },
110
110
  "dependencies": {
111
+ "@algolia/autocomplete-core": "^1.17.2",
112
+ "@algolia/autocomplete-plugin-query-suggestions": "^1.17.2",
113
+ "@algolia/autocomplete-plugin-recent-searches": "^1.17.2",
114
+ "@algolia/autocomplete-preset-algolia": "^1.17.2",
111
115
  "@algolia/client-search": "^4.23.3",
112
116
  "algoliasearch": "^4.23.3",
113
- "instantsearch.js": "^4.69.0",
114
117
  "clsx": "^2.1.1",
118
+ "instantsearch.js": "^4.69.0",
115
119
  "react-aria-components": "^1.2.1",
116
120
  "react-instantsearch": "^7.9.0",
117
121
  "swiper": "^11.1.3"