@orangesk/orange-design-system 3.9.0 → 3.11.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/build/components/AnchorNavigation/style.css +1 -1
- package/build/components/AnchorNavigation/style.css.map +1 -1
- package/build/components/Carousel/style.css +1 -1
- package/build/components/Carousel/style.css.map +1 -1
- package/build/components/Megamenu/style.css +1 -1
- package/build/components/Megamenu/style.css.map +1 -1
- package/build/components/index.js +1 -1
- package/build/components/index.js.map +1 -1
- package/build/components/types/index.d.ts +6 -2
- package/build/footer-sprite-dark.svg +1 -0
- package/build/footer-sprite-light.svg +1 -0
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/megamenu.css +1 -1
- package/build/lib/megamenu.css.map +1 -1
- package/build/lib/scripts.js +1 -1
- package/build/lib/scripts.js.map +1 -1
- package/build/lib/style.css +1 -1
- package/build/lib/style.css.map +1 -1
- package/build/megamenu-sprite-dark.svg +1 -0
- package/build/megamenu-sprite-light.svg +1 -0
- package/package.json +27 -27
- package/public/footer-sprite-dark.svg +1 -0
- package/public/footer-sprite-light.svg +1 -0
- package/src/assets/footer/appstore.svg +31 -0
- package/src/assets/footer/googleplay.svg +52 -0
- package/src/assets/footer/logo.svg +33 -0
- package/src/{components/Footer/PlanObnovy.tsx → assets/footer/plan-obnovy.svg} +53 -211
- package/src/assets/megamenu/input-search.svg +1 -0
- package/src/assets/megamenu/input-valid.svg +1 -0
- package/src/assets/megamenu/logo-line.svg +5 -0
- package/src/assets/megamenu/megamenu-logo.svg +61 -0
- package/src/assets/megamenu/store-apple--white.svg +5 -0
- package/src/assets/megamenu/store-apple.svg +4 -0
- package/src/assets/megamenu/store-huawei--white.svg +5 -0
- package/src/assets/megamenu/store-huawei.svg +4 -0
- package/src/assets/megamenu/store-play--white.svg +7 -0
- package/src/assets/megamenu/store-play.svg +7 -0
- package/src/components/AnchorNavigation/styles/mixins.scss +7 -9
- package/src/components/BlockAction/CloneElementWithClassName.tsx +10 -7
- package/src/components/BlockAction/tests/CloneElementWithClassName.unit.test.jsx +28 -1
- package/src/components/Carousel/Carousel.static.ts +111 -14
- package/src/components/Carousel/Carousel.tsx +35 -12
- package/src/components/Carousel/constants.ts +2 -0
- package/src/components/Carousel/styles/mixins.scss +61 -0
- package/src/components/Carousel/styles/style.scss +7 -0
- package/src/components/Carousel/tests/Carousel.lifecycle.test.ts +223 -0
- package/src/components/Footer/Footer.tsx +44 -54
- package/src/components/Footer/FooterIcon.tsx +12 -0
- package/src/components/Footer/data.ts +4 -2
- package/src/components/Footer/tests/Footer.unit.test.jsx +63 -0
- package/src/components/Forms/TextInput/styles/mixins.scss +4 -2
- package/src/components/Megamenu/Logo.tsx +7 -7
- package/src/components/Megamenu/LogoJeTu.tsx +6 -58
- package/src/components/Megamenu/MegaMenuIcon.tsx +20 -11
- package/src/components/Megamenu/Megamenu.tsx +58 -48
- package/src/components/Megamenu/MegamenuBlog.tsx +14 -2
- package/src/components/Megamenu/MegamenuSearchContent.tsx +13 -0
- package/src/components/Megamenu/MyOrangeMobilePanel.tsx +3 -9
- package/src/components/Megamenu/styles/mixins.scss +21 -34
- package/src/components/Megamenu/tests/Megamenu.unit.test.jsx +158 -0
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
import type { MegamenuTile, MenuItem, MenuSection } from "./data";
|
|
59
59
|
import { megamenuTiles, menuSections } from "./data";
|
|
60
60
|
import { getMegamenuIds } from "./ids";
|
|
61
|
-
import { MegamenuIcon } from "./MegaMenuIcon";
|
|
61
|
+
import { MegamenuIcon, MegamenuSpritePathProvider } from "./MegaMenuIcon";
|
|
62
62
|
import { MegamenuSearchContent } from "./MegamenuSearchContent";
|
|
63
63
|
import { MyOrangeMobilePanel } from "./MyOrangeMobilePanel";
|
|
64
64
|
import {
|
|
@@ -79,6 +79,8 @@ export type MegamenuProps = {
|
|
|
79
79
|
isB2B?: boolean;
|
|
80
80
|
/** Controls whether My Orange panel shows logged-in or logged-out content. */
|
|
81
81
|
isLoggedIn?: boolean;
|
|
82
|
+
/** Replaces My Orange panel triggers with links and omits the account panel. */
|
|
83
|
+
myOrangeHref?: string;
|
|
82
84
|
/** Number of items displayed on the cart badge. Empty cart when omitted or zero. */
|
|
83
85
|
cartItems?: number;
|
|
84
86
|
/** Shows an orange dot for a non-empty cart when item count is unavailable. */
|
|
@@ -229,6 +231,7 @@ export const Megamenu = ({
|
|
|
229
231
|
compactLogoOnly = false,
|
|
230
232
|
isB2B = false,
|
|
231
233
|
isLoggedIn = true,
|
|
234
|
+
myOrangeHref,
|
|
232
235
|
cartItems,
|
|
233
236
|
cartHasItems = false,
|
|
234
237
|
tiles = megamenuTiles,
|
|
@@ -239,7 +242,36 @@ export const Megamenu = ({
|
|
|
239
242
|
const hasCartItems = cartItems !== undefined && cartItems > 0;
|
|
240
243
|
const showCartDot = cartHasItems && !hasCartItems;
|
|
241
244
|
|
|
242
|
-
|
|
245
|
+
const myOrangeContent = (
|
|
246
|
+
<>
|
|
247
|
+
<MegamenuIcon
|
|
248
|
+
width={24}
|
|
249
|
+
height={24}
|
|
250
|
+
name="user"
|
|
251
|
+
className={CLASS_NAV_ICON}
|
|
252
|
+
aria-hidden="true"
|
|
253
|
+
/>
|
|
254
|
+
Môj Orange
|
|
255
|
+
</>
|
|
256
|
+
);
|
|
257
|
+
const myOrangeControl = myOrangeHref ? (
|
|
258
|
+
<a href={myOrangeHref} className={CLASS_NAV_BUTTON}>
|
|
259
|
+
{myOrangeContent}
|
|
260
|
+
</a>
|
|
261
|
+
) : (
|
|
262
|
+
<button
|
|
263
|
+
type="button"
|
|
264
|
+
className={CLASS_NAV_BUTTON}
|
|
265
|
+
data-megamenu-mobile-toggle
|
|
266
|
+
data-megamenu-mobile-target="my-orange"
|
|
267
|
+
aria-haspopup="dialog"
|
|
268
|
+
aria-expanded="false"
|
|
269
|
+
>
|
|
270
|
+
{myOrangeContent}
|
|
271
|
+
</button>
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
const content = (
|
|
243
275
|
<header>
|
|
244
276
|
<nav
|
|
245
277
|
className={cx(CLASS_ROOT, className, {
|
|
@@ -391,7 +423,7 @@ export const Megamenu = ({
|
|
|
391
423
|
<MegamenuIcon
|
|
392
424
|
width={16}
|
|
393
425
|
height={16}
|
|
394
|
-
name="rewards"
|
|
426
|
+
name="rewards-accent"
|
|
395
427
|
className={CLASS_NAV_ICON_CTA}
|
|
396
428
|
aria-hidden="true"
|
|
397
429
|
/>
|
|
@@ -468,25 +500,7 @@ export const Megamenu = ({
|
|
|
468
500
|
) : null}
|
|
469
501
|
</a>
|
|
470
502
|
</li>
|
|
471
|
-
<li className={CLASS_NAV_ITEM}>
|
|
472
|
-
<button
|
|
473
|
-
type="button"
|
|
474
|
-
className={CLASS_NAV_BUTTON}
|
|
475
|
-
data-megamenu-mobile-toggle
|
|
476
|
-
data-megamenu-mobile-target="my-orange"
|
|
477
|
-
aria-haspopup="dialog"
|
|
478
|
-
aria-expanded="false"
|
|
479
|
-
>
|
|
480
|
-
<MegamenuIcon
|
|
481
|
-
width={24}
|
|
482
|
-
height={24}
|
|
483
|
-
name="user"
|
|
484
|
-
className={CLASS_NAV_ICON}
|
|
485
|
-
aria-hidden="true"
|
|
486
|
-
/>
|
|
487
|
-
Môj Orange
|
|
488
|
-
</button>
|
|
489
|
-
</li>
|
|
503
|
+
<li className={CLASS_NAV_ITEM}>{myOrangeControl}</li>
|
|
490
504
|
<li className={cx(CLASS_NAV_ITEM, CLASS_HIDE_LG_UP)}>
|
|
491
505
|
<button
|
|
492
506
|
type="button"
|
|
@@ -639,7 +653,7 @@ export const Megamenu = ({
|
|
|
639
653
|
<MegamenuIcon
|
|
640
654
|
width={16}
|
|
641
655
|
height={16}
|
|
642
|
-
name="rewards"
|
|
656
|
+
name="rewards-accent"
|
|
643
657
|
className={CLASS_NAV_ICON_CTA}
|
|
644
658
|
aria-hidden="true"
|
|
645
659
|
/>
|
|
@@ -657,25 +671,7 @@ export const Megamenu = ({
|
|
|
657
671
|
role="group"
|
|
658
672
|
aria-labelledby="mobile-quick-access-heading"
|
|
659
673
|
>
|
|
660
|
-
<li className={CLASS_NAV_ITEM}>
|
|
661
|
-
<button
|
|
662
|
-
type="button"
|
|
663
|
-
className={CLASS_NAV_BUTTON}
|
|
664
|
-
data-megamenu-mobile-toggle
|
|
665
|
-
data-megamenu-mobile-target="my-orange"
|
|
666
|
-
aria-haspopup="dialog"
|
|
667
|
-
aria-expanded="false"
|
|
668
|
-
>
|
|
669
|
-
<MegamenuIcon
|
|
670
|
-
width={24}
|
|
671
|
-
height={24}
|
|
672
|
-
name="user"
|
|
673
|
-
className={CLASS_NAV_ICON}
|
|
674
|
-
aria-hidden="true"
|
|
675
|
-
/>
|
|
676
|
-
Môj Orange
|
|
677
|
-
</button>
|
|
678
|
-
</li>
|
|
674
|
+
<li className={CLASS_NAV_ITEM}>{myOrangeControl}</li>
|
|
679
675
|
<li className={CLASS_NAV_ITEM}>
|
|
680
676
|
<a href="/" className={CLASS_NAV_BUTTON}>
|
|
681
677
|
<MegamenuIcon
|
|
@@ -751,12 +747,14 @@ export const Megamenu = ({
|
|
|
751
747
|
</div>
|
|
752
748
|
</MegamenuMobilePanel>
|
|
753
749
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
750
|
+
{!myOrangeHref ? (
|
|
751
|
+
<MyOrangeMobilePanel
|
|
752
|
+
panelId={ids.myOrangePanelId}
|
|
753
|
+
titleId={ids.myOrangeTitleId}
|
|
754
|
+
isB2B={isB2B}
|
|
755
|
+
isLoggedIn={isLoggedIn}
|
|
756
|
+
/>
|
|
757
|
+
) : null}
|
|
760
758
|
|
|
761
759
|
<button
|
|
762
760
|
aria-label="Zatvoriť dropdown menu"
|
|
@@ -767,4 +765,16 @@ export const Megamenu = ({
|
|
|
767
765
|
<div className={CLASS_SPACER} aria-hidden="true" />
|
|
768
766
|
</header>
|
|
769
767
|
);
|
|
768
|
+
|
|
769
|
+
return (
|
|
770
|
+
<MegamenuSpritePathProvider
|
|
771
|
+
value={
|
|
772
|
+
isB2B || className?.split(/\s+/).includes("is-dark")
|
|
773
|
+
? "/megamenu-sprite-dark.svg"
|
|
774
|
+
: "/megamenu-sprite-light.svg"
|
|
775
|
+
}
|
|
776
|
+
>
|
|
777
|
+
{content}
|
|
778
|
+
</MegamenuSpritePathProvider>
|
|
779
|
+
);
|
|
770
780
|
};
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
CLASS_TAG_TRANSPARENT,
|
|
31
31
|
} from "./constants";
|
|
32
32
|
import { getMegamenuIds } from "./ids";
|
|
33
|
-
import { MegamenuIcon } from "./MegaMenuIcon";
|
|
33
|
+
import { MegamenuIcon, MegamenuSpritePathProvider } from "./MegaMenuIcon";
|
|
34
34
|
import type { MegamenuProps } from "./Megamenu";
|
|
35
35
|
import { MegamenuSearchContent } from "./MegamenuSearchContent";
|
|
36
36
|
import { MyOrangeMobilePanel } from "./MyOrangeMobilePanel";
|
|
@@ -63,7 +63,7 @@ export const MegamenuBlog = ({
|
|
|
63
63
|
const { hasSearchEmpty, hasSearchFilled, showSearchState, searchValue } =
|
|
64
64
|
getMegamenuSearchState(searchEmpty, searchFilled);
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
const content = (
|
|
67
67
|
<header>
|
|
68
68
|
<nav
|
|
69
69
|
className={cx(CLASS_ROOT, className, {
|
|
@@ -392,4 +392,16 @@ export const MegamenuBlog = ({
|
|
|
392
392
|
<div className={CLASS_SPACER_SMALL} aria-hidden="true" />
|
|
393
393
|
</header>
|
|
394
394
|
);
|
|
395
|
+
|
|
396
|
+
return (
|
|
397
|
+
<MegamenuSpritePathProvider
|
|
398
|
+
value={
|
|
399
|
+
isB2B || className?.split(/\s+/).includes("is-dark")
|
|
400
|
+
? "/megamenu-sprite-dark.svg"
|
|
401
|
+
: "/megamenu-sprite-light.svg"
|
|
402
|
+
}
|
|
403
|
+
>
|
|
404
|
+
{content}
|
|
405
|
+
</MegamenuSpritePathProvider>
|
|
406
|
+
);
|
|
395
407
|
};
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
CLASS_TAG,
|
|
13
13
|
} from "./constants";
|
|
14
14
|
import { searchResultItems, searchTerms } from "./data";
|
|
15
|
+
import { MegamenuIcon } from "./MegaMenuIcon";
|
|
15
16
|
|
|
16
17
|
type MegamenuSearchContentProps = {
|
|
17
18
|
inputId: string;
|
|
@@ -43,6 +44,12 @@ export const MegamenuSearchContent = ({
|
|
|
43
44
|
CLASS_INPUT_WRAPPER_SEARCH_ICON_WITH_PLACEHOLDER,
|
|
44
45
|
)}
|
|
45
46
|
>
|
|
47
|
+
<MegamenuIcon
|
|
48
|
+
name="input-search"
|
|
49
|
+
className="megamenu__input-search-icon"
|
|
50
|
+
width={20}
|
|
51
|
+
height={20}
|
|
52
|
+
/>
|
|
46
53
|
<input
|
|
47
54
|
className={CLASS_INPUT}
|
|
48
55
|
id={inputId}
|
|
@@ -51,6 +58,12 @@ export const MegamenuSearchContent = ({
|
|
|
51
58
|
name="search"
|
|
52
59
|
defaultValue={searchValue}
|
|
53
60
|
/>
|
|
61
|
+
<MegamenuIcon
|
|
62
|
+
name="input-valid"
|
|
63
|
+
className="megamenu__input-status-icon"
|
|
64
|
+
width={16}
|
|
65
|
+
height={16}
|
|
66
|
+
/>
|
|
54
67
|
</span>
|
|
55
68
|
|
|
56
69
|
{hasSearchEmpty ? (
|
|
@@ -133,27 +133,21 @@ export const MyOrangeMobilePanel = ({
|
|
|
133
133
|
className={CLASS_MOBILE_APP_CARD_STORE}
|
|
134
134
|
aria-label="Stiahnuť aplikáciu z App Store"
|
|
135
135
|
>
|
|
136
|
-
<
|
|
137
|
-
src={isB2B ? "/apple--white.svg" : "/apple.svg"}
|
|
138
|
-
alt=""
|
|
139
|
-
/>
|
|
136
|
+
<MegamenuIcon name="store-apple" width={24} height={25} />
|
|
140
137
|
</a>
|
|
141
138
|
<a
|
|
142
139
|
href="#"
|
|
143
140
|
className={CLASS_MOBILE_APP_CARD_STORE}
|
|
144
141
|
aria-label="Stiahnuť aplikáciu z Google Play"
|
|
145
142
|
>
|
|
146
|
-
<
|
|
143
|
+
<MegamenuIcon name="store-play" width={24} height={24} />
|
|
147
144
|
</a>
|
|
148
145
|
<a
|
|
149
146
|
href="#"
|
|
150
147
|
className={CLASS_MOBILE_APP_CARD_STORE}
|
|
151
148
|
aria-label="Stiahnuť aplikáciu z Huawei AppGallery"
|
|
152
149
|
>
|
|
153
|
-
<
|
|
154
|
-
src={isB2B ? "/huawei--white.svg" : "/huawei.svg"}
|
|
155
|
-
alt=""
|
|
156
|
-
/>
|
|
150
|
+
<MegamenuIcon name="store-huawei" width={24} height={24} />
|
|
157
151
|
</a>
|
|
158
152
|
</div>
|
|
159
153
|
</div>
|
|
@@ -528,6 +528,7 @@
|
|
|
528
528
|
&:focus,
|
|
529
529
|
&:active,
|
|
530
530
|
&.is-active {
|
|
531
|
+
color: var(--color-text-default) !important;
|
|
531
532
|
box-shadow: config.$active-line;
|
|
532
533
|
}
|
|
533
534
|
|
|
@@ -951,7 +952,8 @@
|
|
|
951
952
|
align-items: center;
|
|
952
953
|
height: convert.to-rem(40px);
|
|
953
954
|
|
|
954
|
-
img
|
|
955
|
+
img,
|
|
956
|
+
svg {
|
|
955
957
|
display: block;
|
|
956
958
|
width: auto;
|
|
957
959
|
max-width: convert.to-rem(52px);
|
|
@@ -1107,34 +1109,6 @@
|
|
|
1107
1109
|
fill: currentColor;
|
|
1108
1110
|
display: inline-block;
|
|
1109
1111
|
vertical-align: middle;
|
|
1110
|
-
|
|
1111
|
-
&__use {
|
|
1112
|
-
display: inline;
|
|
1113
|
-
|
|
1114
|
-
// Light theme (default) - show only light version
|
|
1115
|
-
&--light {
|
|
1116
|
-
display: inline;
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
&--dark {
|
|
1120
|
-
display: none;
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
// Dark theme context - show only dark version
|
|
1125
|
-
.is-dark &,
|
|
1126
|
-
[data-theme="dark"] &,
|
|
1127
|
-
.dark & {
|
|
1128
|
-
&__use {
|
|
1129
|
-
&--light {
|
|
1130
|
-
display: none;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
&--dark {
|
|
1134
|
-
display: inline;
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
1112
|
}
|
|
1139
1113
|
|
|
1140
1114
|
@mixin overlay {
|
|
@@ -1270,7 +1244,7 @@
|
|
|
1270
1244
|
|
|
1271
1245
|
@mixin input {
|
|
1272
1246
|
@include input.base();
|
|
1273
|
-
@include input.states();
|
|
1247
|
+
@include input.states($valid-icon: false);
|
|
1274
1248
|
max-width: unset !important;
|
|
1275
1249
|
margin-bottom: convert.to-rem(30px);
|
|
1276
1250
|
|
|
@@ -1301,16 +1275,14 @@
|
|
|
1301
1275
|
&--search-icon-with-placeholder {
|
|
1302
1276
|
isolation: isolate;
|
|
1303
1277
|
|
|
1304
|
-
|
|
1305
|
-
content: "";
|
|
1278
|
+
.megamenu__input-search-icon {
|
|
1306
1279
|
position: absolute;
|
|
1307
1280
|
top: 50%;
|
|
1308
1281
|
left: convert.to-rem(8px);
|
|
1309
1282
|
width: convert.to-rem(20px);
|
|
1310
1283
|
height: convert.to-rem(20px);
|
|
1311
1284
|
transform: translateY(-50%);
|
|
1312
|
-
|
|
1313
|
-
background-repeat: no-repeat;
|
|
1285
|
+
color: #f15e00;
|
|
1314
1286
|
pointer-events: none;
|
|
1315
1287
|
z-index: 2;
|
|
1316
1288
|
}
|
|
@@ -1320,6 +1292,21 @@
|
|
|
1320
1292
|
padding-left: convert.to-rem(40px);
|
|
1321
1293
|
margin-bottom: 0;
|
|
1322
1294
|
}
|
|
1295
|
+
|
|
1296
|
+
.megamenu__input-status-icon {
|
|
1297
|
+
position: absolute;
|
|
1298
|
+
top: 50%;
|
|
1299
|
+
right: convert.to-rem(10px);
|
|
1300
|
+
width: convert.to-rem(16px);
|
|
1301
|
+
height: convert.to-rem(16px);
|
|
1302
|
+
transform: translateY(-50%);
|
|
1303
|
+
pointer-events: none;
|
|
1304
|
+
z-index: 2;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
#{config.$class-root}__input:not(.is-valid) ~ .megamenu__input-status-icon {
|
|
1308
|
+
display: none;
|
|
1309
|
+
}
|
|
1323
1310
|
}
|
|
1324
1311
|
|
|
1325
1312
|
&--search-responsive {
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
2
|
+
|
|
1
3
|
import { render } from "@testing-library/react";
|
|
2
4
|
import "@testing-library/jest-dom/vitest";
|
|
3
5
|
|
|
4
6
|
import { Megamenu, MegamenuBlog } from "../";
|
|
7
|
+
import MegamenuController from "../Megamenu.static";
|
|
5
8
|
|
|
6
9
|
describe("Megamenu logo markup", () => {
|
|
7
10
|
it("separates top links from the language switcher without a spacer item", () => {
|
|
@@ -148,6 +151,56 @@ describe("Megamenu logo markup", () => {
|
|
|
148
151
|
expect(container).not.toHaveTextContent("0905 123 456");
|
|
149
152
|
});
|
|
150
153
|
|
|
154
|
+
it.each([false, true])(
|
|
155
|
+
"renders My Orange as SSO links without account panel markup (B2B: %s)",
|
|
156
|
+
(isB2B) => {
|
|
157
|
+
const { container } = render(
|
|
158
|
+
<Megamenu
|
|
159
|
+
isLoggedIn={false}
|
|
160
|
+
myOrangeHref="/sso"
|
|
161
|
+
isB2B={isB2B}
|
|
162
|
+
notSticky
|
|
163
|
+
/>,
|
|
164
|
+
);
|
|
165
|
+
const links = container.querySelectorAll('a[href="/sso"]');
|
|
166
|
+
|
|
167
|
+
expect(links).toHaveLength(2);
|
|
168
|
+
for (const link of links) {
|
|
169
|
+
expect(link).toHaveTextContent("Môj Orange");
|
|
170
|
+
expect(link).not.toHaveAttribute("data-megamenu-mobile-toggle");
|
|
171
|
+
expect(link).not.toHaveAttribute("aria-haspopup");
|
|
172
|
+
expect(link).not.toHaveAttribute("aria-expanded");
|
|
173
|
+
}
|
|
174
|
+
expect(
|
|
175
|
+
container.querySelector('[data-megamenu-mobile-target="my-orange"]'),
|
|
176
|
+
).toBeNull();
|
|
177
|
+
expect(
|
|
178
|
+
container.querySelector('[data-megamenu-mobile-panel="my-orange"]'),
|
|
179
|
+
).toBeNull();
|
|
180
|
+
expect(container.querySelector(".megamenu__mobile-account")).toBeNull();
|
|
181
|
+
expect(
|
|
182
|
+
container.querySelector('[data-megamenu-mobile-panel="main"]'),
|
|
183
|
+
).toBeInTheDocument();
|
|
184
|
+
|
|
185
|
+
const controller = new MegamenuController(
|
|
186
|
+
container.querySelector("[data-megamenu]"),
|
|
187
|
+
);
|
|
188
|
+
try {
|
|
189
|
+
container.querySelector('[data-megamenu-mobile-target="main"]').click();
|
|
190
|
+
expect(
|
|
191
|
+
container.querySelector('[data-megamenu-mobile-panel="main"]'),
|
|
192
|
+
).toHaveAttribute("aria-hidden", "false");
|
|
193
|
+
expect(links[0]).toHaveAttribute("href", "/sso");
|
|
194
|
+
controller.closeMobileMenu();
|
|
195
|
+
expect(
|
|
196
|
+
container.querySelector('[data-megamenu-mobile-panel="main"]'),
|
|
197
|
+
).toHaveAttribute("aria-hidden", "true");
|
|
198
|
+
} finally {
|
|
199
|
+
controller.destroy();
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
);
|
|
203
|
+
|
|
151
204
|
it("renders optional cart item count", () => {
|
|
152
205
|
const { container } = render(<Megamenu cartItems={3} notSticky />);
|
|
153
206
|
|
|
@@ -175,3 +228,108 @@ describe("Megamenu logo markup", () => {
|
|
|
175
228
|
expect(cart?.nextElementSibling).not.toBeInTheDocument();
|
|
176
229
|
});
|
|
177
230
|
});
|
|
231
|
+
|
|
232
|
+
describe("Megamenu vendor sprite markup", () => {
|
|
233
|
+
it.each([
|
|
234
|
+
["main B2C", Megamenu, false],
|
|
235
|
+
["main B2B", Megamenu, true],
|
|
236
|
+
["blog B2C", MegamenuBlog, false],
|
|
237
|
+
["blog B2B", MegamenuBlog, true],
|
|
238
|
+
])(
|
|
239
|
+
"resolves every SVG in %s through the external sprite",
|
|
240
|
+
(_, Component, isB2B) => {
|
|
241
|
+
const spritePath = `/megamenu-sprite-${isB2B ? "dark" : "light"}.svg`;
|
|
242
|
+
const sprite = new DOMParser().parseFromString(
|
|
243
|
+
readFileSync(`public${spritePath}`, "utf8"),
|
|
244
|
+
"image/svg+xml",
|
|
245
|
+
);
|
|
246
|
+
const { container } = render(
|
|
247
|
+
<Component isB2B={isB2B} className={isB2B ? "is-dark" : undefined} />,
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
expect(
|
|
251
|
+
container.querySelector("svg path, svg rect, svg circle"),
|
|
252
|
+
).toBeNull();
|
|
253
|
+
expect(container.querySelector('img[src$=".svg"]')).toBeNull();
|
|
254
|
+
for (const use of container.querySelectorAll("svg use")) {
|
|
255
|
+
const href = use.getAttribute("href") || use.getAttribute("xlink:href");
|
|
256
|
+
expect(href).toMatch(new RegExp(`^${spritePath}#`));
|
|
257
|
+
expect(use.parentElement.querySelectorAll("use")).toHaveLength(1);
|
|
258
|
+
expect(sprite.getElementById(href.split("#")[1])).not.toBeNull();
|
|
259
|
+
}
|
|
260
|
+
for (const wrapper of container.querySelectorAll(
|
|
261
|
+
".megamenu__input-wrapper",
|
|
262
|
+
)) {
|
|
263
|
+
expect(
|
|
264
|
+
wrapper.querySelector(".megamenu__input-search-icon use"),
|
|
265
|
+
).not.toBeNull();
|
|
266
|
+
expect(
|
|
267
|
+
wrapper.querySelector(".megamenu__input-status-icon use"),
|
|
268
|
+
).not.toBeNull();
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
describe("Megamenu dedicated sprites", () => {
|
|
275
|
+
it("keeps megamenu-owned sources and symbols out of the global sprite", () => {
|
|
276
|
+
const globalSprite = new DOMParser().parseFromString(
|
|
277
|
+
readFileSync("public/sprite.svg", "utf8"),
|
|
278
|
+
"image/svg+xml",
|
|
279
|
+
);
|
|
280
|
+
const sources = readdirSync("src/assets/megamenu").filter((file) =>
|
|
281
|
+
file.endsWith(".svg"),
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
expect(sources.length).toBeGreaterThan(0);
|
|
285
|
+
for (const file of sources) {
|
|
286
|
+
expect(existsSync(`src/assets/icons/${file}`), file).toBe(false);
|
|
287
|
+
expect(globalSprite.getElementById(file.slice(0, -4)), file).toBeNull();
|
|
288
|
+
}
|
|
289
|
+
expect(globalSprite.getElementById("rewards-accent")).toBeNull();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("ships matching symbol IDs with theme colors and no unrelated global icons", () => {
|
|
293
|
+
const parse = (theme) =>
|
|
294
|
+
new DOMParser().parseFromString(
|
|
295
|
+
readFileSync(`public/megamenu-sprite-${theme}.svg`, "utf8"),
|
|
296
|
+
"image/svg+xml",
|
|
297
|
+
);
|
|
298
|
+
const light = parse("light");
|
|
299
|
+
const dark = parse("dark");
|
|
300
|
+
const ids = (doc) =>
|
|
301
|
+
Array.from(doc.querySelectorAll("symbol"), (s) => s.id);
|
|
302
|
+
expect(ids(light)).toEqual(ids(dark));
|
|
303
|
+
expect(ids(light)).toHaveLength(20);
|
|
304
|
+
expect(light.getElementById("user").getAttribute("fill")).toBe("#000");
|
|
305
|
+
expect(dark.getElementById("user").getAttribute("fill")).toBe("#fff");
|
|
306
|
+
expect(light.getElementById("linkedin")).toBeNull();
|
|
307
|
+
expect(light.getElementById("megamenu-logo").outerHTML).not.toEqual(
|
|
308
|
+
dark.getElementById("megamenu-logo").outerHTML,
|
|
309
|
+
);
|
|
310
|
+
expect(light.getElementById("store-apple").outerHTML).not.toEqual(
|
|
311
|
+
dark.getElementById("store-apple").outerHTML,
|
|
312
|
+
);
|
|
313
|
+
for (const doc of [light, dark]) {
|
|
314
|
+
expect(doc.querySelector("parsererror")).toBeNull();
|
|
315
|
+
for (const element of doc.querySelectorAll("[clip-path]")) {
|
|
316
|
+
const id = element
|
|
317
|
+
.getAttribute("clip-path")
|
|
318
|
+
.match(/url\(#([^)]+)\)/)?.[1];
|
|
319
|
+
expect(doc.getElementById(id)).not.toBeNull();
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it.each([Megamenu, MegamenuBlog])(
|
|
326
|
+
"uses the dark sprite for an explicit dark navigation class",
|
|
327
|
+
(Component) => {
|
|
328
|
+
const { container } = render(<Component className="is-dark" />);
|
|
329
|
+
for (const use of container.querySelectorAll("use")) {
|
|
330
|
+
expect(use.getAttribute("xlink:href")).toMatch(
|
|
331
|
+
/^\/megamenu-sprite-dark\.svg#/,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
);
|