@dnanpm/ui-components 0.8.0 → 0.10.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 (249) hide show
  1. package/README.md +13 -0
  2. package/dist/components/Accordion/Accordion.css +9 -2
  3. package/dist/components/AccordionItem/AccordionItem.cjs +4 -4
  4. package/dist/components/AccordionItem/AccordionItem.cjs.map +1 -1
  5. package/dist/components/AccordionItem/AccordionItem.css +8 -2
  6. package/dist/components/AccordionItem/AccordionItem.d.ts.map +1 -1
  7. package/dist/components/AccordionItem/AccordionItem.js +2 -2
  8. package/dist/components/AccordionItem/AccordionItem.js.map +1 -1
  9. package/dist/components/Avatar/Avatar.cjs +83 -0
  10. package/dist/components/Avatar/Avatar.cjs.map +1 -0
  11. package/dist/components/Avatar/Avatar.css +188 -0
  12. package/dist/components/Avatar/Avatar.d.ts +3 -0
  13. package/dist/components/Avatar/Avatar.d.ts.map +1 -0
  14. package/dist/components/Avatar/Avatar.js +83 -0
  15. package/dist/components/Avatar/Avatar.js.map +1 -0
  16. package/dist/components/Avatar/Avatar.module.css.cjs +40 -0
  17. package/dist/components/Avatar/Avatar.module.css.cjs.map +1 -0
  18. package/dist/components/Avatar/Avatar.module.css.js +40 -0
  19. package/dist/components/Avatar/Avatar.module.css.js.map +1 -0
  20. package/dist/components/Avatar/Avatar.types.d.ts +66 -0
  21. package/dist/components/Avatar/Avatar.types.d.ts.map +1 -0
  22. package/dist/components/Avatar/Avatar.utils.cjs +17 -0
  23. package/dist/components/Avatar/Avatar.utils.cjs.map +1 -0
  24. package/dist/components/Avatar/Avatar.utils.d.ts +6 -0
  25. package/dist/components/Avatar/Avatar.utils.d.ts.map +1 -0
  26. package/dist/components/Avatar/Avatar.utils.js +17 -0
  27. package/dist/components/Avatar/Avatar.utils.js.map +1 -0
  28. package/dist/components/Avatar/index.d.ts +3 -0
  29. package/dist/components/Avatar/index.d.ts.map +1 -0
  30. package/dist/components/Breadcrumb/Breadcrumb.cjs +9 -12
  31. package/dist/components/Breadcrumb/Breadcrumb.cjs.map +1 -1
  32. package/dist/components/Breadcrumb/Breadcrumb.css +20 -17
  33. package/dist/components/Breadcrumb/Breadcrumb.d.ts.map +1 -1
  34. package/dist/components/Breadcrumb/Breadcrumb.js +2 -5
  35. package/dist/components/Breadcrumb/Breadcrumb.js.map +1 -1
  36. package/dist/components/Breadcrumb/Breadcrumb.module.css.cjs +5 -8
  37. package/dist/components/Breadcrumb/Breadcrumb.module.css.cjs.map +1 -1
  38. package/dist/components/Breadcrumb/Breadcrumb.module.css.js +5 -8
  39. package/dist/components/Breadcrumb/Breadcrumb.module.css.js.map +1 -1
  40. package/dist/components/Button/Button.cjs +29 -3
  41. package/dist/components/Button/Button.cjs.map +1 -1
  42. package/dist/components/Button/Button.css +76 -30
  43. package/dist/components/Button/Button.d.ts +1 -1
  44. package/dist/components/Button/Button.d.ts.map +1 -1
  45. package/dist/components/Button/Button.js +28 -2
  46. package/dist/components/Button/Button.js.map +1 -1
  47. package/dist/components/Button/Button.module.css.cjs +19 -11
  48. package/dist/components/Button/Button.module.css.cjs.map +1 -1
  49. package/dist/components/Button/Button.module.css.js +19 -11
  50. package/dist/components/Button/Button.module.css.js.map +1 -1
  51. package/dist/components/Button/Button.types.d.ts +20 -3
  52. package/dist/components/Button/Button.types.d.ts.map +1 -1
  53. package/dist/components/Button/index.d.ts +1 -1
  54. package/dist/components/Button/index.d.ts.map +1 -1
  55. package/dist/components/ButtonCard/ButtonCard.cjs +19 -14
  56. package/dist/components/ButtonCard/ButtonCard.cjs.map +1 -1
  57. package/dist/components/ButtonCard/ButtonCard.css +62 -20
  58. package/dist/components/ButtonCard/ButtonCard.d.ts +2 -1
  59. package/dist/components/ButtonCard/ButtonCard.d.ts.map +1 -1
  60. package/dist/components/ButtonCard/ButtonCard.js +17 -12
  61. package/dist/components/ButtonCard/ButtonCard.js.map +1 -1
  62. package/dist/components/ButtonCard/ButtonCard.module.css.cjs +14 -12
  63. package/dist/components/ButtonCard/ButtonCard.module.css.cjs.map +1 -1
  64. package/dist/components/ButtonCard/ButtonCard.module.css.js +14 -12
  65. package/dist/components/ButtonCard/ButtonCard.module.css.js.map +1 -1
  66. package/dist/components/ButtonCard/ButtonCard.types.d.ts +3 -2
  67. package/dist/components/ButtonCard/ButtonCard.types.d.ts.map +1 -1
  68. package/dist/components/Checkbox/Checkbox.cjs +105 -0
  69. package/dist/components/Checkbox/Checkbox.cjs.map +1 -0
  70. package/dist/components/Checkbox/Checkbox.css +323 -0
  71. package/dist/components/Checkbox/Checkbox.d.ts +3 -0
  72. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -0
  73. package/dist/components/Checkbox/Checkbox.js +105 -0
  74. package/dist/components/Checkbox/Checkbox.js.map +1 -0
  75. package/dist/components/Checkbox/Checkbox.module.css.cjs +35 -0
  76. package/dist/components/Checkbox/Checkbox.module.css.cjs.map +1 -0
  77. package/dist/components/Checkbox/Checkbox.module.css.js +35 -0
  78. package/dist/components/Checkbox/Checkbox.module.css.js.map +1 -0
  79. package/dist/components/Checkbox/Checkbox.types.d.ts +47 -0
  80. package/dist/components/Checkbox/Checkbox.types.d.ts.map +1 -0
  81. package/dist/components/Checkbox/index.d.ts +3 -0
  82. package/dist/components/Checkbox/index.d.ts.map +1 -0
  83. package/dist/components/ContentCard/ContentCard.cjs +97 -0
  84. package/dist/components/ContentCard/ContentCard.cjs.map +1 -0
  85. package/dist/components/ContentCard/ContentCard.css +254 -0
  86. package/dist/components/ContentCard/ContentCard.d.ts +3 -0
  87. package/dist/components/ContentCard/ContentCard.d.ts.map +1 -0
  88. package/dist/components/ContentCard/ContentCard.js +97 -0
  89. package/dist/components/ContentCard/ContentCard.js.map +1 -0
  90. package/dist/components/ContentCard/ContentCard.module.css.cjs +24 -0
  91. package/dist/components/ContentCard/ContentCard.module.css.cjs.map +1 -0
  92. package/dist/components/ContentCard/ContentCard.module.css.js +25 -0
  93. package/dist/components/ContentCard/ContentCard.module.css.js.map +1 -0
  94. package/dist/components/ContentCard/ContentCard.types.d.ts +100 -0
  95. package/dist/components/ContentCard/ContentCard.types.d.ts.map +1 -0
  96. package/dist/components/ContentCard/index.d.ts +3 -0
  97. package/dist/components/ContentCard/index.d.ts.map +1 -0
  98. package/dist/components/Drawer/Drawer.cjs +15 -7
  99. package/dist/components/Drawer/Drawer.cjs.map +1 -1
  100. package/dist/components/Drawer/Drawer.css +47 -45
  101. package/dist/components/Drawer/Drawer.d.ts.map +1 -1
  102. package/dist/components/Drawer/Drawer.js +12 -4
  103. package/dist/components/Drawer/Drawer.js.map +1 -1
  104. package/dist/components/Drawer/Drawer.module.css.cjs +16 -16
  105. package/dist/components/Drawer/Drawer.module.css.js +16 -16
  106. package/dist/components/Footer/Footer.cjs +8 -9
  107. package/dist/components/Footer/Footer.cjs.map +1 -1
  108. package/dist/components/Footer/Footer.css +91 -84
  109. package/dist/components/Footer/Footer.d.ts.map +1 -1
  110. package/dist/components/Footer/Footer.js +1 -2
  111. package/dist/components/Footer/Footer.js.map +1 -1
  112. package/dist/components/Footer/Footer.module.css.cjs +39 -39
  113. package/dist/components/Footer/Footer.module.css.js +39 -39
  114. package/dist/components/FunctionButton/FunctionButton.cjs +2 -2
  115. package/dist/components/FunctionButton/FunctionButton.cjs.map +1 -1
  116. package/dist/components/FunctionButton/FunctionButton.css +5 -2
  117. package/dist/components/FunctionButton/FunctionButton.js +1 -1
  118. package/dist/components/FunctionButton/FunctionButton.js.map +1 -1
  119. package/dist/components/Hero/Hero.cjs +30 -29
  120. package/dist/components/Hero/Hero.cjs.map +1 -1
  121. package/dist/components/Hero/Hero.css +86 -74
  122. package/dist/components/Hero/Hero.d.ts +1 -1
  123. package/dist/components/Hero/Hero.d.ts.map +1 -1
  124. package/dist/components/Hero/Hero.js +30 -29
  125. package/dist/components/Hero/Hero.js.map +1 -1
  126. package/dist/components/Hero/Hero.module.css.cjs +20 -17
  127. package/dist/components/Hero/Hero.module.css.cjs.map +1 -1
  128. package/dist/components/Hero/Hero.module.css.js +20 -17
  129. package/dist/components/Hero/Hero.module.css.js.map +1 -1
  130. package/dist/components/Hero/Hero.types.d.ts +2 -6
  131. package/dist/components/Hero/Hero.types.d.ts.map +1 -1
  132. package/dist/components/IconButton/IconButton.cjs +3 -4
  133. package/dist/components/IconButton/IconButton.cjs.map +1 -1
  134. package/dist/components/IconButton/IconButton.css +5 -2
  135. package/dist/components/IconButton/IconButton.d.ts.map +1 -1
  136. package/dist/components/IconButton/IconButton.js +1 -2
  137. package/dist/components/IconButton/IconButton.js.map +1 -1
  138. package/dist/components/Label/Label.css +5 -2
  139. package/dist/components/MainNavigation/MainNavigation.cjs +556 -191
  140. package/dist/components/MainNavigation/MainNavigation.cjs.map +1 -1
  141. package/dist/components/MainNavigation/MainNavigation.css +297 -170
  142. package/dist/components/MainNavigation/MainNavigation.d.ts +1 -1
  143. package/dist/components/MainNavigation/MainNavigation.d.ts.map +1 -1
  144. package/dist/components/MainNavigation/MainNavigation.js +526 -161
  145. package/dist/components/MainNavigation/MainNavigation.js.map +1 -1
  146. package/dist/components/MainNavigation/MainNavigation.module.css.cjs +80 -68
  147. package/dist/components/MainNavigation/MainNavigation.module.css.cjs.map +1 -1
  148. package/dist/components/MainNavigation/MainNavigation.module.css.js +80 -68
  149. package/dist/components/MainNavigation/MainNavigation.module.css.js.map +1 -1
  150. package/dist/components/MainNavigation/MainNavigation.types.d.ts +55 -21
  151. package/dist/components/MainNavigation/MainNavigation.types.d.ts.map +1 -1
  152. package/dist/components/MainNavigation/MainNavigation.utils.cjs +28 -4
  153. package/dist/components/MainNavigation/MainNavigation.utils.cjs.map +1 -1
  154. package/dist/components/MainNavigation/MainNavigation.utils.d.ts +11 -1
  155. package/dist/components/MainNavigation/MainNavigation.utils.d.ts.map +1 -1
  156. package/dist/components/MainNavigation/MainNavigation.utils.js +28 -4
  157. package/dist/components/MainNavigation/MainNavigation.utils.js.map +1 -1
  158. package/dist/components/MainNavigation/index.d.ts +1 -1
  159. package/dist/components/MainNavigation/index.d.ts.map +1 -1
  160. package/dist/components/Modal/Modal.cjs +14 -6
  161. package/dist/components/Modal/Modal.cjs.map +1 -1
  162. package/dist/components/Modal/Modal.css +43 -40
  163. package/dist/components/Modal/Modal.d.ts.map +1 -1
  164. package/dist/components/Modal/Modal.js +12 -4
  165. package/dist/components/Modal/Modal.js.map +1 -1
  166. package/dist/components/Modal/Modal.module.css.cjs +18 -18
  167. package/dist/components/Modal/Modal.module.css.js +18 -18
  168. package/dist/components/Notification/Notification.cjs +3 -2
  169. package/dist/components/Notification/Notification.cjs.map +1 -1
  170. package/dist/components/Notification/Notification.css +20 -12
  171. package/dist/components/Notification/Notification.d.ts.map +1 -1
  172. package/dist/components/Notification/Notification.js +2 -1
  173. package/dist/components/Notification/Notification.js.map +1 -1
  174. package/dist/components/Notification/Notification.module.css.cjs +9 -9
  175. package/dist/components/Notification/Notification.module.css.js +9 -9
  176. package/dist/components/Pagination/Pagination.cjs +142 -0
  177. package/dist/components/Pagination/Pagination.cjs.map +1 -0
  178. package/dist/components/Pagination/Pagination.css +256 -0
  179. package/dist/components/Pagination/Pagination.d.ts +3 -0
  180. package/dist/components/Pagination/Pagination.d.ts.map +1 -0
  181. package/dist/components/Pagination/Pagination.js +142 -0
  182. package/dist/components/Pagination/Pagination.js.map +1 -0
  183. package/dist/components/Pagination/Pagination.module.css.cjs +34 -0
  184. package/dist/components/Pagination/Pagination.module.css.cjs.map +1 -0
  185. package/dist/components/Pagination/Pagination.module.css.js +34 -0
  186. package/dist/components/Pagination/Pagination.module.css.js.map +1 -0
  187. package/dist/components/Pagination/Pagination.types.d.ts +20 -0
  188. package/dist/components/Pagination/Pagination.types.d.ts.map +1 -0
  189. package/dist/components/Pagination/Pagination.utils.cjs +76 -0
  190. package/dist/components/Pagination/Pagination.utils.cjs.map +1 -0
  191. package/dist/components/Pagination/Pagination.utils.d.ts +21 -0
  192. package/dist/components/Pagination/Pagination.utils.d.ts.map +1 -0
  193. package/dist/components/Pagination/Pagination.utils.js +76 -0
  194. package/dist/components/Pagination/Pagination.utils.js.map +1 -0
  195. package/dist/components/Pagination/index.d.ts +3 -0
  196. package/dist/components/Pagination/index.d.ts.map +1 -0
  197. package/dist/components/Pictograph/Pictograph.css +9 -2
  198. package/dist/components/Pictograph/PictographItem.css +9 -2
  199. package/dist/components/Quote/Quote.css +5 -2
  200. package/dist/components/Spinner/Spinner.css +9 -2
  201. package/dist/design-tokens/dist/tokens.cjs +5 -0
  202. package/dist/design-tokens/dist/tokens.cjs.map +1 -0
  203. package/dist/design-tokens/dist/tokens.js +5 -0
  204. package/dist/design-tokens/dist/tokens.js.map +1 -0
  205. package/dist/index.cjs +8 -0
  206. package/dist/index.cjs.map +1 -1
  207. package/dist/index.d.ts +10 -2
  208. package/dist/index.d.ts.map +1 -1
  209. package/dist/index.js +8 -0
  210. package/dist/index.js.map +1 -1
  211. package/dist/styles/utilities.css +6 -0
  212. package/dist/styles/utils/elevation.css +34 -26
  213. package/dist/styles/utils/focus.css +63 -65
  214. package/dist/styles/utils/index.cjs +33 -0
  215. package/dist/styles/utils/index.cjs.map +1 -0
  216. package/dist/styles/utils/index.d.ts +20 -0
  217. package/dist/styles/utils/index.d.ts.map +1 -0
  218. package/dist/styles/utils/index.js +33 -0
  219. package/dist/styles/utils/index.js.map +1 -0
  220. package/dist/styles/utils/overlay.css +35 -28
  221. package/dist/styles/utils/text-decoration.css +19 -12
  222. package/dist/styles.css +46 -12
  223. package/dist/utils/index.d.ts +1 -0
  224. package/dist/utils/index.d.ts.map +1 -1
  225. package/dist/utils/isRenderable/index.d.ts +2 -0
  226. package/dist/utils/isRenderable/index.d.ts.map +1 -0
  227. package/dist/utils/isRenderable/isRenderable.cjs +5 -0
  228. package/dist/utils/isRenderable/isRenderable.cjs.map +1 -0
  229. package/dist/utils/isRenderable/isRenderable.d.ts +4 -0
  230. package/dist/utils/isRenderable/isRenderable.d.ts.map +1 -0
  231. package/dist/utils/isRenderable/isRenderable.js +5 -0
  232. package/dist/utils/isRenderable/isRenderable.js.map +1 -0
  233. package/package.json +12 -4
  234. package/dist/styles/utils/elevation.module.css.cjs +0 -16
  235. package/dist/styles/utils/elevation.module.css.cjs.map +0 -1
  236. package/dist/styles/utils/elevation.module.css.js +0 -16
  237. package/dist/styles/utils/elevation.module.css.js.map +0 -1
  238. package/dist/styles/utils/focus.module.css.cjs +0 -16
  239. package/dist/styles/utils/focus.module.css.cjs.map +0 -1
  240. package/dist/styles/utils/focus.module.css.js +0 -16
  241. package/dist/styles/utils/focus.module.css.js.map +0 -1
  242. package/dist/styles/utils/overlay.module.css.cjs +0 -13
  243. package/dist/styles/utils/overlay.module.css.cjs.map +0 -1
  244. package/dist/styles/utils/overlay.module.css.js +0 -13
  245. package/dist/styles/utils/overlay.module.css.js.map +0 -1
  246. package/dist/styles/utils/text-decoration.module.css.cjs +0 -13
  247. package/dist/styles/utils/text-decoration.module.css.cjs.map +0 -1
  248. package/dist/styles/utils/text-decoration.module.css.js +0 -13
  249. package/dist/styles/utils/text-decoration.module.css.js.map +0 -1
@@ -1,14 +1,12 @@
1
1
  import { jsxs, jsx, Fragment as Fragment$1 } from "react/jsx-runtime";
2
- import { useState, useRef, useCallback, useEffect, Fragment } from "react";
2
+ import { useState, useId, useRef, useCallback, useEffect, Fragment } from "react";
3
3
  import { Globe, Search, Cart, Close, Menu, ChevronRight, Open, ArrowRight } from "@dnanpm/icons";
4
- import focusStyles from "../../styles/utils/focus.module.css.js";
5
- import overlayStyles from "../../styles/utils/overlay.module.css.js";
6
- import elevationStyles from "../../styles/utils/elevation.module.css.js";
7
- import textDecorationStyles from "../../styles/utils/text-decoration.module.css.js";
4
+ import { focusStyles, textDecorationStyles, elevationStyles, overlayStyles } from "../../styles/utils/index.js";
8
5
  import styles from "./MainNavigation.module.css.js";
9
- import { assignRef, isMobileViewportByEnvironment, isMobileIosDeviceByEnvironment, isDesktopViewportByEnvironment, getLinkTarget, getLinkRel, toNavigableHref, isExternalLink, isItemInCurrentPath, isExternalTarget, isLinkInCurrentPage } from "./MainNavigation.utils.js";
6
+ import { assignRef, desktopMinWidthMediaQuery, isMobileViewportByEnvironment, isMobileIosDeviceByEnvironment, isDesktopViewportByEnvironment, getLinkTarget, getLinkRel, toNavigableHref, isExternalLink, getLanguageToggleAnnouncements, languageLinkAriaLabels, isItemInCurrentPath, isExternalTarget, isLinkInCurrentPath, isLinkInCurrentPage } from "./MainNavigation.utils.js";
10
7
  import { cn } from "../../utils/cn/cn.js";
11
8
  import { Button } from "../Button/Button.js";
9
+ import { Drawer } from "../Drawer/Drawer.js";
12
10
  import { IconButton } from "../IconButton/IconButton.js";
13
11
  const defaultOrganizations = [];
14
12
  const defaultItems = [];
@@ -17,33 +15,33 @@ const defaultLogoSrc = `data:image/svg+xml,${encodeURIComponent(defaultLogoSvg)}
17
15
  const mobilePanelAnimationDurationMs = 200;
18
16
  const mobileBodyScrollLockClass = "dds-un-scrollable";
19
17
  const defaultOverflowCategoryLabel = "Muut kategoriat";
20
- const desktopMinWidthMediaQuery = "(min-width: 1024px)";
21
18
  const defaultRenderLink = (props) => /* @__PURE__ */ jsx("a", { ...props });
19
+ const defaultRenderLanguageLink = (props) => /* @__PURE__ */ jsx("a", { ...props });
22
20
  const MainNavigation = ({
23
21
  organizations = defaultOrganizations,
24
22
  items = defaultItems,
25
- loginHref = "#",
26
23
  loginLabel = "Kirjaudu",
27
24
  logoHref = "/",
28
- languageSelectorLabel = "FI",
25
+ languages,
26
+ renderLanguageLink = defaultRenderLanguageLink,
29
27
  searchLabel = "Haku",
30
28
  cartLabel = "Ostoskori",
31
- showLanguageSelector = false,
32
- showSearch = false,
33
- showCart = false,
34
29
  cartCounter,
35
30
  cartCounterLabel = "tuotetta ostoskorissa",
36
- onLanguageSelectorClick,
37
- onSearchClick,
38
- onCartClick,
39
- mobileMenuOpenAriaLabel = "Avaa valikko",
40
- mobileMenuCloseAriaLabel = "Sulje valikko",
31
+ cartOpen,
32
+ onCartOpenChange,
33
+ onSearchOpenChange,
34
+ onLanguageOpenChange,
35
+ onLoginOpenChange,
36
+ searchDropdownContent,
37
+ loginDropdownContent,
38
+ cartContent,
39
+ mobileMenuOpenAriaLabel = "Avaa päävalikko",
40
+ mobileMenuCloseAriaLabel = "Sulje päävalikko",
41
41
  organizationStripAriaLabel = "Sivustot",
42
42
  logoAriaLabel = "Siirry etusivulle",
43
43
  mobilePrimaryNavigationAriaLabel = "Päävalikko",
44
44
  externalLinkAriaLabel = "avautuu uuteen välilehteen",
45
- defaultMobileMenuOpen = false,
46
- defaultOpenItemIndex = null,
47
45
  currentPathname,
48
46
  overflowCategoryLabel = defaultOverflowCategoryLabel,
49
47
  onMobileMenuToggle,
@@ -54,13 +52,24 @@ const MainNavigation = ({
54
52
  ref,
55
53
  ...props
56
54
  }) => {
57
- const [mobileMenuOpen, setMobileMenuOpen] = useState(defaultMobileMenuOpen);
55
+ const isCartControlled = cartOpen !== void 0;
56
+ const showSearch = searchDropdownContent != null && typeof searchDropdownContent !== "boolean";
57
+ const showLogin = loginDropdownContent != null && typeof loginDropdownContent !== "boolean";
58
+ const showCart = cartContent != null && typeof cartContent !== "boolean";
59
+ const currentLanguage = languages?.find((language) => language.current) ?? languages?.[0];
60
+ const alternativeLanguages = currentLanguage != null ? (languages ?? []).filter((language) => language.code !== currentLanguage.code) : [];
61
+ const showLanguage = currentLanguage != null && alternativeLanguages.length > 0;
62
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
58
63
  const [isMobileMenuClosing, setIsMobileMenuClosing] = useState(false);
59
- const [openTopLevelItemIndex, setOpenTopLevelItemIndex] = useState(
60
- defaultOpenItemIndex
61
- );
62
- const [isDesktopHeaderOpen, setIsDesktopHeaderOpen] = useState(true);
64
+ const [openTopLevelItemIndex, setOpenTopLevelItemIndex] = useState(null);
65
+ const [isHeaderOpen, setIsHeaderOpen] = useState(true);
63
66
  const [mobileActiveCategoryIndex, setMobileActiveCategoryIndex] = useState(null);
67
+ const [internalCartOpen, setInternalCartOpen] = useState(false);
68
+ const isCartOpen = cartOpen ?? internalCartOpen;
69
+ const [openUtilityDropdown, setOpenUtilityDropdown] = useState(null);
70
+ const searchDropdownId = useId();
71
+ const languageDropdownId = useId();
72
+ const loginDropdownId = useId();
64
73
  const [isMobileSecondPanelClosing, setIsMobileSecondPanelClosing] = useState(false);
65
74
  const [isMobileThirdPanelClosing, setIsMobileThirdPanelClosing] = useState(false);
66
75
  const mobileSecondPanelCloseTimeoutRef = useRef(null);
@@ -76,6 +85,9 @@ const MainNavigation = ({
76
85
  );
77
86
  const headerElementRef = useRef(null);
78
87
  const desktopPanelTriggerButtonRefs = useRef([]);
88
+ const searchTriggerRef = useRef(null);
89
+ const languageTriggerRef = useRef(null);
90
+ const loginTriggerRef = useRef(null);
79
91
  const mobilePrimaryNavRef = useRef(null);
80
92
  const mobileMenuToggleButtonRef = useRef(null);
81
93
  const mobileModalPanelRef = useRef(null);
@@ -85,9 +97,18 @@ const MainNavigation = ({
85
97
  const mobileLevelTwoCategoryButtonRefs = useRef([]);
86
98
  const focusMobilePanelBackOnOpenRef = useRef(false);
87
99
  const focusMobileThirdPanelBackOnOpenRef = useRef(false);
100
+ const lastInteractionWasKeyboardRef = useRef(false);
88
101
  const focusReturnToMobileCategoryTimeoutRef = useRef(
89
102
  null
90
103
  );
104
+ const notifyRef = useRef({
105
+ mobileMenu: false,
106
+ desktopItem: null,
107
+ search: false,
108
+ language: false,
109
+ login: false,
110
+ cart: false
111
+ });
91
112
  const setHeaderRef = useCallback(
92
113
  (node) => {
93
114
  headerElementRef.current = node;
@@ -130,19 +151,18 @@ const MainNavigation = ({
130
151
  let previousScrollY = window.pageYOffset;
131
152
  let headerHeight = parseFloat(window.getComputedStyle(headerElement).height.replace("px", "")) || headerElement.offsetHeight;
132
153
  const openHeader = () => {
133
- setIsDesktopHeaderOpen(true);
154
+ setIsHeaderOpen(true);
134
155
  };
135
156
  const closeHeader = () => {
136
- setIsDesktopHeaderOpen(false);
157
+ setIsHeaderOpen(false);
158
+ };
159
+ const headerHasVisibleFocus = () => {
160
+ const active = document.activeElement;
161
+ return lastInteractionWasKeyboardRef.current && active instanceof HTMLElement && headerElement.contains(active);
137
162
  };
138
163
  const handleScroll = () => {
139
164
  const currentScrollY = window.pageYOffset;
140
- if (!desktopQuery.matches) {
141
- openHeader();
142
- previousScrollY = currentScrollY;
143
- return;
144
- }
145
- if (mobileMenuOpen || openTopLevelItemIndex != null) {
165
+ if (mobileMenuOpen || openTopLevelItemIndex != null || openUtilityDropdown != null || headerHasVisibleFocus()) {
146
166
  openHeader();
147
167
  previousScrollY = currentScrollY;
148
168
  return;
@@ -156,6 +176,11 @@ const MainNavigation = ({
156
176
  }
157
177
  previousScrollY = currentScrollY;
158
178
  };
179
+ const handleFocusIn = () => {
180
+ if (headerHasVisibleFocus()) {
181
+ openHeader();
182
+ }
183
+ };
159
184
  const handleViewportChange = () => {
160
185
  openHeader();
161
186
  previousScrollY = window.pageYOffset;
@@ -163,14 +188,33 @@ const MainNavigation = ({
163
188
  };
164
189
  window.addEventListener("scroll", handleScroll, { passive: true });
165
190
  window.addEventListener("resize", handleViewportChange);
191
+ document.addEventListener("focusin", handleFocusIn);
166
192
  desktopQuery.addEventListener("change", handleViewportChange);
167
193
  handleScroll();
168
194
  return () => {
169
195
  window.removeEventListener("scroll", handleScroll);
170
196
  window.removeEventListener("resize", handleViewportChange);
197
+ document.removeEventListener("focusin", handleFocusIn);
171
198
  desktopQuery.removeEventListener("change", handleViewportChange);
172
199
  };
173
- }, [mobileMenuOpen, openTopLevelItemIndex]);
200
+ }, [mobileMenuOpen, openTopLevelItemIndex, openUtilityDropdown]);
201
+ useEffect(() => {
202
+ if (typeof document === "undefined") {
203
+ return;
204
+ }
205
+ const handleKeyDown = () => {
206
+ lastInteractionWasKeyboardRef.current = true;
207
+ };
208
+ const handlePointerDown = () => {
209
+ lastInteractionWasKeyboardRef.current = false;
210
+ };
211
+ document.addEventListener("keydown", handleKeyDown, true);
212
+ document.addEventListener("pointerdown", handlePointerDown, true);
213
+ return () => {
214
+ document.removeEventListener("keydown", handleKeyDown, true);
215
+ document.removeEventListener("pointerdown", handlePointerDown, true);
216
+ };
217
+ }, []);
174
218
  useEffect(() => {
175
219
  const browserWindow = globalThis.window;
176
220
  const browserDocument = globalThis.document;
@@ -207,7 +251,7 @@ const MainNavigation = ({
207
251
  return;
208
252
  }
209
253
  const desktopQuery = window.matchMedia(desktopMinWidthMediaQuery);
210
- const applyViewportModeChange = ({ matches: isDesktopViewport2 }) => {
254
+ const handleViewportModeChange = ({ matches: isDesktopViewport2 }) => {
211
255
  if (isDesktopViewport2) {
212
256
  clearTimeout(mobileSecondPanelCloseTimeoutRef.current ?? void 0);
213
257
  mobileSecondPanelCloseTimeoutRef.current = null;
@@ -215,28 +259,25 @@ const MainNavigation = ({
215
259
  mobileThirdPanelCloseTimeoutRef.current = null;
216
260
  clearTimeout(resetMobileThirdPanelScrollTimeoutRef.current ?? void 0);
217
261
  resetMobileThirdPanelScrollTimeoutRef.current = null;
218
- setMobileMenuOpen((previous) => {
219
- if (previous) {
220
- onMobileMenuToggle?.(false);
221
- }
222
- return false;
223
- });
262
+ if (notifyRef.current.mobileMenu) {
263
+ notifyRef.current.mobileMenu = false;
264
+ onMobileMenuToggle?.(false);
265
+ }
266
+ setMobileMenuOpen(false);
224
267
  setMobileActiveCategoryIndex(null);
225
268
  setIsMobileSecondPanelClosing(false);
226
269
  setIsMobileThirdPanelClosing(false);
227
270
  return;
228
271
  }
229
- setOpenTopLevelItemIndex((previous) => {
230
- if (previous !== null) {
231
- onDesktopItemToggle?.(null);
232
- }
233
- return null;
234
- });
272
+ if (notifyRef.current.desktopItem !== null) {
273
+ notifyRef.current.desktopItem = null;
274
+ onDesktopItemToggle?.(null);
275
+ }
276
+ setOpenTopLevelItemIndex(null);
235
277
  };
236
- applyViewportModeChange(desktopQuery);
237
- desktopQuery.addEventListener("change", applyViewportModeChange);
278
+ desktopQuery.addEventListener("change", handleViewportModeChange);
238
279
  return () => {
239
- desktopQuery.removeEventListener("change", applyViewportModeChange);
280
+ desktopQuery.removeEventListener("change", handleViewportModeChange);
240
281
  };
241
282
  }, [onDesktopItemToggle, onMobileMenuToggle]);
242
283
  const resetMobilePanelState = useCallback(() => {
@@ -256,20 +297,18 @@ const MainNavigation = ({
256
297
  return;
257
298
  }
258
299
  const shouldAnimateMobileClose = mobileMenuOpen;
300
+ if (mobileMenuOpen) {
301
+ notifyRef.current.mobileMenu = false;
302
+ onMobileMenuToggle?.(false);
303
+ }
304
+ if (openTopLevelItemIndex !== null) {
305
+ notifyRef.current.desktopItem = null;
306
+ onDesktopItemToggle?.(null);
307
+ }
259
308
  clearTimeout(mobileMenuCloseResetTimeoutRef.current ?? void 0);
260
309
  setIsMobileMenuClosing(shouldAnimateMobileClose);
261
- setMobileMenuOpen((previous) => {
262
- if (previous) {
263
- onMobileMenuToggle?.(false);
264
- }
265
- return false;
266
- });
267
- setOpenTopLevelItemIndex((previous) => {
268
- if (previous !== null) {
269
- onDesktopItemToggle?.(null);
270
- }
271
- return null;
272
- });
310
+ setMobileMenuOpen(false);
311
+ setOpenTopLevelItemIndex(null);
273
312
  if (shouldAnimateMobileClose) {
274
313
  mobileMenuCloseResetTimeoutRef.current = setTimeout(() => {
275
314
  resetMobilePanelState();
@@ -292,19 +331,21 @@ const MainNavigation = ({
292
331
  closeMobileMenu();
293
332
  return;
294
333
  }
334
+ closeUtilityDropdown();
335
+ notifyRef.current.mobileMenu = true;
295
336
  setMobileMenuOpen(true);
296
337
  setIsMobileMenuClosing(false);
297
338
  onMobileMenuToggle?.(true);
298
339
  };
299
340
  const toggleTopLevelItem = (index) => {
300
- setOpenTopLevelItemIndex((previous) => {
301
- const next = previous === index ? null : index;
302
- setMobileActiveCategoryIndex(null);
303
- setIsMobileSecondPanelClosing(false);
304
- setIsMobileThirdPanelClosing(false);
305
- onDesktopItemToggle?.(next);
306
- return next;
307
- });
341
+ closeUtilityDropdown();
342
+ const next = openTopLevelItemIndex === index ? null : index;
343
+ notifyRef.current.desktopItem = next;
344
+ setOpenTopLevelItemIndex(next);
345
+ setMobileActiveCategoryIndex(null);
346
+ setIsMobileSecondPanelClosing(false);
347
+ setIsMobileThirdPanelClosing(false);
348
+ onDesktopItemToggle?.(next);
308
349
  };
309
350
  const isDesktopViewport = useCallback(() => {
310
351
  return isDesktopViewportByEnvironment(globalThis.window);
@@ -356,6 +397,23 @@ const MainNavigation = ({
356
397
  },
357
398
  [getDesktopPanelInteractiveElements, isFocusable]
358
399
  );
400
+ const getUtilityDropdownFocusLoopElements = useCallback(
401
+ (kind) => {
402
+ const focusLoopElements = /* @__PURE__ */ new Set();
403
+ const triggerButton = kind === "search" ? searchTriggerRef.current : kind === "language" ? languageTriggerRef.current : loginTriggerRef.current;
404
+ if (triggerButton != null && isFocusable(triggerButton)) {
405
+ focusLoopElements.add(triggerButton);
406
+ }
407
+ getFocusableElements(
408
+ headerElementRef.current,
409
+ `.${styles["main-navigation__dropdown"]} a[href], .${styles["main-navigation__dropdown"]} button:not([disabled]), .${styles["main-navigation__dropdown"]} input:not([disabled]), .${styles["main-navigation__dropdown"]} select:not([disabled]), .${styles["main-navigation__dropdown"]} textarea:not([disabled]), .${styles["main-navigation__dropdown"]} [tabindex]:not([tabindex="-1"])`
410
+ ).forEach((element) => {
411
+ focusLoopElements.add(element);
412
+ });
413
+ return Array.from(focusLoopElements);
414
+ },
415
+ [getFocusableElements, isFocusable]
416
+ );
359
417
  const getMobileFocusableElements = useCallback(() => {
360
418
  const focusableElements = [];
361
419
  const addFocusableElements = (elements) => {
@@ -399,6 +457,26 @@ const MainNavigation = ({
399
457
  resetMobileThirdPanelScrollTimeoutRef.current = null;
400
458
  }, 0);
401
459
  }, []);
460
+ const notifyUtilityOpenChange = useCallback(
461
+ (kind, open) => {
462
+ if (kind === "search") {
463
+ onSearchOpenChange?.(open);
464
+ } else if (kind === "language") {
465
+ onLanguageOpenChange?.(open);
466
+ } else {
467
+ onLoginOpenChange?.(open);
468
+ }
469
+ },
470
+ [onLanguageOpenChange, onLoginOpenChange, onSearchOpenChange]
471
+ );
472
+ const closeUtilityDropdown = useCallback(() => {
473
+ const openDropdown = notifyRef.current.search ? "search" : notifyRef.current.language ? "language" : notifyRef.current.login ? "login" : null;
474
+ if (openDropdown != null) {
475
+ notifyRef.current[openDropdown] = false;
476
+ notifyUtilityOpenChange(openDropdown, false);
477
+ }
478
+ setOpenUtilityDropdown(null);
479
+ }, [notifyUtilityOpenChange]);
402
480
  const closeMenus = useCallback(() => {
403
481
  clearTimeout(mobileSecondPanelCloseTimeoutRef.current ?? void 0);
404
482
  mobileSecondPanelCloseTimeoutRef.current = null;
@@ -406,16 +484,24 @@ const MainNavigation = ({
406
484
  mobileThirdPanelCloseTimeoutRef.current = null;
407
485
  clearTimeout(focusMobileSecondPanelTimeoutRef.current ?? void 0);
408
486
  focusMobileSecondPanelTimeoutRef.current = null;
487
+ focusMobilePanelBackOnOpenRef.current = false;
409
488
  clearTimeout(focusMobileThirdPanelTimeoutRef.current ?? void 0);
410
489
  focusMobileThirdPanelTimeoutRef.current = null;
490
+ focusMobileThirdPanelBackOnOpenRef.current = false;
411
491
  clearTimeout(resetMobileThirdPanelScrollTimeoutRef.current ?? void 0);
412
492
  resetMobileThirdPanelScrollTimeoutRef.current = null;
413
493
  clearTimeout(focusReturnToMobileTopLevelItemTimeoutRef.current ?? void 0);
414
494
  focusReturnToMobileTopLevelItemTimeoutRef.current = null;
415
495
  clearTimeout(focusReturnToMobileCategoryTimeoutRef.current ?? void 0);
416
496
  focusReturnToMobileCategoryTimeoutRef.current = null;
497
+ const openDropdown = notifyRef.current.search ? "search" : notifyRef.current.language ? "language" : notifyRef.current.login ? "login" : null;
498
+ if (openDropdown != null) {
499
+ notifyRef.current[openDropdown] = false;
500
+ notifyUtilityOpenChange(openDropdown, false);
501
+ }
502
+ setOpenUtilityDropdown(null);
417
503
  closeMobileMenu();
418
- }, [closeMobileMenu]);
504
+ }, [closeMobileMenu, notifyUtilityOpenChange]);
419
505
  const closeMobilePanel = useCallback(
420
506
  ({
421
507
  isClosing,
@@ -464,9 +550,133 @@ const MainNavigation = ({
464
550
  const openItem = openTopLevelItemIndex != null ? items[openTopLevelItemIndex] : void 0;
465
551
  const openPanel = openItem?.panel;
466
552
  const isMobilePanelClosingOut = isMobileMenuClosing && !mobileMenuOpen;
467
- const showPageOverlay = mobileMenuOpen || openPanel != null || isMobilePanelClosingOut;
468
553
  const isOverlayClosingOut = isMobilePanelClosingOut && openPanel == null;
469
554
  const cartAccessibleLabel = cartCounter != null ? `${cartLabel} ${cartCounter} ${cartCounterLabel}` : cartLabel;
555
+ const languageAnnouncements = currentLanguage != null ? getLanguageToggleAnnouncements(
556
+ (languages ?? []).map((language) => language.code),
557
+ currentLanguage.code
558
+ ) : [];
559
+ const activeUtilityDropdown = openUtilityDropdown === "search" && showSearch ? "search" : openUtilityDropdown === "language" && showLanguage ? "language" : openUtilityDropdown === "login" && showLogin ? "login" : null;
560
+ const isSearchOpen = activeUtilityDropdown === "search";
561
+ const isLanguageOpen = activeUtilityDropdown === "language";
562
+ const isLoginOpen = activeUtilityDropdown === "login";
563
+ const effectiveCartOpen = isCartOpen && showCart;
564
+ const showPageOverlay = mobileMenuOpen || openPanel != null || isMobilePanelClosingOut || activeUtilityDropdown != null;
565
+ const toggleUtilityDropdown = (kind) => {
566
+ const previous = openUtilityDropdown;
567
+ const next = previous === kind ? null : kind;
568
+ if (previous != null && previous !== next) {
569
+ notifyRef.current[previous] = false;
570
+ notifyUtilityOpenChange(previous, false);
571
+ }
572
+ if (next != null) {
573
+ notifyRef.current[next] = true;
574
+ notifyUtilityOpenChange(next, true);
575
+ closeMobileMenu();
576
+ if (isCartOpen) {
577
+ if (!isCartControlled) {
578
+ notifyRef.current.cart = false;
579
+ setInternalCartOpen(false);
580
+ }
581
+ onCartOpenChange?.(false);
582
+ }
583
+ }
584
+ setOpenUtilityDropdown(next);
585
+ };
586
+ const handleLanguageClick = () => {
587
+ toggleUtilityDropdown("language");
588
+ };
589
+ const handleSearchClick = () => {
590
+ toggleUtilityDropdown("search");
591
+ };
592
+ const handleLoginClick = () => {
593
+ toggleUtilityDropdown("login");
594
+ };
595
+ const handleCartClick = () => {
596
+ const next = !isCartOpen;
597
+ if (next) {
598
+ closeMenus();
599
+ }
600
+ if (!isCartControlled) {
601
+ notifyRef.current.cart = next && showCart;
602
+ setInternalCartOpen(next);
603
+ }
604
+ onCartOpenChange?.(next);
605
+ };
606
+ const handleCartOpenChange = (open) => {
607
+ if (!isCartControlled) {
608
+ notifyRef.current.cart = open && showCart;
609
+ setInternalCartOpen(open);
610
+ }
611
+ onCartOpenChange?.(open);
612
+ };
613
+ if (effectiveCartOpen) {
614
+ if (openUtilityDropdown !== null) {
615
+ setOpenUtilityDropdown(null);
616
+ }
617
+ if (mobileMenuOpen) {
618
+ setMobileMenuOpen(false);
619
+ }
620
+ if (isMobileMenuClosing) {
621
+ setIsMobileMenuClosing(false);
622
+ }
623
+ if (openTopLevelItemIndex !== null || mobileActiveCategoryIndex !== null || isMobileSecondPanelClosing || isMobileThirdPanelClosing) {
624
+ resetMobilePanelState();
625
+ }
626
+ } else if (openUtilityDropdown !== null && activeUtilityDropdown === null) {
627
+ setOpenUtilityDropdown(null);
628
+ }
629
+ if (!isCartControlled && internalCartOpen && !showCart) {
630
+ setInternalCartOpen(false);
631
+ }
632
+ useEffect(() => {
633
+ const lastNotified = notifyRef.current;
634
+ if (mobileMenuOpen !== lastNotified.mobileMenu) {
635
+ lastNotified.mobileMenu = mobileMenuOpen;
636
+ onMobileMenuToggle?.(mobileMenuOpen);
637
+ }
638
+ if (openTopLevelItemIndex !== lastNotified.desktopItem) {
639
+ lastNotified.desktopItem = openTopLevelItemIndex;
640
+ onDesktopItemToggle?.(openTopLevelItemIndex);
641
+ }
642
+ ["search", "language", "login"].forEach((kind) => {
643
+ const open = activeUtilityDropdown === kind;
644
+ if (open !== lastNotified[kind]) {
645
+ lastNotified[kind] = open;
646
+ notifyUtilityOpenChange(kind, open);
647
+ }
648
+ });
649
+ if (!isCartControlled) {
650
+ const open = internalCartOpen && showCart;
651
+ if (open !== lastNotified.cart) {
652
+ lastNotified.cart = open;
653
+ onCartOpenChange?.(open);
654
+ }
655
+ }
656
+ });
657
+ useEffect(() => {
658
+ if (!effectiveCartOpen) {
659
+ return;
660
+ }
661
+ clearTimeout(mobileSecondPanelCloseTimeoutRef.current ?? void 0);
662
+ mobileSecondPanelCloseTimeoutRef.current = null;
663
+ clearTimeout(mobileThirdPanelCloseTimeoutRef.current ?? void 0);
664
+ mobileThirdPanelCloseTimeoutRef.current = null;
665
+ clearTimeout(mobileMenuCloseResetTimeoutRef.current ?? void 0);
666
+ mobileMenuCloseResetTimeoutRef.current = null;
667
+ clearTimeout(focusMobileSecondPanelTimeoutRef.current ?? void 0);
668
+ focusMobileSecondPanelTimeoutRef.current = null;
669
+ focusMobilePanelBackOnOpenRef.current = false;
670
+ clearTimeout(focusMobileThirdPanelTimeoutRef.current ?? void 0);
671
+ focusMobileThirdPanelTimeoutRef.current = null;
672
+ focusMobileThirdPanelBackOnOpenRef.current = false;
673
+ clearTimeout(resetMobileThirdPanelScrollTimeoutRef.current ?? void 0);
674
+ resetMobileThirdPanelScrollTimeoutRef.current = null;
675
+ clearTimeout(focusReturnToMobileTopLevelItemTimeoutRef.current ?? void 0);
676
+ focusReturnToMobileTopLevelItemTimeoutRef.current = null;
677
+ clearTimeout(focusReturnToMobileCategoryTimeoutRef.current ?? void 0);
678
+ focusReturnToMobileCategoryTimeoutRef.current = null;
679
+ }, [effectiveCartOpen]);
470
680
  useEffect(() => {
471
681
  if (!showPageOverlay) {
472
682
  return;
@@ -574,6 +784,7 @@ const MainNavigation = ({
574
784
  closeTimeoutRef: mobileSecondPanelCloseTimeoutRef,
575
785
  onClosed: () => {
576
786
  const closedTopLevelItemIndex = openTopLevelItemIndex;
787
+ notifyRef.current.desktopItem = null;
577
788
  setOpenTopLevelItemIndex(null);
578
789
  setMobileActiveCategoryIndex(null);
579
790
  onDesktopItemToggle?.(null);
@@ -647,39 +858,49 @@ const MainNavigation = ({
647
858
  {
648
859
  className: styles["main-navigation__mobile-level-2-category-list"],
649
860
  "aria-hidden": shouldHideLevelTwoFromAssistiveTech || void 0,
650
- children: mobilePanelColumns.map((column, index) => /* @__PURE__ */ jsx(
651
- "li",
652
- {
653
- className: styles["main-navigation__mobile-level-2-category-item"],
654
- children: /* @__PURE__ */ jsxs(
655
- "button",
656
- {
657
- ref: (node) => {
658
- mobileLevelTwoCategoryButtonRefs.current[index] = node;
659
- },
660
- type: "button",
661
- className: cn(
662
- styles["main-navigation__mobile-level-2-category-button"],
663
- focusStyles.focusableInset
664
- ),
665
- onClick: () => openMobileCategoryPanel(index),
666
- onKeyDown: (event) => {
667
- if (event.key !== "Enter" || isDesktopViewport()) {
668
- return;
669
- }
670
- event.preventDefault();
671
- focusMobileThirdPanelBackOnOpenRef.current = true;
672
- openMobileCategoryPanel(index);
673
- },
674
- children: [
675
- /* @__PURE__ */ jsx("span", { children: getColumnHeading(column.heading, column.overflow) }),
676
- /* @__PURE__ */ jsx(ChevronRight, {})
677
- ]
678
- }
679
- )
680
- },
681
- `mobile-category-${column.heading}-${index}`
682
- ))
861
+ children: mobilePanelColumns.map((column, index) => {
862
+ const isInCurrentPath = column.links.some(
863
+ (link) => isLinkInCurrentPath(link, currentPathname)
864
+ );
865
+ return /* @__PURE__ */ jsx(
866
+ "li",
867
+ {
868
+ className: styles["main-navigation__mobile-level-2-category-item"],
869
+ children: /* @__PURE__ */ jsxs(
870
+ "button",
871
+ {
872
+ ref: (node) => {
873
+ mobileLevelTwoCategoryButtonRefs.current[index] = node;
874
+ },
875
+ type: "button",
876
+ className: cn(
877
+ styles["main-navigation__mobile-level-2-category-button"],
878
+ isInCurrentPath && styles["main-navigation__mobile-level-2-category-button--current"],
879
+ focusStyles.focusableInset
880
+ ),
881
+ "aria-current": isInCurrentPath ? "true" : void 0,
882
+ onClick: () => openMobileCategoryPanel(index),
883
+ onKeyDown: (event) => {
884
+ if (event.key !== "Enter" || isDesktopViewport()) {
885
+ return;
886
+ }
887
+ event.preventDefault();
888
+ focusMobileThirdPanelBackOnOpenRef.current = true;
889
+ openMobileCategoryPanel(index);
890
+ },
891
+ children: [
892
+ /* @__PURE__ */ jsx("span", { children: getColumnHeading(
893
+ column.heading,
894
+ column.overflow
895
+ ) }),
896
+ /* @__PURE__ */ jsx(ChevronRight, {})
897
+ ]
898
+ }
899
+ )
900
+ },
901
+ `mobile-category-${column.heading}-${index}`
902
+ );
903
+ })
683
904
  }
684
905
  ),
685
906
  /* @__PURE__ */ jsx(
@@ -734,21 +955,29 @@ const MainNavigation = ({
734
955
  ]
735
956
  }
736
957
  ),
737
- /* @__PURE__ */ jsx("ul", { className: styles["main-navigation__mobile-level-3-list"], children: selectedColumn.links.map((link, index) => /* @__PURE__ */ jsx(
738
- "li",
739
- {
740
- className: styles["main-navigation__mobile-level-3-item"],
741
- children: renderNavigationLink({
742
- link,
743
- className: cn(
744
- styles["main-navigation__mobile-level-3-link"],
745
- focusStyles.focusableInset
746
- ),
747
- children: link.label
748
- })
749
- },
750
- `${selectedColumn.heading}-${index}`
751
- )) })
958
+ /* @__PURE__ */ jsx("ul", { className: styles["main-navigation__mobile-level-3-list"], children: selectedColumn.links.map((link, index) => {
959
+ const isInCurrentPage = isLinkInCurrentPage(
960
+ link,
961
+ currentPathname
962
+ );
963
+ return /* @__PURE__ */ jsx(
964
+ "li",
965
+ {
966
+ className: styles["main-navigation__mobile-level-3-item"],
967
+ children: renderNavigationLink({
968
+ link,
969
+ className: cn(
970
+ styles["main-navigation__mobile-level-3-link"],
971
+ isInCurrentPage && styles["main-navigation__mobile-level-3-link--current"],
972
+ focusStyles.focusableInset
973
+ ),
974
+ ariaCurrent: isInCurrentPage ? "page" : void 0,
975
+ children: link.label
976
+ })
977
+ },
978
+ `${selectedColumn.heading}-${index}`
979
+ );
980
+ }) })
752
981
  ] })
753
982
  }
754
983
  )
@@ -875,6 +1104,7 @@ const MainNavigation = ({
875
1104
  isCurrentPathItem && styles["main-navigation__item-toggle--current"],
876
1105
  isOpen && styles["main-navigation__item-toggle--open"]
877
1106
  ),
1107
+ "aria-current": isCurrentPathItem ? "true" : void 0,
878
1108
  "aria-expanded": isOpen,
879
1109
  onClick: () => toggleTopLevelItem(index),
880
1110
  onKeyDown: (event) => {
@@ -909,7 +1139,7 @@ const MainNavigation = ({
909
1139
  ref: setHeaderRef,
910
1140
  className: cn(
911
1141
  styles["main-navigation"],
912
- isDesktopHeaderOpen && styles["main-navigation--open"],
1142
+ isHeaderOpen && styles["main-navigation--open"],
913
1143
  mobileMenuOpen && styles["main-navigation--menu-open"],
914
1144
  isMobileMenuClosing && styles["main-navigation--menu-closing"],
915
1145
  showPageOverlay && styles["main-navigation--overlay"],
@@ -919,6 +1149,21 @@ const MainNavigation = ({
919
1149
  ),
920
1150
  ...props,
921
1151
  onKeyDown: (event) => {
1152
+ if (event.key === "Tab" && activeUtilityDropdown != null) {
1153
+ const focusLoopElements = getUtilityDropdownFocusLoopElements(activeUtilityDropdown);
1154
+ if (focusLoopElements.length > 1) {
1155
+ event.preventDefault();
1156
+ const currentIndex = focusLoopElements.indexOf(
1157
+ document.activeElement
1158
+ );
1159
+ const direction = event.shiftKey ? -1 : 1;
1160
+ const nextIndex = currentIndex === -1 ? event.shiftKey ? focusLoopElements.length - 1 : 0 : (currentIndex + direction + focusLoopElements.length) % focusLoopElements.length;
1161
+ focusLoopElements[nextIndex]?.focus();
1162
+ } else {
1163
+ closeUtilityDropdown();
1164
+ }
1165
+ return;
1166
+ }
922
1167
  if (event.key === "Tab" && mobileMenuOpen && !isDesktopViewport()) {
923
1168
  const focusableElements = getMobileFocusableElements();
924
1169
  if (focusableElements.length > 0) {
@@ -946,7 +1191,12 @@ const MainNavigation = ({
946
1191
  }
947
1192
  }
948
1193
  if (event.key === "Escape") {
1194
+ const utilityDropdownToRestore = activeUtilityDropdown;
949
1195
  closeMenus();
1196
+ if (utilityDropdownToRestore != null) {
1197
+ const triggerButton = utilityDropdownToRestore === "search" ? searchTriggerRef.current : utilityDropdownToRestore === "language" ? languageTriggerRef.current : loginTriggerRef.current;
1198
+ triggerButton?.focus();
1199
+ }
950
1200
  }
951
1201
  props.onKeyDown?.(event);
952
1202
  },
@@ -998,48 +1248,116 @@ const MainNavigation = ({
998
1248
  }
999
1249
  ),
1000
1250
  /* @__PURE__ */ jsxs("div", { className: styles["main-navigation__icon-nav"], children: [
1001
- showLanguageSelector && /* @__PURE__ */ jsxs(
1002
- "button",
1003
- {
1004
- type: "button",
1005
- className: cn(
1006
- styles["main-navigation__icon-nav-item"],
1007
- focusStyles.focusableInset
1008
- ),
1009
- "aria-label": languageSelectorLabel,
1010
- onClick: onLanguageSelectorClick,
1011
- children: [
1012
- /* @__PURE__ */ jsx(Globe, {}),
1013
- /* @__PURE__ */ jsx("span", { className: styles["main-navigation__icon-nav-label"], children: languageSelectorLabel })
1014
- ]
1015
- }
1016
- ),
1017
- showSearch && /* @__PURE__ */ jsxs(
1018
- "button",
1019
- {
1020
- type: "button",
1021
- className: cn(
1022
- styles["main-navigation__icon-nav-item"],
1023
- focusStyles.focusableInset
1251
+ showLanguage && currentLanguage != null && /* @__PURE__ */ jsxs("div", { className: styles["main-navigation__utility"], children: [
1252
+ /* @__PURE__ */ jsxs(
1253
+ "button",
1254
+ {
1255
+ ref: languageTriggerRef,
1256
+ type: "button",
1257
+ className: cn(
1258
+ styles["main-navigation__icon-nav-item"],
1259
+ isLanguageOpen && styles["main-navigation__icon-nav-item--active"],
1260
+ focusStyles.focusableInset
1261
+ ),
1262
+ "aria-expanded": isLanguageOpen,
1263
+ "aria-controls": isLanguageOpen ? languageDropdownId : void 0,
1264
+ onClick: handleLanguageClick,
1265
+ children: [
1266
+ /* @__PURE__ */ jsx(Globe, { "aria-hidden": "true" }),
1267
+ /* @__PURE__ */ jsx(
1268
+ "span",
1269
+ {
1270
+ "aria-hidden": "true",
1271
+ className: styles["main-navigation__icon-nav-label"],
1272
+ children: currentLanguage.code.toUpperCase()
1273
+ }
1274
+ ),
1275
+ /* @__PURE__ */ jsx("span", { className: styles["main-navigation__sr-only"], children: languageAnnouncements.map((announcement, index) => /* @__PURE__ */ jsxs(Fragment, { children: [
1276
+ index > 0 ? " " : null,
1277
+ /* @__PURE__ */ jsx("span", { lang: announcement.lang, children: announcement.text })
1278
+ ] }, announcement.lang)) })
1279
+ ]
1280
+ }
1281
+ ),
1282
+ isLanguageOpen && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1283
+ /* @__PURE__ */ jsx(
1284
+ "span",
1285
+ {
1286
+ "aria-hidden": "true",
1287
+ className: styles["main-navigation__dropdown-caret"]
1288
+ }
1024
1289
  ),
1025
- "aria-label": searchLabel,
1026
- onClick: onSearchClick,
1027
- children: [
1028
- /* @__PURE__ */ jsx(Search, {}),
1029
- /* @__PURE__ */ jsx("span", { className: styles["main-navigation__icon-nav-label"], children: searchLabel })
1030
- ]
1031
- }
1032
- ),
1290
+ /* @__PURE__ */ jsx(
1291
+ "div",
1292
+ {
1293
+ id: languageDropdownId,
1294
+ className: cn(
1295
+ styles["main-navigation__dropdown"],
1296
+ styles["main-navigation__dropdown--language"],
1297
+ elevationStyles.elevationMedium
1298
+ ),
1299
+ children: /* @__PURE__ */ jsx("ul", { className: styles["main-navigation__language-list"], children: alternativeLanguages.map((language) => /* @__PURE__ */ jsx(
1300
+ "li",
1301
+ {
1302
+ className: styles["main-navigation__language-list-item"],
1303
+ children: renderLanguageLink({
1304
+ href: toNavigableHref(language.href),
1305
+ lang: language.code,
1306
+ "aria-label": language.ariaLabel ?? languageLinkAriaLabels[language.code],
1307
+ className: cn(
1308
+ styles["main-navigation__language-link"],
1309
+ focusStyles.focusable
1310
+ ),
1311
+ children: language.code.toUpperCase()
1312
+ })
1313
+ },
1314
+ language.code
1315
+ )) })
1316
+ }
1317
+ )
1318
+ ] })
1319
+ ] }),
1320
+ showSearch && /* @__PURE__ */ jsxs("div", { className: styles["main-navigation__utility"], children: [
1321
+ /* @__PURE__ */ jsxs(
1322
+ "button",
1323
+ {
1324
+ ref: searchTriggerRef,
1325
+ type: "button",
1326
+ className: cn(
1327
+ styles["main-navigation__icon-nav-item"],
1328
+ isSearchOpen && styles["main-navigation__icon-nav-item--active"],
1329
+ focusStyles.focusableInset
1330
+ ),
1331
+ "aria-label": searchLabel,
1332
+ "aria-expanded": isSearchOpen,
1333
+ "aria-controls": isSearchOpen ? searchDropdownId : void 0,
1334
+ onClick: handleSearchClick,
1335
+ children: [
1336
+ /* @__PURE__ */ jsx(Search, {}),
1337
+ /* @__PURE__ */ jsx("span", { className: styles["main-navigation__icon-nav-label"], children: searchLabel })
1338
+ ]
1339
+ }
1340
+ ),
1341
+ isSearchOpen && /* @__PURE__ */ jsx(
1342
+ "span",
1343
+ {
1344
+ "aria-hidden": "true",
1345
+ className: styles["main-navigation__dropdown-caret"]
1346
+ }
1347
+ )
1348
+ ] }),
1033
1349
  showCart && /* @__PURE__ */ jsxs(
1034
1350
  "button",
1035
1351
  {
1036
1352
  type: "button",
1037
1353
  className: cn(
1038
1354
  styles["main-navigation__icon-nav-item"],
1355
+ isCartOpen && styles["main-navigation__icon-nav-item--active"],
1039
1356
  focusStyles.focusableInset
1040
1357
  ),
1041
1358
  "aria-label": cartAccessibleLabel,
1042
- onClick: onCartClick,
1359
+ "aria-expanded": isCartOpen,
1360
+ onClick: handleCartClick,
1043
1361
  children: [
1044
1362
  /* @__PURE__ */ jsx(Cart, {}),
1045
1363
  /* @__PURE__ */ jsx("span", { className: styles["main-navigation__icon-nav-label"], children: cartLabel }),
@@ -1054,16 +1372,53 @@ const MainNavigation = ({
1054
1372
  ]
1055
1373
  }
1056
1374
  ),
1057
- /* @__PURE__ */ jsx(
1058
- Button,
1059
- {
1060
- href: toNavigableHref(loginHref),
1061
- size: "small",
1062
- renderLink: renderUtilityLink,
1063
- children: loginLabel
1064
- }
1065
- )
1375
+ showLogin && /* @__PURE__ */ jsxs("div", { className: styles["main-navigation__utility"], children: [
1376
+ /* @__PURE__ */ jsx(
1377
+ Button,
1378
+ {
1379
+ ref: loginTriggerRef,
1380
+ size: "small",
1381
+ "aria-expanded": isLoginOpen,
1382
+ "aria-controls": isLoginOpen ? loginDropdownId : void 0,
1383
+ onClick: handleLoginClick,
1384
+ children: loginLabel
1385
+ }
1386
+ ),
1387
+ isLoginOpen && /* @__PURE__ */ jsxs(Fragment$1, { children: [
1388
+ /* @__PURE__ */ jsx(
1389
+ "span",
1390
+ {
1391
+ "aria-hidden": "true",
1392
+ className: styles["main-navigation__dropdown-caret"]
1393
+ }
1394
+ ),
1395
+ /* @__PURE__ */ jsx(
1396
+ "div",
1397
+ {
1398
+ id: loginDropdownId,
1399
+ className: cn(
1400
+ styles["main-navigation__dropdown"],
1401
+ styles["main-navigation__dropdown--login"],
1402
+ elevationStyles.elevationMedium
1403
+ ),
1404
+ children: loginDropdownContent
1405
+ }
1406
+ )
1407
+ ] })
1408
+ ] })
1066
1409
  ] }),
1410
+ showSearch && isSearchOpen && /* @__PURE__ */ jsx(
1411
+ "div",
1412
+ {
1413
+ id: searchDropdownId,
1414
+ className: cn(
1415
+ styles["main-navigation__dropdown"],
1416
+ styles["main-navigation__dropdown--search"],
1417
+ elevationStyles.elevationMedium
1418
+ ),
1419
+ children: searchDropdownContent
1420
+ }
1421
+ ),
1067
1422
  /* @__PURE__ */ jsx(
1068
1423
  "button",
1069
1424
  {
@@ -1083,6 +1438,16 @@ const MainNavigation = ({
1083
1438
  ] }),
1084
1439
  !mobileMenuOpen && renderPanel(
1085
1440
  cn(styles["main-navigation__panel"], styles["main-navigation__panel--desktop"])
1441
+ ),
1442
+ showCart && /* @__PURE__ */ jsx(
1443
+ Drawer,
1444
+ {
1445
+ open: isCartOpen,
1446
+ onOpenChange: handleCartOpenChange,
1447
+ title: cartLabel,
1448
+ size: "small",
1449
+ children: cartContent
1450
+ }
1086
1451
  )
1087
1452
  ]
1088
1453
  }