@asante-org/leybold-design-system 1.2.2 → 1.3.1

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 (2) hide show
  1. package/dist/index.js +74 -78
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,11 +1,9 @@
1
- 'use strict';
2
-
3
- var React = require('react');
4
- var reactFontawesome = require('@fortawesome/react-fontawesome');
5
- var freeSolidSvgIcons = require('@fortawesome/free-solid-svg-icons');
6
- var freeBrandsSvgIcons = require('@fortawesome/free-brands-svg-icons');
7
- var proSolidSvgIcons = require('@fortawesome/pro-solid-svg-icons');
8
- var edwardsvacuumDesignSystem = require('@asante-org/edwardsvacuum-design-system');
1
+ import React, { useMemo, useState, useCallback, useRef, useEffect } from 'react';
2
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
3
+ import { faArrowLeft, faArrowLeftLong, faArrowRight, faArrowRightLong, faChevronRight, faChevronLeft, faArrowUpRightFromSquare, faGlobe, faXmark as faXmark$1 } from '@fortawesome/free-solid-svg-icons';
4
+ import { faInstagram, faYoutube, faLinkedinIn, faXTwitter, faFacebookF } from '@fortawesome/free-brands-svg-icons';
5
+ import { faChevronRight as faChevronRight$1, faArrowUpRightFromSquare as faArrowUpRightFromSquare$1 } from '@fortawesome/pro-solid-svg-icons';
6
+ import { ProductDetailsCard, AlgoliaDynamicSearchRaw, QrForm } from '@asante-org/edwardsvacuum-design-system';
9
7
 
10
8
  function _extends() {
11
9
  return _extends = Object.assign ? Object.assign.bind() : function (n) {
@@ -112,20 +110,20 @@ var classNames = /*@__PURE__*/getDefaultExportFromCjs(classnamesExports);
112
110
  const getIcon = icon => {
113
111
  switch (icon) {
114
112
  case "arrow-right":
115
- return /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
116
- icon: freeSolidSvgIcons.faArrowRight
113
+ return /*#__PURE__*/React.createElement(FontAwesomeIcon, {
114
+ icon: faArrowRight
117
115
  });
118
116
  case "external":
119
- return /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
120
- icon: freeSolidSvgIcons.faArrowUpRightFromSquare
117
+ return /*#__PURE__*/React.createElement(FontAwesomeIcon, {
118
+ icon: faArrowUpRightFromSquare
121
119
  });
122
120
  case "chevron-left":
123
- return /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
124
- icon: freeSolidSvgIcons.faChevronLeft
121
+ return /*#__PURE__*/React.createElement(FontAwesomeIcon, {
122
+ icon: faChevronLeft
125
123
  });
126
124
  case "chevron-right":
127
- return /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
128
- icon: freeSolidSvgIcons.faChevronRight
125
+ return /*#__PURE__*/React.createElement(FontAwesomeIcon, {
126
+ icon: faChevronRight
129
127
  });
130
128
  default:
131
129
  return null;
@@ -209,19 +207,19 @@ const Button = ({
209
207
  "data-force-state": props['data-force-state']
210
208
  }, props), !isIconOnly && children, isCarouselLeft && /*#__PURE__*/React.createElement("span", {
211
209
  className: iconClasses
212
- }, /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
213
- icon: freeSolidSvgIcons.faArrowLeft,
210
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
211
+ icon: faArrowLeft,
214
212
  className: styles$k.button__icon__default
215
- }), /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
216
- icon: freeSolidSvgIcons.faArrowLeftLong,
213
+ }), /*#__PURE__*/React.createElement(FontAwesomeIcon, {
214
+ icon: faArrowLeftLong,
217
215
  className: styles$k.button__icon__hover
218
216
  })), isCarouselRight && /*#__PURE__*/React.createElement("span", {
219
217
  className: iconClasses
220
- }, /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
221
- icon: freeSolidSvgIcons.faArrowRight,
218
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
219
+ icon: faArrowRight,
222
220
  className: styles$k.button__icon__default
223
- }), /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
224
- icon: freeSolidSvgIcons.faArrowRightLong,
221
+ }), /*#__PURE__*/React.createElement(FontAwesomeIcon, {
222
+ icon: faArrowRightLong,
225
223
  className: styles$k.button__icon__hover
226
224
  })), !isIconOnly && iconElement && /*#__PURE__*/React.createElement("span", {
227
225
  className: iconClasses
@@ -288,13 +286,13 @@ const SocialIconComponent = ({
288
286
  platform
289
287
  }) => {
290
288
  const iconMap = {
291
- facebook: freeBrandsSvgIcons.faFacebookF,
292
- x: freeBrandsSvgIcons.faXTwitter,
293
- linkedin: freeBrandsSvgIcons.faLinkedinIn,
294
- youtube: freeBrandsSvgIcons.faYoutube,
295
- instagram: freeBrandsSvgIcons.faInstagram
289
+ facebook: faFacebookF,
290
+ x: faXTwitter,
291
+ linkedin: faLinkedinIn,
292
+ youtube: faYoutube,
293
+ instagram: faInstagram
296
294
  };
297
- return /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
295
+ return /*#__PURE__*/React.createElement(FontAwesomeIcon, {
298
296
  icon: iconMap[platform]
299
297
  });
300
298
  };
@@ -420,8 +418,8 @@ const FooterBottom = ({
420
418
  className: styles$j.footer__countrySelector
421
419
  }, countrySelector.showIcon !== false && /*#__PURE__*/React.createElement("span", {
422
420
  className: styles$j.footer__countrySelectorIcon
423
- }, /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
424
- icon: freeSolidSvgIcons.faGlobe
421
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
422
+ icon: faGlobe
425
423
  })), countrySelector.label));
426
424
  };
427
425
 
@@ -615,8 +613,8 @@ const PaginationButton = ({
615
613
  className: `${styles$i.navButton} ${styles$i[`navButton--${direction}`]} ${disabled ? styles$i.navButtonDisabled : ""} ${className || ""}`,
616
614
  "aria-label": ariaLabel || label,
617
615
  tabIndex: disabled ? -1 : 0
618
- }, /*#__PURE__*/React.createElement("span", null, label), direction === "next" && /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
619
- icon: proSolidSvgIcons.faChevronRight,
616
+ }, /*#__PURE__*/React.createElement("span", null, label), direction === "next" && /*#__PURE__*/React.createElement(FontAwesomeIcon, {
617
+ icon: faChevronRight$1,
620
618
  className: styles$i.navIcon,
621
619
  "aria-hidden": "true"
622
620
  })));
@@ -695,7 +693,7 @@ const Pagination = ({
695
693
  className,
696
694
  ariaLabel = "Pagination"
697
695
  }) => {
698
- const pageNumbers = React.useMemo(() => generatePageNumbers(currentPage, totalPages, maxVisiblePages), [currentPage, totalPages, maxVisiblePages]);
696
+ const pageNumbers = useMemo(() => generatePageNumbers(currentPage, totalPages, maxVisiblePages), [currentPage, totalPages, maxVisiblePages]);
699
697
  const handlePageChange = page => {
700
698
  if (page >= 1 && page <= totalPages && page !== currentPage) {
701
699
  onPageChange(page);
@@ -769,15 +767,15 @@ const Image = ({
769
767
  srcSet,
770
768
  sizes
771
769
  }) => {
772
- const [isLoading, setIsLoading] = React.useState(true);
773
- const [hasError, setHasError] = React.useState(false);
774
- const [currentSrc, setCurrentSrc] = React.useState(src);
775
- const handleLoad = React.useCallback(() => {
770
+ const [isLoading, setIsLoading] = useState(true);
771
+ const [hasError, setHasError] = useState(false);
772
+ const [currentSrc, setCurrentSrc] = useState(src);
773
+ const handleLoad = useCallback(() => {
776
774
  setIsLoading(false);
777
775
  setHasError(false);
778
776
  onLoad?.();
779
777
  }, [onLoad]);
780
- const handleError = React.useCallback(() => {
778
+ const handleError = useCallback(() => {
781
779
  setIsLoading(false);
782
780
  setHasError(true);
783
781
 
@@ -919,7 +917,7 @@ const ProductCardHorizontal = ({
919
917
  className: styles$h.productButton,
920
918
  onClick: button.onClick,
921
919
  size: "extra-small"
922
- }, button.label) : /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
920
+ }, button.label) : /*#__PURE__*/React.createElement(FontAwesomeIcon, {
923
921
  icon: faArrowUpRight,
924
922
  className: styles$h.productArrowIcon,
925
923
  "aria-hidden": "true"
@@ -978,7 +976,7 @@ const ProductCardDetails = ({
978
976
  };
979
977
  return /*#__PURE__*/React.createElement("div", {
980
978
  className: styles$f.productDetails
981
- }, /*#__PURE__*/React.createElement(edwardsvacuumDesignSystem.ProductDetailsCard, {
979
+ }, /*#__PURE__*/React.createElement(ProductDetailsCard, {
982
980
  className: `${className}`,
983
981
  title: title,
984
982
  imageUrl: imageUrl,
@@ -1065,7 +1063,7 @@ const AlgoliaDynamicSearchLeybold = props => {
1065
1063
  ProductCard: ProductCardAdapter,
1066
1064
  ProductDetailsCard: ProductCardDetailsAdapter
1067
1065
  };
1068
- return /*#__PURE__*/React.createElement(edwardsvacuumDesignSystem.AlgoliaDynamicSearchRaw, _extends({}, props, {
1066
+ return /*#__PURE__*/React.createElement(AlgoliaDynamicSearchRaw, _extends({}, props, {
1069
1067
  innerComponents: innerComponents
1070
1068
  }));
1071
1069
  };
@@ -1118,7 +1116,7 @@ const QrFormButtonAdapter = ({
1118
1116
  const QrFormLeybold = props => {
1119
1117
  return /*#__PURE__*/React.createElement("div", {
1120
1118
  className: "qr-journey-form-wrapper"
1121
- }, /*#__PURE__*/React.createElement(edwardsvacuumDesignSystem.QrForm, _extends({}, props, {
1119
+ }, /*#__PURE__*/React.createElement(QrForm, _extends({}, props, {
1122
1120
  ButtonComponent: QrFormButtonAdapter
1123
1121
  })));
1124
1122
  };
@@ -1169,9 +1167,9 @@ const SearchModal = ({
1169
1167
  className = '',
1170
1168
  stickyHeaderContent
1171
1169
  }) => {
1172
- const modalRef = React.useRef(null);
1173
- const previouslyFocusedElement = React.useRef(null);
1174
- React.useEffect(() => {
1170
+ const modalRef = useRef(null);
1171
+ const previouslyFocusedElement = useRef(null);
1172
+ useEffect(() => {
1175
1173
  if (isOpen) {
1176
1174
  // Store the previously focused element
1177
1175
  previouslyFocusedElement.current = document.activeElement;
@@ -1196,7 +1194,7 @@ const SearchModal = ({
1196
1194
  document.body.style.overflow = '';
1197
1195
  };
1198
1196
  }, [isOpen]);
1199
- React.useEffect(() => {
1197
+ useEffect(() => {
1200
1198
  const handleEscape = event => {
1201
1199
  if (event.key === 'Escape' && isOpen) {
1202
1200
  onClose();
@@ -1207,7 +1205,7 @@ const SearchModal = ({
1207
1205
  }, [isOpen, onClose]);
1208
1206
 
1209
1207
  // Focus trap implementation
1210
- React.useEffect(() => {
1208
+ useEffect(() => {
1211
1209
  if (!isOpen || !modalRef.current) return;
1212
1210
  const modal = modalRef.current;
1213
1211
  const focusableElements = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
@@ -1620,7 +1618,7 @@ const FilterSearch = ({
1620
1618
  };
1621
1619
  return /*#__PURE__*/React.createElement("div", {
1622
1620
  className: `${styles$7.filterSearch} ${className || ""}`
1623
- }, !value && /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
1621
+ }, !value && /*#__PURE__*/React.createElement(FontAwesomeIcon, {
1624
1622
  icon: faMagnifyingGlass,
1625
1623
  className: styles$7.searchIcon,
1626
1624
  "aria-hidden": "true"
@@ -1636,8 +1634,8 @@ const FilterSearch = ({
1636
1634
  onClick: handleClear,
1637
1635
  className: styles$7.clearButton,
1638
1636
  "aria-label": "Clear search"
1639
- }, /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
1640
- icon: freeSolidSvgIcons.faXmark
1637
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
1638
+ icon: faXmark$1
1641
1639
  })));
1642
1640
  };
1643
1641
 
@@ -1733,10 +1731,10 @@ const FilterAccordion = ({
1733
1731
  variant = 'desktop',
1734
1732
  showCheckbox = true
1735
1733
  }) => {
1736
- const [searchQuery, setSearchQuery] = React.useState("");
1734
+ const [searchQuery, setSearchQuery] = useState("");
1737
1735
 
1738
1736
  // Filter facet values based on search query
1739
- const filteredValues = React.useMemo(() => {
1737
+ const filteredValues = useMemo(() => {
1740
1738
  if (!searchQuery.trim()) {
1741
1739
  return facet.values;
1742
1740
  }
@@ -1861,7 +1859,7 @@ const AppliedFilters = ({
1861
1859
  className
1862
1860
  }) => {
1863
1861
  // Extract all refined (selected) filters
1864
- const appliedFilters = React.useMemo(() => {
1862
+ const appliedFilters = useMemo(() => {
1865
1863
  const filters = [];
1866
1864
  facets.forEach(facet => {
1867
1865
  facet.values.forEach(value => {
@@ -1913,7 +1911,7 @@ const FiltersPanel = ({
1913
1911
  showCheckbox = true
1914
1912
  }) => {
1915
1913
  // Track which accordions are expanded (transient UI state)
1916
- const [expandedAccordions, setExpandedAccordions] = React.useState(() => {
1914
+ const [expandedAccordions, setExpandedAccordions] = useState(() => {
1917
1915
  // Initialize with default expanded facets
1918
1916
  const expanded = new Set();
1919
1917
  facets.forEach(facet => {
@@ -1925,7 +1923,7 @@ const FiltersPanel = ({
1925
1923
  });
1926
1924
 
1927
1925
  // Sync expansion state when facets change (e.g., new facets appear after refetch)
1928
- React.useEffect(() => {
1926
+ useEffect(() => {
1929
1927
  setExpandedAccordions(prev => {
1930
1928
  const next = new Set(prev);
1931
1929
  // Add new facets with defaultExpanded
@@ -1944,7 +1942,7 @@ const FiltersPanel = ({
1944
1942
  return next;
1945
1943
  });
1946
1944
  }, [facets]);
1947
- const handleAccordionToggle = React.useCallback(facetId => {
1945
+ const handleAccordionToggle = useCallback(facetId => {
1948
1946
  setExpandedAccordions(prev => {
1949
1947
  const next = new Set(prev);
1950
1948
  if (next.has(facetId)) {
@@ -1955,13 +1953,13 @@ const FiltersPanel = ({
1955
1953
  return next;
1956
1954
  });
1957
1955
  }, []);
1958
- const handleValueToggle = React.useCallback((attribute, value) => {
1956
+ const handleValueToggle = useCallback((attribute, value) => {
1959
1957
  onFacetToggle(attribute, value);
1960
1958
  }, [onFacetToggle]);
1961
- const handleRemoveFilter = React.useCallback((attribute, value) => {
1959
+ const handleRemoveFilter = useCallback((attribute, value) => {
1962
1960
  onFacetToggle(attribute, value);
1963
1961
  }, [onFacetToggle]);
1964
- const handleClearAll = React.useCallback(() => {
1962
+ const handleClearAll = useCallback(() => {
1965
1963
  // Remove all refined facets
1966
1964
  facets.forEach(facet => {
1967
1965
  facet.values.forEach(value => {
@@ -2070,8 +2068,8 @@ const ProductCardVertical = ({
2070
2068
  className: styles$6.productCardVertical__button,
2071
2069
  "aria-label": `${buttonLabel} - ${title}`,
2072
2070
  tabIndex: -1
2073
- }, /*#__PURE__*/React.createElement("span", null, buttonLabel), /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
2074
- icon: proSolidSvgIcons.faArrowUpRightFromSquare,
2071
+ }, /*#__PURE__*/React.createElement("span", null, buttonLabel), /*#__PURE__*/React.createElement(FontAwesomeIcon, {
2072
+ icon: faArrowUpRightFromSquare$1,
2075
2073
  "aria-hidden": "true"
2076
2074
  })));
2077
2075
  };
@@ -2340,11 +2338,11 @@ const FilterDrawer = ({
2340
2338
  children,
2341
2339
  className
2342
2340
  }) => {
2343
- const drawerRef = React.useRef(null);
2344
- const previouslyFocusedElement = React.useRef(null);
2341
+ const drawerRef = useRef(null);
2342
+ const previouslyFocusedElement = useRef(null);
2345
2343
 
2346
2344
  // Focus management
2347
- React.useEffect(() => {
2345
+ useEffect(() => {
2348
2346
  if (isOpen) {
2349
2347
  // Store previously focused element
2350
2348
  previouslyFocusedElement.current = document.activeElement;
@@ -2371,7 +2369,7 @@ const FilterDrawer = ({
2371
2369
  }, [isOpen]);
2372
2370
 
2373
2371
  // Escape key handler
2374
- React.useEffect(() => {
2372
+ useEffect(() => {
2375
2373
  const handleEscape = event => {
2376
2374
  if (event.key === 'Escape' && isOpen) {
2377
2375
  onClose();
@@ -2382,7 +2380,7 @@ const FilterDrawer = ({
2382
2380
  }, [isOpen, onClose]);
2383
2381
 
2384
2382
  // Focus trap implementation
2385
- React.useEffect(() => {
2383
+ useEffect(() => {
2386
2384
  if (!isOpen || !drawerRef.current) return;
2387
2385
  const drawer = drawerRef.current;
2388
2386
  const focusableElements = drawer.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
@@ -2428,7 +2426,7 @@ const FilterDrawer = ({
2428
2426
  onClick: onClose,
2429
2427
  "aria-label": "Close filters",
2430
2428
  className: styles$2.drawerCloseButton
2431
- }, /*#__PURE__*/React.createElement(reactFontawesome.FontAwesomeIcon, {
2429
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
2432
2430
  icon: faXmark
2433
2431
  })), /*#__PURE__*/React.createElement("div", {
2434
2432
  ref: drawerRef,
@@ -2471,7 +2469,7 @@ const FederatedResultsView = ({
2471
2469
  const displayContents = activeTab === "products" ? [] : contents;
2472
2470
 
2473
2471
  // Content tab single-select handler (clears all others when selecting)
2474
- const handleContentCategorySelect = React.useCallback((attribute, value) => {
2472
+ const handleContentCategorySelect = useCallback((attribute, value) => {
2475
2473
  const facet = facets.find(f => f.attribute === attribute);
2476
2474
  if (!facet) return;
2477
2475
 
@@ -2490,15 +2488,15 @@ const FederatedResultsView = ({
2490
2488
  }, [facets, onFacetToggle]);
2491
2489
 
2492
2490
  // Track if any filters applied
2493
- const hasAppliedFilters = React.useMemo(() => {
2491
+ const hasAppliedFilters = useMemo(() => {
2494
2492
  return facets.some(facet => facet.values.some(value => value.isRefined));
2495
2493
  }, [facets]);
2496
2494
 
2497
2495
  // Track previous filter state to detect transitions
2498
- const prevHasAppliedFilters = React.useRef(hasAppliedFilters);
2496
+ const prevHasAppliedFilters = useRef(hasAppliedFilters);
2499
2497
 
2500
2498
  // Auto-close drawer when transitioning FROM filters applied TO no filters (mobile only)
2501
- React.useEffect(() => {
2499
+ useEffect(() => {
2502
2500
  // Only close if we HAD filters and now have NONE (not on initial open)
2503
2501
  if (prevHasAppliedFilters.current && !hasAppliedFilters && isFilterDrawerOpen && onFilterDrawerClose) {
2504
2502
  onFilterDrawerClose();
@@ -2657,7 +2655,7 @@ const FederatedSearchExperience = ({
2657
2655
  onFilterDrawerClose
2658
2656
  }) => {
2659
2657
  // Track if any filters are active (for red dot indicator)
2660
- const hasAppliedFilters = React.useMemo(() => {
2658
+ const hasAppliedFilters = useMemo(() => {
2661
2659
  return facets.some(facet => facet.values.some(value => value.isRefined));
2662
2660
  }, [facets]);
2663
2661
  return /*#__PURE__*/React.createElement(SearchModal, {
@@ -2830,10 +2828,8 @@ const SearchTriggerButton = ({
2830
2828
  }, label));
2831
2829
  };
2832
2830
 
2833
- exports.AlgoliaDynamicSearch = AlgoliaDynamicSearchLeybold;
2834
- exports.AlgoliaDynamicSearchLeybold = AlgoliaDynamicSearchLeybold;
2835
- exports.AppliedFilterTag = AppliedFilterTag;
2836
- exports.AppliedFilters = AppliedFilters;
2831
+ export { AlgoliaDynamicSearchLeybold as AlgoliaDynamicSearch, AlgoliaDynamicSearchLeybold, AppliedFilterTag, AppliedFilters, Button, ContentCardHorizontal, FederatedInstantResultsLayout, FederatedResultsView, FederatedSearchExperience, FilterAccordion, FilterItem, FilterSearch, FiltersPanel, Footer, FooterBottom, FooterLink, FooterLinkGroup, FooterSocialIcon, FooterSocialIcons, ModalCloseButton, Pagination, PaginationButton, PaginationEllipsis, PaginationItem, ProductCardHorizontal, ProductCardVertical, QrFormLeybold as QrForm, QrFormLeybold, ResultsColumn, ResultsCount, ResultsList, SearchBar, SearchIcon, SearchInput, SearchModal, SearchSubmitButton, SearchTriggerButton, SeeAllLinkButton };
2832
+ liedFilters = AppliedFilters;
2837
2833
  exports.Button = Button;
2838
2834
  exports.ContentCardHorizontal = ContentCardHorizontal;
2839
2835
  exports.FederatedInstantResultsLayout = FederatedInstantResultsLayout;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asante-org/leybold-design-system",
3
- "version": "1.2.2",
3
+ "version": "1.3.1",
4
4
  "description": "Design system for Leybold",
5
5
  "license": "UNLICENSED",
6
6
  "main": "dist/index.js",
@@ -24,7 +24,7 @@
24
24
  "release:major": "npm version major && npm run build:npm && npm run publish:npm"
25
25
  },
26
26
  "dependencies": {
27
- "@asante-org/edwardsvacuum-design-system": "^1.8.3",
27
+ "@asante-org/edwardsvacuum-design-system": "^1.9.1",
28
28
  "classnames": "^2.5.1",
29
29
  "next": "13.3.0",
30
30
  "path": "^0.12.7",