@orangesk/orange-design-system 3.12.0 → 4.0.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/Breadcrumbs/style.css +1 -1
- package/build/components/Breadcrumbs/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/Footer/style.css +1 -1
- package/build/components/Footer/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/lib/base.css +1 -1
- package/build/lib/base.css.map +1 -1
- package/build/lib/breadcrumbs.css +2 -2
- package/build/lib/breadcrumbs.css.map +1 -1
- package/build/lib/components.css +1 -1
- package/build/lib/components.css.map +1 -1
- package/build/lib/fonts.css +1 -1
- package/build/lib/fonts.css.map +1 -1
- package/build/lib/footer.css +1 -1
- package/build/lib/footer.css.map +1 -1
- package/build/lib/footer.iife.js +2 -0
- package/build/lib/footer.iife.js.map +1 -0
- package/build/lib/megamenu.css +1 -1
- package/build/lib/megamenu.css.map +1 -1
- package/build/lib/megamenu.iife.js +2 -0
- package/build/lib/megamenu.iife.js.map +1 -0
- package/build/lib/megamenu.js +1 -1
- package/build/lib/megamenu.js.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/package.json +10 -12
- package/src/components/AnchorNavigation/AnchorNavigation.static.ts +3 -4
- package/src/components/AnchorNavigation/tests/AnchorNavigation.megamenu.unit.test.ts +74 -0
- package/src/components/AnchorNavigation/tests/AnchorNavigation.unit.test.jsx +6 -0
- package/src/components/Breadcrumbs/styles/mixins.scss +6 -0
- package/src/components/Breadcrumbs/styles/rules.scss +30 -0
- package/src/components/Breadcrumbs/styles/style.scss +2 -26
- package/src/components/Carousel/Carousel.static.ts +0 -3
- package/src/components/Carousel/styles/mixins.scss +0 -4
- package/src/components/Carousel/tests/Carousel.interactions.test.ts +116 -85
- package/src/components/CarouselHero/CarouselHero.static.ts +0 -3
- package/src/components/CarouselPromotions/CarouselPromotions.static.ts +0 -3
- package/src/components/Footer/classic.ts +3 -0
- package/src/components/Footer/styles/mixins.scss +32 -1
- package/src/components/Footer/styles/style.scss +8 -5
- package/src/components/Footer/tests/Footer.styles.unit.test.jsx +7 -2
- package/src/components/Megamenu/Megamenu.static.ts +25 -6
- package/src/components/Megamenu/classic.ts +3 -0
- package/src/components/Megamenu/styles/mixins.scss +114 -52
- package/src/components/Megamenu/styles/style.scss +6 -7
- package/src/components/Megamenu/tests/Megamenu.scroll.unit.test.ts +185 -0
- package/src/styles/base/globals.scss +1 -37
- package/src/styles/base/header-height-values.scss +9 -0
- package/src/styles/base/header-height.scss +50 -0
- package/src/styles/base/styleguide.scss +0 -1
- package/build/files/tone-of-voice.pdf +0 -26572
- package/build/images/card-device-example.png +0 -0
- package/build/images/cta-device.png +0 -0
- package/build/images/cta-plans.png +0 -0
- package/build/images/cta-renewal.png +0 -0
- package/build/images/device-mobile.png +0 -0
- package/build/images/form-validation-format.png +0 -0
- package/build/images/form-validation-info-structure.png +0 -0
- package/build/images/form-validation-semantics.png +0 -0
- package/build/images/forms-labels-grouping.png +0 -0
- package/build/images/forms-labels-instruction.png +0 -0
- package/build/images/forms-labels-structure.png +0 -0
- package/build/images/hero/example-lg.jpg +0 -0
- package/build/images/hero/example-lg@2x.jpg +0 -0
- package/build/images/hero/example-xl.jpg +0 -0
- package/build/images/hero/example-xl@2x.jpg +0 -0
- package/build/images/hero/example-xxl.jpg +0 -0
- package/build/images/hero/example-xxl@2x.jpg +0 -0
- package/build/images/hero/example.jpg +0 -0
- package/build/images/hero/example@2x.jpg +0 -0
- package/build/images/hero/old-vendor-2x.jpg +0 -0
- package/build/images/hero/old-vendor-lg-2x.jpg +0 -0
- package/build/images/hero/old-vendor-lg.jpg +0 -0
- package/build/images/hero/old-vendor-xl-2x.jpg +0 -0
- package/build/images/hero/old-vendor-xl.jpg +0 -0
- package/build/images/hero/old-vendor-xxl-2x.jpg +0 -0
- package/build/images/hero/old-vendor-xxl.jpg +0 -0
- package/build/images/hero/old-vendor.jpg +0 -0
- package/build/images/hero/photo-2x.jpg +0 -0
- package/build/images/hero/photo-lg-2x.jpg +0 -0
- package/build/images/hero/photo-lg.jpg +0 -0
- package/build/images/hero/photo-xl-2x.jpg +0 -0
- package/build/images/hero/photo-xl.jpg +0 -0
- package/build/images/hero/photo-xxl-2x.jpg +0 -0
- package/build/images/hero/photo-xxl.jpg +0 -0
- package/build/images/hero/photo.jpg +0 -0
- package/build/images/hero/single.png +0 -0
- package/build/images/hero/single@2x.png +0 -0
- package/build/images/hero/vendor-lg.png +0 -0
- package/build/images/hero/vendor-lg@2x.png +0 -0
- package/build/images/hero/vendor-xl.png +0 -0
- package/build/images/hero/vendor-xl@2x.png +0 -0
- package/build/images/hero/vendor-xxl.png +0 -0
- package/build/images/hero/vendor-xxl@2x.png +0 -0
- package/build/images/hero/vendor.png +0 -0
- package/build/images/hero/vendor@2x.png +0 -0
- package/build/images/phones.png +0 -0
- package/build/images/product-1.svg +0 -10
- package/build/images/product-2.svg +0 -14
- package/build/images/product-3.svg +0 -9
- package/build/images/tone-of-voice.jpg +0 -0
- package/build/lib/base.js +0 -3
- package/build/lib/breadcrumbs.js +0 -3
- package/build/lib/components.js +0 -3
- package/build/lib/fonts.js +0 -3
- package/build/lib/reset.js +0 -3
- package/build/lib/style.js +0 -3
- package/build/lib/utilities.js +0 -3
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orangesk/orange-design-system",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.x"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"build/",
|
|
10
|
+
"!build/images/**",
|
|
11
|
+
"!build/files/**",
|
|
10
12
|
"public/fonts/",
|
|
11
13
|
"public/footer-sprite-*.svg",
|
|
12
14
|
"src/components/",
|
|
@@ -35,7 +37,6 @@
|
|
|
35
37
|
"a11y-dialog": "^8.1.5",
|
|
36
38
|
"classnames": "^2.5.1",
|
|
37
39
|
"daypickr": "^0.3.4",
|
|
38
|
-
"diff2html": "^3.4.56",
|
|
39
40
|
"dompurify": "^3.4.17",
|
|
40
41
|
"html-react-parser": "6.1.9",
|
|
41
42
|
"lorem-ipsum": "3.0.0",
|
|
@@ -58,7 +59,7 @@
|
|
|
58
59
|
"wnumb": "^1.2.0"
|
|
59
60
|
},
|
|
60
61
|
"devDependencies": {
|
|
61
|
-
"@babel/core": "8.0.
|
|
62
|
+
"@babel/core": "8.0.10",
|
|
62
63
|
"@babel/preset-env": "8.0.7",
|
|
63
64
|
"@babel/preset-react": "8.0.1",
|
|
64
65
|
"@babel/preset-typescript": "8.0.7",
|
|
@@ -71,32 +72,28 @@
|
|
|
71
72
|
"@rollup/plugin-terser": "1.0.2",
|
|
72
73
|
"@rollup/plugin-typescript": "^12.3.1",
|
|
73
74
|
"@rollup/plugin-url": "^8.0.2",
|
|
74
|
-
"@rollup/rollup-darwin-arm64": "^4.65.0",
|
|
75
75
|
"@testing-library/dom": "^10.4.2",
|
|
76
76
|
"@testing-library/jest-dom": "7.0.1",
|
|
77
77
|
"@testing-library/react": "^16.3.3",
|
|
78
78
|
"@testing-library/user-event": "^14.6.8",
|
|
79
|
-
"@types/node": "26.6.
|
|
79
|
+
"@types/node": "26.6.6",
|
|
80
80
|
"@types/react": "19.3.0",
|
|
81
81
|
"@types/react-dom": "19.3.0",
|
|
82
82
|
"@types/wnumb": "^1.2.3",
|
|
83
|
-
"@vitejs/plugin-react": "6.1.2",
|
|
84
83
|
"@vitest/coverage-v8": "5.0.5",
|
|
85
84
|
"@vitest/ui": "5.0.5",
|
|
86
85
|
"canvas": "^3.2.3",
|
|
87
|
-
"
|
|
88
|
-
"glob": "13.0.6",
|
|
86
|
+
"glob": "14.0.3",
|
|
89
87
|
"html-validate": "11.17.0",
|
|
90
88
|
"husky": "^9.1.7",
|
|
91
|
-
"identity-obj-proxy": "^3.0.0",
|
|
92
89
|
"jsdom": "30.1.3",
|
|
93
90
|
"lint-staged": "17.6.0",
|
|
94
91
|
"prettier": "^3.9.10",
|
|
95
|
-
"rollup": "^4.
|
|
92
|
+
"rollup": "^4.66.0",
|
|
96
93
|
"rollup-plugin-copy": "^3.5.0",
|
|
97
94
|
"rollup-plugin-dts": "^6.5.1",
|
|
98
95
|
"rollup-plugin-postcss": "^4.0.2",
|
|
99
|
-
"sass": "^1.
|
|
96
|
+
"sass": "^1.107.0",
|
|
100
97
|
"svg-sprite": "^2.0.4",
|
|
101
98
|
"typescript": "6.0.3",
|
|
102
99
|
"vitest": "5.0.5",
|
|
@@ -109,11 +106,12 @@
|
|
|
109
106
|
"scripts": {
|
|
110
107
|
"dev": "npm run sprite && npm run build:search-index && npm run build:preview-iframe && next dev",
|
|
111
108
|
"build": "npm run sprite && npm run build:search-index && npm run build:preview-iframe && next build",
|
|
112
|
-
"build:bundle": "pnpm run sprite && pnpm exec rollup -c && pnpm exec rollup -c rollup.megamenu.config.mjs && pnpm exec rollup -c rollup.footer.config.mjs && pnpm run verify:production-bundle",
|
|
109
|
+
"build:bundle": "pnpm run sprite && pnpm exec rollup -c && pnpm exec rollup -c rollup.megamenu.config.mjs && pnpm exec rollup -c rollup.footer.config.mjs && pnpm run verify:production-bundle && pnpm run verify:standalone-bundles",
|
|
113
110
|
"build:preview-iframe": "node scripts/build-preview-iframe-bundle.mjs",
|
|
114
111
|
"build:megamenu": "pnpm run sprite && pnpm exec rollup -c rollup.megamenu.config.mjs",
|
|
115
112
|
"build:footer": "pnpm run build:scss-exports && node scripts/build-footer-sprites.mjs && pnpm exec rollup -c rollup.footer.config.mjs",
|
|
116
113
|
"verify:production-bundle": "node scripts/verify-production-bundle.mjs",
|
|
114
|
+
"verify:standalone-bundles": "node scripts/verify-standalone-bundles.mjs",
|
|
117
115
|
"dev:footer": "npm run build:scss-exports && node scripts/build-footer-sprites.mjs && pnpm exec rollup -c rollup.footer.config.mjs --watch",
|
|
118
116
|
"build:scss-exports": "node scripts/build-scss-exports.js",
|
|
119
117
|
"build:search-index": "node scripts/mdx-search-index.js",
|
|
@@ -99,7 +99,8 @@ export default class AnchorNavigation {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
private getMegamenuOffsetHeight(): number {
|
|
102
|
-
|
|
102
|
+
// offsetHeight rounds fractional CSS pixels and can leave a visible seam.
|
|
103
|
+
return this.megamenuElement?.getBoundingClientRect().height || 0;
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
private updateStickyPosition(): void {
|
|
@@ -304,9 +305,7 @@ export default class AnchorNavigation {
|
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
private getTotalStickyOffset(): number {
|
|
307
|
-
const scrollOffset = this.
|
|
308
|
-
? this.megamenuElement.offsetHeight
|
|
309
|
-
: 0;
|
|
308
|
+
const scrollOffset = this.getMegamenuOffsetHeight();
|
|
310
309
|
const anchorNavOffset = this.element.offsetHeight;
|
|
311
310
|
return scrollOffset + anchorNavOffset;
|
|
312
311
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import AnchorNavigation from "../AnchorNavigation.static";
|
|
4
|
+
|
|
5
|
+
describe("AnchorNavigation fractional Megamenu height", () => {
|
|
6
|
+
let instance: AnchorNavigation;
|
|
7
|
+
let menu: HTMLElement;
|
|
8
|
+
let anchor: HTMLElement;
|
|
9
|
+
let height: number;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
height = 80.5;
|
|
13
|
+
menu = document.createElement("nav");
|
|
14
|
+
menu.setAttribute("data-megamenu", "");
|
|
15
|
+
// jsdom has no layout; represent the browser's fractional and rounded APIs.
|
|
16
|
+
vi.spyOn(menu, "getBoundingClientRect").mockImplementation(
|
|
17
|
+
() => ({ height }) as DOMRect,
|
|
18
|
+
);
|
|
19
|
+
Object.defineProperty(menu, "offsetHeight", {
|
|
20
|
+
get: () => Math.round(height),
|
|
21
|
+
});
|
|
22
|
+
anchor = document.createElement("nav");
|
|
23
|
+
anchor.innerHTML = '<ul class="anchor-navigation__content-left"></ul>';
|
|
24
|
+
document.body.append(menu, anchor);
|
|
25
|
+
instance = new AnchorNavigation(anchor);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
instance.destroy();
|
|
30
|
+
menu.remove();
|
|
31
|
+
anchor.remove();
|
|
32
|
+
vi.restoreAllMocks();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("places the navigation at the fractional menu edge on initialization", () => {
|
|
36
|
+
expect(anchor.style.top).toBe("80.5px");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("follows fractional animation heights through its ResizeObserver", () => {
|
|
40
|
+
height = 113.625;
|
|
41
|
+
const observer = (instance as any).resizeObserver;
|
|
42
|
+
observer.callback([], observer);
|
|
43
|
+
expect(anchor.style.top).toBe("113.625px");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("keeps the fractional menu offset when scrolling to a section", () => {
|
|
47
|
+
const section = document.createElement("section");
|
|
48
|
+
section.id = "fractional-section";
|
|
49
|
+
vi.spyOn(section, "getBoundingClientRect").mockReturnValue({
|
|
50
|
+
top: 600,
|
|
51
|
+
} as DOMRect);
|
|
52
|
+
document.body.append(section);
|
|
53
|
+
Object.defineProperty(anchor, "offsetHeight", { value: 50 });
|
|
54
|
+
const previousScrollY = window.scrollY;
|
|
55
|
+
Object.defineProperty(window, "scrollY", { configurable: true, value: 0 });
|
|
56
|
+
const scroll = vi.spyOn(window, "scrollTo").mockImplementation(() => {});
|
|
57
|
+
const link = document.createElement("a");
|
|
58
|
+
link.className = "anchor-navigation__item";
|
|
59
|
+
link.href = "#fractional-section";
|
|
60
|
+
anchor.append(link);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
link.click();
|
|
64
|
+
expect(scroll).toHaveBeenCalledWith({ top: 469.5, behavior: "smooth" });
|
|
65
|
+
} finally {
|
|
66
|
+
Object.defineProperty(window, "scrollY", {
|
|
67
|
+
configurable: true,
|
|
68
|
+
value: previousScrollY,
|
|
69
|
+
writable: true,
|
|
70
|
+
});
|
|
71
|
+
section.remove();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -628,6 +628,9 @@ describe("rendering AnchorNavigation", () => {
|
|
|
628
628
|
configurable: true,
|
|
629
629
|
value: 120,
|
|
630
630
|
});
|
|
631
|
+
vi.spyOn(megamenu, "getBoundingClientRect").mockReturnValue({
|
|
632
|
+
height: 120,
|
|
633
|
+
});
|
|
631
634
|
document.body.appendChild(megamenu);
|
|
632
635
|
|
|
633
636
|
Object.defineProperty(window, "scrollY", {
|
|
@@ -703,6 +706,9 @@ describe("rendering AnchorNavigation", () => {
|
|
|
703
706
|
configurable: true,
|
|
704
707
|
get: () => megamenuHeight,
|
|
705
708
|
});
|
|
709
|
+
vi.spyOn(megamenu, "getBoundingClientRect").mockImplementation(() => ({
|
|
710
|
+
height: megamenuHeight,
|
|
711
|
+
}));
|
|
706
712
|
document.body.appendChild(megamenu);
|
|
707
713
|
|
|
708
714
|
Object.defineProperty(window, "scrollY", {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
@mixin container {
|
|
27
|
+
@include typoMixins.list-unstyled;
|
|
27
28
|
@include container.base;
|
|
28
29
|
|
|
29
30
|
font-size: 0;
|
|
@@ -111,6 +112,11 @@
|
|
|
111
112
|
text-decoration: none;
|
|
112
113
|
display: inline;
|
|
113
114
|
|
|
115
|
+
&:focus-visible {
|
|
116
|
+
outline: 2px solid currentColor;
|
|
117
|
+
outline-offset: 2px;
|
|
118
|
+
}
|
|
119
|
+
|
|
114
120
|
&:hover {
|
|
115
121
|
color: var(--color-text-default);
|
|
116
122
|
text-decoration: underline;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
@use "./mixins";
|
|
2
|
+
|
|
3
|
+
// Shared selectors for the layered ODS and unlayered standalone outputs.
|
|
4
|
+
@mixin styles {
|
|
5
|
+
.osk-breadcrumbs {
|
|
6
|
+
@include mixins.base;
|
|
7
|
+
|
|
8
|
+
&__container {
|
|
9
|
+
@include mixins.container;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.osk-breadcrumbs__item {
|
|
14
|
+
@include mixins.item;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.background-contrast .osk-breadcrumbs__item,
|
|
18
|
+
.surface-contrast .osk-breadcrumbs__item,
|
|
19
|
+
.is-dark .osk-breadcrumbs__item {
|
|
20
|
+
@include mixins.item-dark;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.osk-breadcrumbs__link {
|
|
24
|
+
@include mixins.link;
|
|
25
|
+
|
|
26
|
+
&[aria-current="page"] {
|
|
27
|
+
@include mixins.link-current;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
@use "./
|
|
1
|
+
@use "./rules";
|
|
2
2
|
|
|
3
3
|
@layer components {
|
|
4
|
-
.
|
|
5
|
-
@include mixins.base;
|
|
6
|
-
|
|
7
|
-
&__container {
|
|
8
|
-
@include mixins.container;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
.osk-breadcrumbs__item {
|
|
13
|
-
@include mixins.item;
|
|
14
|
-
|
|
15
|
-
.background-contrast &,
|
|
16
|
-
.surface-contrast &,
|
|
17
|
-
.is-dark & {
|
|
18
|
-
@include mixins.item-dark;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.osk-breadcrumbs__link {
|
|
23
|
-
@include mixins.link;
|
|
24
|
-
|
|
25
|
-
&[aria-current="page"] {
|
|
26
|
-
@include mixins.link-current;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
4
|
+
@include rules.styles;
|
|
29
5
|
}
|
|
@@ -40,9 +40,6 @@ interface ExternalControlsState {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export const defaultConfig: SwiperOptions = {
|
|
43
|
-
// Keep pointer selection and click handlers available to CMS editors and integrations.
|
|
44
|
-
touchStartPreventDefault: false,
|
|
45
|
-
preventClicksPropagation: false,
|
|
46
43
|
navigation: {
|
|
47
44
|
nextEl: SELECTOR_NEXT,
|
|
48
45
|
prevEl: SELECTOR_PREV,
|
|
@@ -3,100 +3,131 @@ import CarouselHero from "../../CarouselHero/CarouselHero.static";
|
|
|
3
3
|
import CarouselPromotions from "../../CarouselPromotions/CarouselPromotions.static";
|
|
4
4
|
import Carousel from "../Carousel.static";
|
|
5
5
|
|
|
6
|
-
describe.each(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
describe.each(
|
|
7
|
+
[
|
|
8
|
+
{ name: "Carousel", Module: Carousel, prefix: "carousel" },
|
|
9
|
+
{ name: "CarouselHero", Module: CarouselHero, prefix: "carousel-hero" },
|
|
10
|
+
{
|
|
11
|
+
name: "CarouselPromotions",
|
|
12
|
+
Module: CarouselPromotions,
|
|
13
|
+
prefix: "carousel-promotions",
|
|
14
|
+
},
|
|
15
|
+
].flatMap((component) =>
|
|
16
|
+
["defaults", "data attribute", "constructor"].map((source) => ({
|
|
17
|
+
...component,
|
|
18
|
+
source,
|
|
19
|
+
editorMode: source !== "defaults",
|
|
20
|
+
})),
|
|
21
|
+
),
|
|
22
|
+
)(
|
|
23
|
+
"$name pointer interactions with real Swiper ($source)",
|
|
24
|
+
({ Module, prefix, source, editorMode }) => {
|
|
25
|
+
let carousel: Carousel | CarouselHero | CarouselPromotions;
|
|
26
|
+
let icon: SVGElement;
|
|
17
27
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
vi.useFakeTimers();
|
|
30
|
+
document.body.innerHTML = `<div class="${prefix}" data-${prefix}>
|
|
21
31
|
<div class="${prefix}__viewport-wrapper"><div class="${prefix}__viewport"><div class="${prefix}__track">
|
|
22
32
|
<div class="${prefix}__slide"><a href="#card"><svg><path d="M0 0h10v10z" /></svg></a></div>
|
|
23
33
|
<div class="${prefix}__slide">Second</div><div class="${prefix}__slide">Third</div>
|
|
24
34
|
</div></div></div>
|
|
25
35
|
</div>`;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
36
|
+
const element = document.body.firstElementChild as HTMLElement;
|
|
37
|
+
for (const node of [
|
|
38
|
+
element,
|
|
39
|
+
element.querySelector(`.${prefix}__viewport`)!,
|
|
40
|
+
]) {
|
|
41
|
+
Object.defineProperty(node, "clientWidth", { value: 600 });
|
|
42
|
+
Object.defineProperty(node, "clientHeight", { value: 200 });
|
|
43
|
+
}
|
|
44
|
+
const editorOptions = {
|
|
45
|
+
touchStartPreventDefault: false,
|
|
46
|
+
preventClicksPropagation: false,
|
|
47
|
+
};
|
|
48
|
+
if (source === "data attribute") {
|
|
49
|
+
element.setAttribute(
|
|
50
|
+
"data-swiper-options",
|
|
51
|
+
JSON.stringify(editorOptions),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
carousel = new Module(element, {
|
|
55
|
+
loop: false,
|
|
56
|
+
breakpoints: {},
|
|
57
|
+
...(source === "constructor" ? editorOptions : {}),
|
|
58
|
+
});
|
|
59
|
+
vi.advanceTimersByTime(100);
|
|
60
|
+
icon = element.querySelector("path")!;
|
|
61
|
+
expect(carousel.instance.enabled).toBe(true);
|
|
62
|
+
});
|
|
46
63
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
clientY: 20,
|
|
53
|
-
button: 0,
|
|
64
|
+
afterEach(() => {
|
|
65
|
+
carousel?.destroy();
|
|
66
|
+
vi.clearAllTimers();
|
|
67
|
+
vi.useRealTimers();
|
|
68
|
+
document.body.innerHTML = "";
|
|
54
69
|
});
|
|
55
|
-
Object.assign(event, { pointerId: 1, pointerType });
|
|
56
|
-
icon.dispatchEvent(event);
|
|
57
|
-
return event;
|
|
58
|
-
}
|
|
59
70
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
71
|
+
function pointer(type: string, x: number, pointerType = "mouse") {
|
|
72
|
+
const event = new MouseEvent(type, {
|
|
73
|
+
bubbles: true,
|
|
74
|
+
cancelable: true,
|
|
75
|
+
clientX: x,
|
|
76
|
+
clientY: 20,
|
|
77
|
+
button: 0,
|
|
78
|
+
});
|
|
79
|
+
Object.assign(event, { pointerId: 1, pointerType });
|
|
80
|
+
icon.dispatchEvent(event);
|
|
81
|
+
return event;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
it.each(["mouse", "touch", "pen"])(
|
|
85
|
+
"applies the configured pointerdown behavior for %s",
|
|
86
|
+
(pointerType) => {
|
|
87
|
+
const onPointerDown = vi.fn();
|
|
88
|
+
carousel.element.addEventListener("pointerdown", onPointerDown);
|
|
89
|
+
const event = pointer("pointerdown", 400, pointerType);
|
|
90
|
+
expect(onPointerDown).toHaveBeenCalledOnce();
|
|
91
|
+
expect(event.defaultPrevented).toBe(!editorMode);
|
|
92
|
+
},
|
|
93
|
+
);
|
|
70
94
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
95
|
+
it("delivers an ordinary icon click without canceling it", () => {
|
|
96
|
+
const onClick = vi.fn();
|
|
97
|
+
carousel.element.addEventListener("click", onClick);
|
|
98
|
+
pointer("pointerdown", 400);
|
|
99
|
+
pointer("pointerup", 400);
|
|
100
|
+
const click = new MouseEvent("click", {
|
|
101
|
+
bubbles: true,
|
|
102
|
+
cancelable: true,
|
|
103
|
+
});
|
|
104
|
+
icon.dispatchEvent(click);
|
|
105
|
+
expect(onClick).toHaveBeenCalledOnce();
|
|
106
|
+
expect(click.defaultPrevented).toBe(false);
|
|
107
|
+
});
|
|
81
108
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
109
|
+
it("keeps swipe navigation and link protection with configured click propagation", () => {
|
|
110
|
+
const onIconClick = vi.fn();
|
|
111
|
+
const onClick = vi.fn();
|
|
112
|
+
icon.addEventListener("click", onIconClick);
|
|
113
|
+
carousel.element.addEventListener("click", onClick);
|
|
114
|
+
// The initial translation is zero; jsdom cannot parse CSS transforms with DOMMatrixReadOnly.
|
|
115
|
+
carousel.instance.wrapperEl.style.transform = "none";
|
|
116
|
+
pointer("pointerdown", 400);
|
|
117
|
+
pointer("pointermove", 350);
|
|
118
|
+
pointer("pointermove", 100);
|
|
119
|
+
pointer("pointerup", 100);
|
|
120
|
+
expect(carousel.instance.activeIndex).toBe(1);
|
|
121
|
+
expect(carousel.instance.animating).toBe(true);
|
|
95
122
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
123
|
+
const click = new MouseEvent("click", {
|
|
124
|
+
bubbles: true,
|
|
125
|
+
cancelable: true,
|
|
126
|
+
});
|
|
127
|
+
icon.dispatchEvent(click);
|
|
128
|
+
expect(onIconClick).toHaveBeenCalledTimes(editorMode ? 1 : 0);
|
|
129
|
+
expect(onClick).toHaveBeenCalledTimes(editorMode ? 1 : 0);
|
|
130
|
+
expect(click.defaultPrevented).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
);
|
|
@@ -27,9 +27,6 @@ import {
|
|
|
27
27
|
} from "./constants";
|
|
28
28
|
|
|
29
29
|
export const defaultConfig: SwiperOptions = {
|
|
30
|
-
// Keep pointer selection and click handlers available to CMS editors and integrations.
|
|
31
|
-
touchStartPreventDefault: false,
|
|
32
|
-
preventClicksPropagation: false,
|
|
33
30
|
pagination: {
|
|
34
31
|
clickable: true,
|
|
35
32
|
bulletClass: CLASS_PAGINATION_ITEM,
|
|
@@ -22,9 +22,6 @@ import {
|
|
|
22
22
|
} from "./constants";
|
|
23
23
|
|
|
24
24
|
export const defaultConfig: SwiperOptions = {
|
|
25
|
-
// Keep pointer selection and click handlers available to CMS editors and integrations.
|
|
26
|
-
touchStartPreventDefault: false,
|
|
27
|
-
preventClicksPropagation: false,
|
|
28
25
|
pagination: {
|
|
29
26
|
el: SELECTOR_DOTS,
|
|
30
27
|
clickable: true,
|
|
@@ -16,10 +16,33 @@
|
|
|
16
16
|
@include visibility.visually-hidden;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
:where(button, input, select, textarea) {
|
|
20
|
+
font: inherit;
|
|
21
|
+
color: inherit;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
:where(h3, strong, b) {
|
|
25
|
+
font-family: inherit;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
:where(strong, b) {
|
|
29
|
+
font-weight: 700;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
li {
|
|
33
|
+
font-size: inherit;
|
|
34
|
+
line-height: inherit;
|
|
35
|
+
font-weight: inherit;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:where(a) {
|
|
20
39
|
color: var(--color-text-default);
|
|
21
40
|
text-decoration: none;
|
|
41
|
+
font-family: inherit;
|
|
42
|
+
font-weight: inherit;
|
|
22
43
|
font-size: inherit;
|
|
44
|
+
background-color: transparent;
|
|
45
|
+
box-shadow: none;
|
|
23
46
|
|
|
24
47
|
&:hover,
|
|
25
48
|
&:focus,
|
|
@@ -27,6 +50,8 @@
|
|
|
27
50
|
text-decoration: underline;
|
|
28
51
|
text-underline-offset: convert.to-rem(2px);
|
|
29
52
|
text-decoration-thickness: auto;
|
|
53
|
+
background-color: transparent;
|
|
54
|
+
box-shadow: none;
|
|
30
55
|
}
|
|
31
56
|
|
|
32
57
|
&:focus-visible {
|
|
@@ -46,6 +71,11 @@
|
|
|
46
71
|
[tabindex]:not([tabindex="-1"]),
|
|
47
72
|
[contentEditable="true"] {
|
|
48
73
|
@include base.focusring;
|
|
74
|
+
|
|
75
|
+
&:focus-visible {
|
|
76
|
+
// Legacy ODS explicitly suppresses outlines with !important.
|
|
77
|
+
outline-width: base.$focusring-width !important;
|
|
78
|
+
}
|
|
49
79
|
}
|
|
50
80
|
|
|
51
81
|
*,
|
|
@@ -74,6 +104,7 @@
|
|
|
74
104
|
|
|
75
105
|
@mixin base {
|
|
76
106
|
font-size: 1rem;
|
|
107
|
+
font-weight: 400;
|
|
77
108
|
letter-spacing: convert.to-rem(-0.1px);
|
|
78
109
|
line-height: convert.to-rem(18px);
|
|
79
110
|
color: var(--color-text-default);
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
@use "../../SocialButton/styles/mixins" as socialButtonMixins;
|
|
8
8
|
@use "../../Icon/styles/mixins" as iconMixins;
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// Keep specificity equal in document and shadow trees, above legacy link rules.
|
|
11
|
+
:is(:root, :host) #{config.$class-root} {
|
|
11
12
|
@include mixins.globals;
|
|
12
13
|
}
|
|
13
14
|
|
|
@@ -22,7 +23,7 @@
|
|
|
22
23
|
@include megamenuMixins.dark-vars;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
#{config.$class-root} {
|
|
26
|
+
:is(:root, :host) #{config.$class-root} {
|
|
26
27
|
@include mixins.base;
|
|
27
28
|
|
|
28
29
|
&__container {
|
|
@@ -62,11 +63,13 @@
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
[data-footer-toggle][aria-expanded="false"]
|
|
66
|
+
[data-footer-toggle][aria-expanded="false"]
|
|
67
|
+
> #{config.$class-root}__accordion-icon {
|
|
66
68
|
transform: rotate(0deg);
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
[data-footer-toggle][aria-expanded="true"]
|
|
71
|
+
[data-footer-toggle][aria-expanded="true"]
|
|
72
|
+
> #{config.$class-root}__accordion-icon {
|
|
70
73
|
transform: rotate(180deg);
|
|
71
74
|
}
|
|
72
75
|
|
|
@@ -91,7 +94,7 @@
|
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
&__menu-section >
|
|
97
|
+
&__menu-section > #{config.$class-root}__list {
|
|
95
98
|
@include mixins.accordion-list;
|
|
96
99
|
}
|
|
97
100
|
|