@dnanpm/ui-components 0.8.0 → 0.9.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.
- package/dist/components/Accordion/Accordion.css +6 -3
- package/dist/components/AccordionItem/AccordionItem.css +6 -3
- package/dist/components/Breadcrumb/Breadcrumb.css +6 -3
- package/dist/components/Button/Button.css +2 -3
- package/dist/components/ButtonCard/ButtonCard.css +2 -3
- package/dist/components/ContentCard/ContentCard.cjs +96 -0
- package/dist/components/ContentCard/ContentCard.cjs.map +1 -0
- package/dist/components/ContentCard/ContentCard.css +249 -0
- package/dist/components/ContentCard/ContentCard.d.ts +3 -0
- package/dist/components/ContentCard/ContentCard.d.ts.map +1 -0
- package/dist/components/ContentCard/ContentCard.js +96 -0
- package/dist/components/ContentCard/ContentCard.js.map +1 -0
- package/dist/components/ContentCard/ContentCard.module.css.cjs +24 -0
- package/dist/components/ContentCard/ContentCard.module.css.cjs.map +1 -0
- package/dist/components/ContentCard/ContentCard.module.css.js +25 -0
- package/dist/components/ContentCard/ContentCard.module.css.js.map +1 -0
- package/dist/components/ContentCard/ContentCard.types.d.ts +99 -0
- package/dist/components/ContentCard/ContentCard.types.d.ts.map +1 -0
- package/dist/components/ContentCard/index.d.ts +3 -0
- package/dist/components/ContentCard/index.d.ts.map +1 -0
- package/dist/components/Drawer/Drawer.css +2 -3
- package/dist/components/Footer/Footer.css +6 -3
- package/dist/components/FunctionButton/FunctionButton.css +2 -3
- package/dist/components/Hero/Hero.cjs +24 -26
- package/dist/components/Hero/Hero.cjs.map +1 -1
- package/dist/components/Hero/Hero.css +81 -74
- package/dist/components/Hero/Hero.js +24 -26
- package/dist/components/Hero/Hero.js.map +1 -1
- package/dist/components/Hero/Hero.module.css.cjs +20 -17
- package/dist/components/Hero/Hero.module.css.cjs.map +1 -1
- package/dist/components/Hero/Hero.module.css.js +20 -17
- package/dist/components/Hero/Hero.module.css.js.map +1 -1
- package/dist/components/IconButton/IconButton.css +2 -3
- package/dist/components/Label/Label.css +2 -3
- package/dist/components/MainNavigation/MainNavigation.cjs +407 -96
- package/dist/components/MainNavigation/MainNavigation.cjs.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.css +255 -151
- package/dist/components/MainNavigation/MainNavigation.d.ts +1 -1
- package/dist/components/MainNavigation/MainNavigation.d.ts.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.js +409 -98
- package/dist/components/MainNavigation/MainNavigation.js.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.module.css.cjs +78 -68
- package/dist/components/MainNavigation/MainNavigation.module.css.cjs.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.module.css.js +78 -68
- package/dist/components/MainNavigation/MainNavigation.module.css.js.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.types.d.ts +64 -17
- package/dist/components/MainNavigation/MainNavigation.types.d.ts.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.utils.cjs +20 -0
- package/dist/components/MainNavigation/MainNavigation.utils.cjs.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.utils.d.ts +10 -1
- package/dist/components/MainNavigation/MainNavigation.utils.d.ts.map +1 -1
- package/dist/components/MainNavigation/MainNavigation.utils.js +20 -0
- package/dist/components/MainNavigation/MainNavigation.utils.js.map +1 -1
- package/dist/components/MainNavigation/index.d.ts +1 -1
- package/dist/components/MainNavigation/index.d.ts.map +1 -1
- package/dist/components/Modal/Modal.css +2 -3
- package/dist/components/Notification/Notification.css +6 -3
- package/dist/components/Pictograph/Pictograph.css +6 -3
- package/dist/components/Pictograph/PictographItem.css +6 -3
- package/dist/components/Quote/Quote.css +2 -3
- package/dist/components/Spinner/Spinner.css +6 -3
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/styles/utils/elevation.css +2 -3
- package/dist/styles/utils/focus.css +25 -22
- package/dist/styles/utils/focus.module.css.cjs +3 -3
- package/dist/styles/utils/focus.module.css.js +3 -3
- package/dist/styles/utils/overlay.css +2 -3
- package/dist/styles/utils/text-decoration.css +2 -3
- package/dist/styles.css +17 -7
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ const MainNavigation_module = require("./MainNavigation.module.css.cjs");
|
|
|
11
11
|
const MainNavigation_utils = require("./MainNavigation.utils.cjs");
|
|
12
12
|
const cn = require("../../utils/cn/cn.cjs");
|
|
13
13
|
const Button = require("../Button/Button.cjs");
|
|
14
|
+
const Drawer = require("../Drawer/Drawer.cjs");
|
|
14
15
|
const IconButton = require("../IconButton/IconButton.cjs");
|
|
15
16
|
const defaultOrganizations = [];
|
|
16
17
|
const defaultItems = [];
|
|
@@ -21,25 +22,30 @@ const mobileBodyScrollLockClass = "dds-un-scrollable";
|
|
|
21
22
|
const defaultOverflowCategoryLabel = "Muut kategoriat";
|
|
22
23
|
const desktopMinWidthMediaQuery = "(min-width: 1024px)";
|
|
23
24
|
const defaultRenderLink = (props) => /* @__PURE__ */ jsxRuntime.jsx("a", { ...props });
|
|
25
|
+
const defaultRenderLanguageLink = (props) => /* @__PURE__ */ jsxRuntime.jsx("a", { ...props });
|
|
24
26
|
const MainNavigation = ({
|
|
25
27
|
organizations = defaultOrganizations,
|
|
26
28
|
items = defaultItems,
|
|
27
|
-
loginHref = "#",
|
|
28
29
|
loginLabel = "Kirjaudu",
|
|
29
30
|
logoHref = "/",
|
|
30
|
-
|
|
31
|
+
languages,
|
|
32
|
+
renderLanguageLink = defaultRenderLanguageLink,
|
|
31
33
|
searchLabel = "Haku",
|
|
32
34
|
cartLabel = "Ostoskori",
|
|
33
|
-
showLanguageSelector = false,
|
|
34
|
-
showSearch = false,
|
|
35
|
-
showCart = false,
|
|
36
35
|
cartCounter,
|
|
37
36
|
cartCounterLabel = "tuotetta ostoskorissa",
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
37
|
+
defaultCartOpen = false,
|
|
38
|
+
cartOpen,
|
|
39
|
+
onCartOpenChange,
|
|
40
|
+
defaultOpenDropdown,
|
|
41
|
+
onSearchOpenChange,
|
|
42
|
+
onLanguageOpenChange,
|
|
43
|
+
onLoginOpenChange,
|
|
44
|
+
searchDropdownContent,
|
|
45
|
+
loginDropdownContent,
|
|
46
|
+
cartContent,
|
|
47
|
+
mobileMenuOpenAriaLabel = "Avaa päävalikko",
|
|
48
|
+
mobileMenuCloseAriaLabel = "Sulje päävalikko",
|
|
43
49
|
organizationStripAriaLabel = "Sivustot",
|
|
44
50
|
logoAriaLabel = "Siirry etusivulle",
|
|
45
51
|
mobilePrimaryNavigationAriaLabel = "Päävalikko",
|
|
@@ -61,8 +67,17 @@ const MainNavigation = ({
|
|
|
61
67
|
const [openTopLevelItemIndex, setOpenTopLevelItemIndex] = react.useState(
|
|
62
68
|
defaultOpenItemIndex
|
|
63
69
|
);
|
|
64
|
-
const [
|
|
70
|
+
const [isHeaderOpen, setIsHeaderOpen] = react.useState(true);
|
|
65
71
|
const [mobileActiveCategoryIndex, setMobileActiveCategoryIndex] = react.useState(null);
|
|
72
|
+
const [internalCartOpen, setInternalCartOpen] = react.useState(defaultCartOpen);
|
|
73
|
+
const isCartControlled = cartOpen !== void 0;
|
|
74
|
+
const isCartOpen = cartOpen ?? internalCartOpen;
|
|
75
|
+
const hasInitialNavigationSurface = (cartOpen ?? defaultCartOpen) || defaultMobileMenuOpen || defaultOpenItemIndex != null && items[defaultOpenItemIndex]?.panel != null;
|
|
76
|
+
const [openUtilityDropdown, setOpenUtilityDropdown] = react.useState(hasInitialNavigationSurface ? null : defaultOpenDropdown ?? null);
|
|
77
|
+
const openUtilityDropdownRef = react.useRef(openUtilityDropdown);
|
|
78
|
+
const searchDropdownId = react.useId();
|
|
79
|
+
const languageDropdownId = react.useId();
|
|
80
|
+
const loginDropdownId = react.useId();
|
|
66
81
|
const [isMobileSecondPanelClosing, setIsMobileSecondPanelClosing] = react.useState(false);
|
|
67
82
|
const [isMobileThirdPanelClosing, setIsMobileThirdPanelClosing] = react.useState(false);
|
|
68
83
|
const mobileSecondPanelCloseTimeoutRef = react.useRef(null);
|
|
@@ -78,6 +93,9 @@ const MainNavigation = ({
|
|
|
78
93
|
);
|
|
79
94
|
const headerElementRef = react.useRef(null);
|
|
80
95
|
const desktopPanelTriggerButtonRefs = react.useRef([]);
|
|
96
|
+
const searchTriggerRef = react.useRef(null);
|
|
97
|
+
const languageTriggerRef = react.useRef(null);
|
|
98
|
+
const loginTriggerRef = react.useRef(null);
|
|
81
99
|
const mobilePrimaryNavRef = react.useRef(null);
|
|
82
100
|
const mobileMenuToggleButtonRef = react.useRef(null);
|
|
83
101
|
const mobileModalPanelRef = react.useRef(null);
|
|
@@ -87,9 +105,14 @@ const MainNavigation = ({
|
|
|
87
105
|
const mobileLevelTwoCategoryButtonRefs = react.useRef([]);
|
|
88
106
|
const focusMobilePanelBackOnOpenRef = react.useRef(false);
|
|
89
107
|
const focusMobileThirdPanelBackOnOpenRef = react.useRef(false);
|
|
108
|
+
const lastInteractionWasKeyboardRef = react.useRef(false);
|
|
90
109
|
const focusReturnToMobileCategoryTimeoutRef = react.useRef(
|
|
91
110
|
null
|
|
92
111
|
);
|
|
112
|
+
const mobileMenuOpenRef = react.useRef(mobileMenuOpen);
|
|
113
|
+
const openTopLevelItemIndexRef = react.useRef(openTopLevelItemIndex);
|
|
114
|
+
const lastAppliedViewportModeRef = react.useRef(null);
|
|
115
|
+
const internalCartOpenRef = react.useRef(internalCartOpen);
|
|
93
116
|
const setHeaderRef = react.useCallback(
|
|
94
117
|
(node) => {
|
|
95
118
|
headerElementRef.current = node;
|
|
@@ -132,19 +155,18 @@ const MainNavigation = ({
|
|
|
132
155
|
let previousScrollY = window.pageYOffset;
|
|
133
156
|
let headerHeight = parseFloat(window.getComputedStyle(headerElement).height.replace("px", "")) || headerElement.offsetHeight;
|
|
134
157
|
const openHeader = () => {
|
|
135
|
-
|
|
158
|
+
setIsHeaderOpen(true);
|
|
136
159
|
};
|
|
137
160
|
const closeHeader = () => {
|
|
138
|
-
|
|
161
|
+
setIsHeaderOpen(false);
|
|
162
|
+
};
|
|
163
|
+
const headerHasVisibleFocus = () => {
|
|
164
|
+
const active = document.activeElement;
|
|
165
|
+
return lastInteractionWasKeyboardRef.current && active instanceof HTMLElement && headerElement.contains(active);
|
|
139
166
|
};
|
|
140
167
|
const handleScroll = () => {
|
|
141
168
|
const currentScrollY = window.pageYOffset;
|
|
142
|
-
if (
|
|
143
|
-
openHeader();
|
|
144
|
-
previousScrollY = currentScrollY;
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
if (mobileMenuOpen || openTopLevelItemIndex != null) {
|
|
169
|
+
if (mobileMenuOpen || openTopLevelItemIndex != null || openUtilityDropdown != null || headerHasVisibleFocus()) {
|
|
148
170
|
openHeader();
|
|
149
171
|
previousScrollY = currentScrollY;
|
|
150
172
|
return;
|
|
@@ -158,6 +180,11 @@ const MainNavigation = ({
|
|
|
158
180
|
}
|
|
159
181
|
previousScrollY = currentScrollY;
|
|
160
182
|
};
|
|
183
|
+
const handleFocusIn = () => {
|
|
184
|
+
if (headerHasVisibleFocus()) {
|
|
185
|
+
openHeader();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
161
188
|
const handleViewportChange = () => {
|
|
162
189
|
openHeader();
|
|
163
190
|
previousScrollY = window.pageYOffset;
|
|
@@ -165,14 +192,33 @@ const MainNavigation = ({
|
|
|
165
192
|
};
|
|
166
193
|
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
167
194
|
window.addEventListener("resize", handleViewportChange);
|
|
195
|
+
document.addEventListener("focusin", handleFocusIn);
|
|
168
196
|
desktopQuery.addEventListener("change", handleViewportChange);
|
|
169
197
|
handleScroll();
|
|
170
198
|
return () => {
|
|
171
199
|
window.removeEventListener("scroll", handleScroll);
|
|
172
200
|
window.removeEventListener("resize", handleViewportChange);
|
|
201
|
+
document.removeEventListener("focusin", handleFocusIn);
|
|
173
202
|
desktopQuery.removeEventListener("change", handleViewportChange);
|
|
174
203
|
};
|
|
175
|
-
}, [mobileMenuOpen, openTopLevelItemIndex]);
|
|
204
|
+
}, [mobileMenuOpen, openTopLevelItemIndex, openUtilityDropdown]);
|
|
205
|
+
react.useEffect(() => {
|
|
206
|
+
if (typeof document === "undefined") {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
const handleKeyDown = () => {
|
|
210
|
+
lastInteractionWasKeyboardRef.current = true;
|
|
211
|
+
};
|
|
212
|
+
const handlePointerDown = () => {
|
|
213
|
+
lastInteractionWasKeyboardRef.current = false;
|
|
214
|
+
};
|
|
215
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
216
|
+
document.addEventListener("pointerdown", handlePointerDown, true);
|
|
217
|
+
return () => {
|
|
218
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
219
|
+
document.removeEventListener("pointerdown", handlePointerDown, true);
|
|
220
|
+
};
|
|
221
|
+
}, []);
|
|
176
222
|
react.useEffect(() => {
|
|
177
223
|
const browserWindow = globalThis.window;
|
|
178
224
|
const browserDocument = globalThis.document;
|
|
@@ -210,6 +256,11 @@ const MainNavigation = ({
|
|
|
210
256
|
}
|
|
211
257
|
const desktopQuery = window.matchMedia(desktopMinWidthMediaQuery);
|
|
212
258
|
const applyViewportModeChange = ({ matches: isDesktopViewport2 }) => {
|
|
259
|
+
const viewportMode = isDesktopViewport2 ? "desktop" : "mobile";
|
|
260
|
+
if (lastAppliedViewportModeRef.current === viewportMode) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
lastAppliedViewportModeRef.current = viewportMode;
|
|
213
264
|
if (isDesktopViewport2) {
|
|
214
265
|
clearTimeout(mobileSecondPanelCloseTimeoutRef.current ?? void 0);
|
|
215
266
|
mobileSecondPanelCloseTimeoutRef.current = null;
|
|
@@ -217,23 +268,23 @@ const MainNavigation = ({
|
|
|
217
268
|
mobileThirdPanelCloseTimeoutRef.current = null;
|
|
218
269
|
clearTimeout(resetMobileThirdPanelScrollTimeoutRef.current ?? void 0);
|
|
219
270
|
resetMobileThirdPanelScrollTimeoutRef.current = null;
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
271
|
+
const wasMobileMenuOpen = mobileMenuOpenRef.current;
|
|
272
|
+
mobileMenuOpenRef.current = false;
|
|
273
|
+
if (wasMobileMenuOpen) {
|
|
274
|
+
onMobileMenuToggle?.(false);
|
|
275
|
+
}
|
|
276
|
+
setMobileMenuOpen(false);
|
|
226
277
|
setMobileActiveCategoryIndex(null);
|
|
227
278
|
setIsMobileSecondPanelClosing(false);
|
|
228
279
|
setIsMobileThirdPanelClosing(false);
|
|
229
280
|
return;
|
|
230
281
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
282
|
+
const hadOpenDesktopItem = openTopLevelItemIndexRef.current !== null;
|
|
283
|
+
openTopLevelItemIndexRef.current = null;
|
|
284
|
+
if (hadOpenDesktopItem) {
|
|
285
|
+
onDesktopItemToggle?.(null);
|
|
286
|
+
}
|
|
287
|
+
setOpenTopLevelItemIndex(null);
|
|
237
288
|
};
|
|
238
289
|
applyViewportModeChange(desktopQuery);
|
|
239
290
|
desktopQuery.addEventListener("change", applyViewportModeChange);
|
|
@@ -242,6 +293,7 @@ const MainNavigation = ({
|
|
|
242
293
|
};
|
|
243
294
|
}, [onDesktopItemToggle, onMobileMenuToggle]);
|
|
244
295
|
const resetMobilePanelState = react.useCallback(() => {
|
|
296
|
+
openTopLevelItemIndexRef.current = null;
|
|
245
297
|
setOpenTopLevelItemIndex(null);
|
|
246
298
|
setMobileActiveCategoryIndex(null);
|
|
247
299
|
setIsMobileSecondPanelClosing(false);
|
|
@@ -258,20 +310,20 @@ const MainNavigation = ({
|
|
|
258
310
|
return;
|
|
259
311
|
}
|
|
260
312
|
const shouldAnimateMobileClose = mobileMenuOpen;
|
|
313
|
+
const wasMobileMenuOpen = mobileMenuOpenRef.current;
|
|
314
|
+
const openDesktopItemIndex = openTopLevelItemIndexRef.current;
|
|
315
|
+
mobileMenuOpenRef.current = false;
|
|
316
|
+
openTopLevelItemIndexRef.current = null;
|
|
317
|
+
if (wasMobileMenuOpen) {
|
|
318
|
+
onMobileMenuToggle?.(false);
|
|
319
|
+
}
|
|
320
|
+
if (openDesktopItemIndex !== null) {
|
|
321
|
+
onDesktopItemToggle?.(null);
|
|
322
|
+
}
|
|
261
323
|
clearTimeout(mobileMenuCloseResetTimeoutRef.current ?? void 0);
|
|
262
324
|
setIsMobileMenuClosing(shouldAnimateMobileClose);
|
|
263
|
-
setMobileMenuOpen(
|
|
264
|
-
|
|
265
|
-
onMobileMenuToggle?.(false);
|
|
266
|
-
}
|
|
267
|
-
return false;
|
|
268
|
-
});
|
|
269
|
-
setOpenTopLevelItemIndex((previous) => {
|
|
270
|
-
if (previous !== null) {
|
|
271
|
-
onDesktopItemToggle?.(null);
|
|
272
|
-
}
|
|
273
|
-
return null;
|
|
274
|
-
});
|
|
325
|
+
setMobileMenuOpen(false);
|
|
326
|
+
setOpenTopLevelItemIndex(null);
|
|
275
327
|
if (shouldAnimateMobileClose) {
|
|
276
328
|
mobileMenuCloseResetTimeoutRef.current = setTimeout(() => {
|
|
277
329
|
resetMobilePanelState();
|
|
@@ -294,19 +346,21 @@ const MainNavigation = ({
|
|
|
294
346
|
closeMobileMenu();
|
|
295
347
|
return;
|
|
296
348
|
}
|
|
349
|
+
closeUtilityDropdown();
|
|
350
|
+
mobileMenuOpenRef.current = true;
|
|
297
351
|
setMobileMenuOpen(true);
|
|
298
352
|
setIsMobileMenuClosing(false);
|
|
299
353
|
onMobileMenuToggle?.(true);
|
|
300
354
|
};
|
|
301
355
|
const toggleTopLevelItem = (index) => {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
356
|
+
closeUtilityDropdown();
|
|
357
|
+
const next = openTopLevelItemIndex === index ? null : index;
|
|
358
|
+
openTopLevelItemIndexRef.current = next;
|
|
359
|
+
setOpenTopLevelItemIndex(next);
|
|
360
|
+
setMobileActiveCategoryIndex(null);
|
|
361
|
+
setIsMobileSecondPanelClosing(false);
|
|
362
|
+
setIsMobileThirdPanelClosing(false);
|
|
363
|
+
onDesktopItemToggle?.(next);
|
|
310
364
|
};
|
|
311
365
|
const isDesktopViewport = react.useCallback(() => {
|
|
312
366
|
return MainNavigation_utils.isDesktopViewportByEnvironment(globalThis.window);
|
|
@@ -358,6 +412,23 @@ const MainNavigation = ({
|
|
|
358
412
|
},
|
|
359
413
|
[getDesktopPanelInteractiveElements, isFocusable]
|
|
360
414
|
);
|
|
415
|
+
const getUtilityDropdownFocusLoopElements = react.useCallback(
|
|
416
|
+
(kind) => {
|
|
417
|
+
const focusLoopElements = /* @__PURE__ */ new Set();
|
|
418
|
+
const triggerButton = kind === "search" ? searchTriggerRef.current : kind === "language" ? languageTriggerRef.current : loginTriggerRef.current;
|
|
419
|
+
if (triggerButton != null && isFocusable(triggerButton)) {
|
|
420
|
+
focusLoopElements.add(triggerButton);
|
|
421
|
+
}
|
|
422
|
+
getFocusableElements(
|
|
423
|
+
headerElementRef.current,
|
|
424
|
+
`.${MainNavigation_module["main-navigation__dropdown"]} a[href], .${MainNavigation_module["main-navigation__dropdown"]} button:not([disabled]), .${MainNavigation_module["main-navigation__dropdown"]} input:not([disabled]), .${MainNavigation_module["main-navigation__dropdown"]} select:not([disabled]), .${MainNavigation_module["main-navigation__dropdown"]} textarea:not([disabled]), .${MainNavigation_module["main-navigation__dropdown"]} [tabindex]:not([tabindex="-1"])`
|
|
425
|
+
).forEach((element) => {
|
|
426
|
+
focusLoopElements.add(element);
|
|
427
|
+
});
|
|
428
|
+
return Array.from(focusLoopElements);
|
|
429
|
+
},
|
|
430
|
+
[getFocusableElements, isFocusable]
|
|
431
|
+
);
|
|
361
432
|
const getMobileFocusableElements = react.useCallback(() => {
|
|
362
433
|
const focusableElements = [];
|
|
363
434
|
const addFocusableElements = (elements) => {
|
|
@@ -401,6 +472,26 @@ const MainNavigation = ({
|
|
|
401
472
|
resetMobileThirdPanelScrollTimeoutRef.current = null;
|
|
402
473
|
}, 0);
|
|
403
474
|
}, []);
|
|
475
|
+
const notifyUtilityOpenChange = react.useCallback(
|
|
476
|
+
(kind, open) => {
|
|
477
|
+
if (kind === "search") {
|
|
478
|
+
onSearchOpenChange?.(open);
|
|
479
|
+
} else if (kind === "language") {
|
|
480
|
+
onLanguageOpenChange?.(open);
|
|
481
|
+
} else {
|
|
482
|
+
onLoginOpenChange?.(open);
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
[onLanguageOpenChange, onLoginOpenChange, onSearchOpenChange]
|
|
486
|
+
);
|
|
487
|
+
const closeUtilityDropdown = react.useCallback(() => {
|
|
488
|
+
const openDropdown = openUtilityDropdownRef.current;
|
|
489
|
+
if (openDropdown != null) {
|
|
490
|
+
openUtilityDropdownRef.current = null;
|
|
491
|
+
notifyUtilityOpenChange(openDropdown, false);
|
|
492
|
+
}
|
|
493
|
+
setOpenUtilityDropdown(null);
|
|
494
|
+
}, [notifyUtilityOpenChange]);
|
|
404
495
|
const closeMenus = react.useCallback(() => {
|
|
405
496
|
clearTimeout(mobileSecondPanelCloseTimeoutRef.current ?? void 0);
|
|
406
497
|
mobileSecondPanelCloseTimeoutRef.current = null;
|
|
@@ -416,8 +507,14 @@ const MainNavigation = ({
|
|
|
416
507
|
focusReturnToMobileTopLevelItemTimeoutRef.current = null;
|
|
417
508
|
clearTimeout(focusReturnToMobileCategoryTimeoutRef.current ?? void 0);
|
|
418
509
|
focusReturnToMobileCategoryTimeoutRef.current = null;
|
|
510
|
+
const openDropdown = openUtilityDropdownRef.current;
|
|
511
|
+
if (openDropdown != null) {
|
|
512
|
+
openUtilityDropdownRef.current = null;
|
|
513
|
+
notifyUtilityOpenChange(openDropdown, false);
|
|
514
|
+
}
|
|
515
|
+
setOpenUtilityDropdown(null);
|
|
419
516
|
closeMobileMenu();
|
|
420
|
-
}, [closeMobileMenu]);
|
|
517
|
+
}, [closeMobileMenu, notifyUtilityOpenChange]);
|
|
421
518
|
const closeMobilePanel = react.useCallback(
|
|
422
519
|
({
|
|
423
520
|
isClosing,
|
|
@@ -466,9 +563,87 @@ const MainNavigation = ({
|
|
|
466
563
|
const openItem = openTopLevelItemIndex != null ? items[openTopLevelItemIndex] : void 0;
|
|
467
564
|
const openPanel = openItem?.panel;
|
|
468
565
|
const isMobilePanelClosingOut = isMobileMenuClosing && !mobileMenuOpen;
|
|
469
|
-
const showPageOverlay = mobileMenuOpen || openPanel != null || isMobilePanelClosingOut;
|
|
470
566
|
const isOverlayClosingOut = isMobilePanelClosingOut && openPanel == null;
|
|
567
|
+
const showSearch = searchDropdownContent != null && typeof searchDropdownContent !== "boolean";
|
|
568
|
+
const showLogin = loginDropdownContent != null && typeof loginDropdownContent !== "boolean";
|
|
569
|
+
const showCart = cartContent != null && typeof cartContent !== "boolean";
|
|
471
570
|
const cartAccessibleLabel = cartCounter != null ? `${cartLabel} ${cartCounter} ${cartCounterLabel}` : cartLabel;
|
|
571
|
+
const currentLanguage = languages?.find((language) => language.current) ?? languages?.[0];
|
|
572
|
+
const alternativeLanguages = currentLanguage != null ? (languages ?? []).filter((language) => language.code !== currentLanguage.code) : [];
|
|
573
|
+
const showLanguage = currentLanguage != null && alternativeLanguages.length > 0;
|
|
574
|
+
const languageAnnouncements = currentLanguage != null ? MainNavigation_utils.getLanguageToggleAnnouncements(
|
|
575
|
+
(languages ?? []).map((language) => language.code),
|
|
576
|
+
currentLanguage.code
|
|
577
|
+
) : [];
|
|
578
|
+
const activeUtilityDropdown = openUtilityDropdown === "search" && showSearch ? "search" : openUtilityDropdown === "language" && showLanguage ? "language" : openUtilityDropdown === "login" && showLogin ? "login" : null;
|
|
579
|
+
const isSearchOpen = activeUtilityDropdown === "search";
|
|
580
|
+
const isLanguageOpen = activeUtilityDropdown === "language";
|
|
581
|
+
const isLoginOpen = activeUtilityDropdown === "login";
|
|
582
|
+
const showPageOverlay = mobileMenuOpen || openPanel != null || isMobilePanelClosingOut || activeUtilityDropdown != null;
|
|
583
|
+
const toggleUtilityDropdown = (kind) => {
|
|
584
|
+
const previous = openUtilityDropdown;
|
|
585
|
+
const next = previous === kind ? null : kind;
|
|
586
|
+
if (previous != null && previous !== next) {
|
|
587
|
+
notifyUtilityOpenChange(previous, false);
|
|
588
|
+
}
|
|
589
|
+
if (next != null) {
|
|
590
|
+
notifyUtilityOpenChange(next, true);
|
|
591
|
+
closeMobileMenu();
|
|
592
|
+
if (isCartOpen) {
|
|
593
|
+
if (!isCartControlled) {
|
|
594
|
+
internalCartOpenRef.current = false;
|
|
595
|
+
setInternalCartOpen(false);
|
|
596
|
+
}
|
|
597
|
+
onCartOpenChange?.(false);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
openUtilityDropdownRef.current = next;
|
|
601
|
+
setOpenUtilityDropdown(next);
|
|
602
|
+
};
|
|
603
|
+
const handleLanguageClick = () => {
|
|
604
|
+
toggleUtilityDropdown("language");
|
|
605
|
+
};
|
|
606
|
+
const handleSearchClick = () => {
|
|
607
|
+
toggleUtilityDropdown("search");
|
|
608
|
+
};
|
|
609
|
+
const handleLoginClick = () => {
|
|
610
|
+
toggleUtilityDropdown("login");
|
|
611
|
+
};
|
|
612
|
+
const handleCartClick = () => {
|
|
613
|
+
const next = !isCartOpen;
|
|
614
|
+
if (next) {
|
|
615
|
+
closeMenus();
|
|
616
|
+
}
|
|
617
|
+
if (!isCartControlled) {
|
|
618
|
+
internalCartOpenRef.current = next;
|
|
619
|
+
setInternalCartOpen(next);
|
|
620
|
+
}
|
|
621
|
+
onCartOpenChange?.(next);
|
|
622
|
+
};
|
|
623
|
+
const handleCartOpenChange = (open) => {
|
|
624
|
+
if (!isCartControlled) {
|
|
625
|
+
internalCartOpenRef.current = open;
|
|
626
|
+
setInternalCartOpen(open);
|
|
627
|
+
}
|
|
628
|
+
onCartOpenChange?.(open);
|
|
629
|
+
};
|
|
630
|
+
react.useEffect(() => {
|
|
631
|
+
if (isCartOpen) {
|
|
632
|
+
closeMenus();
|
|
633
|
+
}
|
|
634
|
+
}, [closeMenus, isCartOpen]);
|
|
635
|
+
react.useEffect(() => {
|
|
636
|
+
if (openUtilityDropdown != null && activeUtilityDropdown == null) {
|
|
637
|
+
closeUtilityDropdown();
|
|
638
|
+
}
|
|
639
|
+
}, [activeUtilityDropdown, closeUtilityDropdown, openUtilityDropdown]);
|
|
640
|
+
react.useEffect(() => {
|
|
641
|
+
if (!showCart && !isCartControlled && internalCartOpen && internalCartOpenRef.current) {
|
|
642
|
+
internalCartOpenRef.current = false;
|
|
643
|
+
setInternalCartOpen(false);
|
|
644
|
+
onCartOpenChange?.(false);
|
|
645
|
+
}
|
|
646
|
+
}, [internalCartOpen, isCartControlled, onCartOpenChange, showCart]);
|
|
472
647
|
react.useEffect(() => {
|
|
473
648
|
if (!showPageOverlay) {
|
|
474
649
|
return;
|
|
@@ -576,6 +751,7 @@ const MainNavigation = ({
|
|
|
576
751
|
closeTimeoutRef: mobileSecondPanelCloseTimeoutRef,
|
|
577
752
|
onClosed: () => {
|
|
578
753
|
const closedTopLevelItemIndex = openTopLevelItemIndex;
|
|
754
|
+
openTopLevelItemIndexRef.current = null;
|
|
579
755
|
setOpenTopLevelItemIndex(null);
|
|
580
756
|
setMobileActiveCategoryIndex(null);
|
|
581
757
|
onDesktopItemToggle?.(null);
|
|
@@ -911,7 +1087,7 @@ const MainNavigation = ({
|
|
|
911
1087
|
ref: setHeaderRef,
|
|
912
1088
|
className: cn.cn(
|
|
913
1089
|
MainNavigation_module["main-navigation"],
|
|
914
|
-
|
|
1090
|
+
isHeaderOpen && MainNavigation_module["main-navigation--open"],
|
|
915
1091
|
mobileMenuOpen && MainNavigation_module["main-navigation--menu-open"],
|
|
916
1092
|
isMobileMenuClosing && MainNavigation_module["main-navigation--menu-closing"],
|
|
917
1093
|
showPageOverlay && MainNavigation_module["main-navigation--overlay"],
|
|
@@ -921,6 +1097,21 @@ const MainNavigation = ({
|
|
|
921
1097
|
),
|
|
922
1098
|
...props,
|
|
923
1099
|
onKeyDown: (event) => {
|
|
1100
|
+
if (event.key === "Tab" && activeUtilityDropdown != null) {
|
|
1101
|
+
const focusLoopElements = getUtilityDropdownFocusLoopElements(activeUtilityDropdown);
|
|
1102
|
+
if (focusLoopElements.length > 1) {
|
|
1103
|
+
event.preventDefault();
|
|
1104
|
+
const currentIndex = focusLoopElements.indexOf(
|
|
1105
|
+
document.activeElement
|
|
1106
|
+
);
|
|
1107
|
+
const direction = event.shiftKey ? -1 : 1;
|
|
1108
|
+
const nextIndex = currentIndex === -1 ? event.shiftKey ? focusLoopElements.length - 1 : 0 : (currentIndex + direction + focusLoopElements.length) % focusLoopElements.length;
|
|
1109
|
+
focusLoopElements[nextIndex]?.focus();
|
|
1110
|
+
} else {
|
|
1111
|
+
closeUtilityDropdown();
|
|
1112
|
+
}
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
924
1115
|
if (event.key === "Tab" && mobileMenuOpen && !isDesktopViewport()) {
|
|
925
1116
|
const focusableElements = getMobileFocusableElements();
|
|
926
1117
|
if (focusableElements.length > 0) {
|
|
@@ -948,7 +1139,12 @@ const MainNavigation = ({
|
|
|
948
1139
|
}
|
|
949
1140
|
}
|
|
950
1141
|
if (event.key === "Escape") {
|
|
1142
|
+
const utilityDropdownToRestore = activeUtilityDropdown;
|
|
951
1143
|
closeMenus();
|
|
1144
|
+
if (utilityDropdownToRestore != null) {
|
|
1145
|
+
const triggerButton = utilityDropdownToRestore === "search" ? searchTriggerRef.current : utilityDropdownToRestore === "language" ? languageTriggerRef.current : loginTriggerRef.current;
|
|
1146
|
+
triggerButton?.focus();
|
|
1147
|
+
}
|
|
952
1148
|
}
|
|
953
1149
|
props.onKeyDown?.(event);
|
|
954
1150
|
},
|
|
@@ -1000,48 +1196,116 @@ const MainNavigation = ({
|
|
|
1000
1196
|
}
|
|
1001
1197
|
),
|
|
1002
1198
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: MainNavigation_module["main-navigation__icon-nav"], children: [
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1199
|
+
showLanguage && currentLanguage != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: MainNavigation_module["main-navigation__utility"], children: [
|
|
1200
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1201
|
+
"button",
|
|
1202
|
+
{
|
|
1203
|
+
ref: languageTriggerRef,
|
|
1204
|
+
type: "button",
|
|
1205
|
+
className: cn.cn(
|
|
1206
|
+
MainNavigation_module["main-navigation__icon-nav-item"],
|
|
1207
|
+
isLanguageOpen && MainNavigation_module["main-navigation__icon-nav-item--active"],
|
|
1208
|
+
focus_module.default.focusableInset
|
|
1209
|
+
),
|
|
1210
|
+
"aria-expanded": isLanguageOpen,
|
|
1211
|
+
"aria-controls": isLanguageOpen ? languageDropdownId : void 0,
|
|
1212
|
+
onClick: handleLanguageClick,
|
|
1213
|
+
children: [
|
|
1214
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.Globe, { "aria-hidden": "true" }),
|
|
1215
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1216
|
+
"span",
|
|
1217
|
+
{
|
|
1218
|
+
"aria-hidden": "true",
|
|
1219
|
+
className: MainNavigation_module["main-navigation__icon-nav-label"],
|
|
1220
|
+
children: currentLanguage.code.toUpperCase()
|
|
1221
|
+
}
|
|
1222
|
+
),
|
|
1223
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: MainNavigation_module["main-navigation__sr-only"], children: languageAnnouncements.map((announcement, index) => /* @__PURE__ */ jsxRuntime.jsxs(react.Fragment, { children: [
|
|
1224
|
+
index > 0 ? " " : null,
|
|
1225
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { lang: announcement.lang, children: announcement.text })
|
|
1226
|
+
] }, announcement.lang)) })
|
|
1227
|
+
]
|
|
1228
|
+
}
|
|
1229
|
+
),
|
|
1230
|
+
isLanguageOpen && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1231
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1232
|
+
"span",
|
|
1233
|
+
{
|
|
1234
|
+
"aria-hidden": "true",
|
|
1235
|
+
className: MainNavigation_module["main-navigation__dropdown-caret"]
|
|
1236
|
+
}
|
|
1026
1237
|
),
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1238
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1239
|
+
"div",
|
|
1240
|
+
{
|
|
1241
|
+
id: languageDropdownId,
|
|
1242
|
+
className: cn.cn(
|
|
1243
|
+
MainNavigation_module["main-navigation__dropdown"],
|
|
1244
|
+
MainNavigation_module["main-navigation__dropdown--language"],
|
|
1245
|
+
elevation_module.default.elevationMedium
|
|
1246
|
+
),
|
|
1247
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("ul", { className: MainNavigation_module["main-navigation__language-list"], children: alternativeLanguages.map((language) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1248
|
+
"li",
|
|
1249
|
+
{
|
|
1250
|
+
className: MainNavigation_module["main-navigation__language-list-item"],
|
|
1251
|
+
children: renderLanguageLink({
|
|
1252
|
+
href: MainNavigation_utils.toNavigableHref(language.href),
|
|
1253
|
+
lang: language.code,
|
|
1254
|
+
"aria-label": language.ariaLabel ?? MainNavigation_utils.languageLinkAriaLabels[language.code],
|
|
1255
|
+
className: cn.cn(
|
|
1256
|
+
MainNavigation_module["main-navigation__language-link"],
|
|
1257
|
+
focus_module.default.focusable
|
|
1258
|
+
),
|
|
1259
|
+
children: language.code.toUpperCase()
|
|
1260
|
+
})
|
|
1261
|
+
},
|
|
1262
|
+
language.code
|
|
1263
|
+
)) })
|
|
1264
|
+
}
|
|
1265
|
+
)
|
|
1266
|
+
] })
|
|
1267
|
+
] }),
|
|
1268
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: MainNavigation_module["main-navigation__utility"], children: [
|
|
1269
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1270
|
+
"button",
|
|
1271
|
+
{
|
|
1272
|
+
ref: searchTriggerRef,
|
|
1273
|
+
type: "button",
|
|
1274
|
+
className: cn.cn(
|
|
1275
|
+
MainNavigation_module["main-navigation__icon-nav-item"],
|
|
1276
|
+
isSearchOpen && MainNavigation_module["main-navigation__icon-nav-item--active"],
|
|
1277
|
+
focus_module.default.focusableInset
|
|
1278
|
+
),
|
|
1279
|
+
"aria-label": searchLabel,
|
|
1280
|
+
"aria-expanded": isSearchOpen,
|
|
1281
|
+
"aria-controls": isSearchOpen ? searchDropdownId : void 0,
|
|
1282
|
+
onClick: handleSearchClick,
|
|
1283
|
+
children: [
|
|
1284
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.Search, {}),
|
|
1285
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: MainNavigation_module["main-navigation__icon-nav-label"], children: searchLabel })
|
|
1286
|
+
]
|
|
1287
|
+
}
|
|
1288
|
+
),
|
|
1289
|
+
isSearchOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1290
|
+
"span",
|
|
1291
|
+
{
|
|
1292
|
+
"aria-hidden": "true",
|
|
1293
|
+
className: MainNavigation_module["main-navigation__dropdown-caret"]
|
|
1294
|
+
}
|
|
1295
|
+
)
|
|
1296
|
+
] }),
|
|
1035
1297
|
showCart && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1036
1298
|
"button",
|
|
1037
1299
|
{
|
|
1038
1300
|
type: "button",
|
|
1039
1301
|
className: cn.cn(
|
|
1040
1302
|
MainNavigation_module["main-navigation__icon-nav-item"],
|
|
1303
|
+
isCartOpen && MainNavigation_module["main-navigation__icon-nav-item--active"],
|
|
1041
1304
|
focus_module.default.focusableInset
|
|
1042
1305
|
),
|
|
1043
1306
|
"aria-label": cartAccessibleLabel,
|
|
1044
|
-
|
|
1307
|
+
"aria-expanded": isCartOpen,
|
|
1308
|
+
onClick: handleCartClick,
|
|
1045
1309
|
children: [
|
|
1046
1310
|
/* @__PURE__ */ jsxRuntime.jsx(icons.Cart, {}),
|
|
1047
1311
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: MainNavigation_module["main-navigation__icon-nav-label"], children: cartLabel }),
|
|
@@ -1056,16 +1320,53 @@ const MainNavigation = ({
|
|
|
1056
1320
|
]
|
|
1057
1321
|
}
|
|
1058
1322
|
),
|
|
1059
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1323
|
+
showLogin && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: MainNavigation_module["main-navigation__utility"], children: [
|
|
1324
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1325
|
+
Button.Button,
|
|
1326
|
+
{
|
|
1327
|
+
ref: loginTriggerRef,
|
|
1328
|
+
size: "small",
|
|
1329
|
+
"aria-expanded": isLoginOpen,
|
|
1330
|
+
"aria-controls": isLoginOpen ? loginDropdownId : void 0,
|
|
1331
|
+
onClick: handleLoginClick,
|
|
1332
|
+
children: loginLabel
|
|
1333
|
+
}
|
|
1334
|
+
),
|
|
1335
|
+
isLoginOpen && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1336
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1337
|
+
"span",
|
|
1338
|
+
{
|
|
1339
|
+
"aria-hidden": "true",
|
|
1340
|
+
className: MainNavigation_module["main-navigation__dropdown-caret"]
|
|
1341
|
+
}
|
|
1342
|
+
),
|
|
1343
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1344
|
+
"div",
|
|
1345
|
+
{
|
|
1346
|
+
id: loginDropdownId,
|
|
1347
|
+
className: cn.cn(
|
|
1348
|
+
MainNavigation_module["main-navigation__dropdown"],
|
|
1349
|
+
MainNavigation_module["main-navigation__dropdown--login"],
|
|
1350
|
+
elevation_module.default.elevationMedium
|
|
1351
|
+
),
|
|
1352
|
+
children: loginDropdownContent
|
|
1353
|
+
}
|
|
1354
|
+
)
|
|
1355
|
+
] })
|
|
1356
|
+
] })
|
|
1068
1357
|
] }),
|
|
1358
|
+
showSearch && isSearchOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1359
|
+
"div",
|
|
1360
|
+
{
|
|
1361
|
+
id: searchDropdownId,
|
|
1362
|
+
className: cn.cn(
|
|
1363
|
+
MainNavigation_module["main-navigation__dropdown"],
|
|
1364
|
+
MainNavigation_module["main-navigation__dropdown--search"],
|
|
1365
|
+
elevation_module.default.elevationMedium
|
|
1366
|
+
),
|
|
1367
|
+
children: searchDropdownContent
|
|
1368
|
+
}
|
|
1369
|
+
),
|
|
1069
1370
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1070
1371
|
"button",
|
|
1071
1372
|
{
|
|
@@ -1085,6 +1386,16 @@ const MainNavigation = ({
|
|
|
1085
1386
|
] }),
|
|
1086
1387
|
!mobileMenuOpen && renderPanel(
|
|
1087
1388
|
cn.cn(MainNavigation_module["main-navigation__panel"], MainNavigation_module["main-navigation__panel--desktop"])
|
|
1389
|
+
),
|
|
1390
|
+
showCart && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1391
|
+
Drawer.Drawer,
|
|
1392
|
+
{
|
|
1393
|
+
open: isCartOpen,
|
|
1394
|
+
onOpenChange: handleCartOpenChange,
|
|
1395
|
+
title: cartLabel,
|
|
1396
|
+
size: "small",
|
|
1397
|
+
children: cartContent
|
|
1398
|
+
}
|
|
1088
1399
|
)
|
|
1089
1400
|
]
|
|
1090
1401
|
}
|