@orangesk/orange-design-system 2.0.0-beta.7 → 2.0.0-beta.8
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/index.js +4 -4
- package/build/components/index.js.map +1 -1
- package/build/components/tsconfig.tsbuildinfo +1 -1
- package/build/components/types/index.d.ts +2 -2
- package/build/components/types/src/components/AnchorNavigation/AnchorNavigation.d.ts +1 -1
- package/build/components/types/src/components/AnchorNavigation/AnchorNavigation.static.d.ts +19 -17
- package/build/components/types/src/components/Card/Card.d.ts +1 -1
- package/build/components/types/src/components/Megamenu/constants.d.ts +2 -0
- package/build/components/types/src/scripts/index.d.ts +5 -0
- package/build/lib/after-components.css +1 -1
- package/build/lib/after-components.css.map +1 -1
- package/build/lib/before-components.css +1 -1
- package/build/lib/before-components.css.map +1 -1
- 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/megamenu.js +1 -1
- package/build/lib/megamenu.js.map +1 -1
- package/build/lib/scripts.js +4 -4
- 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/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/src/components/AnchorNavigation/AnchorNavigation.static.ts +253 -73
- package/src/components/AnchorNavigation/AnchorNavigation.tsx +31 -24
- package/src/components/AnchorNavigation/styles/mixins.scss +14 -17
- package/src/components/AnchorNavigation/tests/AnchorNavigation.conformance.test.js +67 -0
- package/src/components/AnchorNavigation/tests/AnchorNavigation.unit.test.js +163 -0
- package/src/components/BlockAction/styles/mixins.scss +0 -6
- package/src/components/Card/Card.tsx +1 -0
- package/src/components/Link/styles/style.scss +1 -1
- package/src/components/Link/tests/Link.conformance.test.js +5 -20
- package/src/components/Link/tests/Link.unit.test.js +1 -10
- package/src/components/Megamenu/Megamenu.static.ts +2 -0
- package/src/components/Megamenu/Megamenu.tsx +671 -665
- package/src/components/Megamenu/MegamenuBlog.tsx +187 -183
- package/src/components/Megamenu/constants.ts +2 -0
- package/src/components/Megamenu/styles/mixins.scss +30 -1
- package/src/components/Megamenu/styles/style.scss +8 -0
- package/src/styles/base/globals.scss +18 -0
- package/src/styles/utilities/color.scss +4 -0
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
interface AnchorNavigationConfig {
|
|
2
|
-
itemSelector: string;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export const defaultConfig: AnchorNavigationConfig = {
|
|
6
|
-
itemSelector: '.anchor-navigation__item',
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export const configDocs = {
|
|
10
|
-
itemSelector: "Anchor navigation item element selector",
|
|
11
|
-
};
|
|
12
|
-
|
|
13
1
|
export default class AnchorNavigation {
|
|
14
2
|
private element: HTMLElement;
|
|
15
|
-
private
|
|
16
|
-
private
|
|
17
|
-
private
|
|
3
|
+
private megamenuElement: HTMLElement | null;
|
|
4
|
+
private resizeObserver: ResizeObserver | null;
|
|
5
|
+
private scrollHandler: () => void;
|
|
6
|
+
private scrollSpyHandler: () => void;
|
|
7
|
+
private scrollEndHandler: () => void;
|
|
8
|
+
private resizeHandler: () => void;
|
|
9
|
+
private isAutoScrolling: boolean = false;
|
|
10
|
+
private navLinks: NodeListOf<HTMLAnchorElement> | null = null;
|
|
11
|
+
private sections: HTMLElement[] = [];
|
|
12
|
+
private currentPath: string;
|
|
13
|
+
private lastActiveIndex: number = 0;
|
|
18
14
|
|
|
19
|
-
constructor(element: HTMLElement
|
|
15
|
+
constructor(element: HTMLElement) {
|
|
20
16
|
this.element = element;
|
|
21
|
-
this.config = { ...defaultConfig, ...config };
|
|
22
17
|
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
18
|
+
this.megamenuElement = null;
|
|
19
|
+
this.resizeObserver = null;
|
|
20
|
+
this.isAutoScrolling = false;
|
|
21
|
+
this.currentPath = window.location.pathname;
|
|
25
22
|
|
|
26
|
-
this.
|
|
23
|
+
this.scrollHandler = this.updateStickyPosition.bind(this);
|
|
24
|
+
this.scrollSpyHandler = this.handleScrollSpy.bind(this);
|
|
25
|
+
this.scrollEndHandler = this.handleScrollEnd.bind(this);
|
|
26
|
+
this.resizeHandler = this.initScrollSpy.bind(this);
|
|
27
27
|
|
|
28
28
|
(this.element as any).ODS_AnchorNavigation = this;
|
|
29
29
|
|
|
@@ -33,83 +33,263 @@ export default class AnchorNavigation {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
static getInstance(el: HTMLElement): AnchorNavigation | null {
|
|
36
|
-
return el && (el as any).ODS_AnchorNavigation
|
|
36
|
+
return el && (el as any).ODS_AnchorNavigation
|
|
37
|
+
? (el as any).ODS_AnchorNavigation
|
|
38
|
+
: null;
|
|
37
39
|
}
|
|
38
40
|
|
|
39
|
-
private
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
);
|
|
41
|
+
private findMegamenuElement(): HTMLElement | null {
|
|
42
|
+
return document.querySelector("[data-megamenu]") as HTMLElement | null;
|
|
43
|
+
}
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
private updateStickyPosition(): void {
|
|
46
|
+
if (!this.megamenuElement) return;
|
|
47
|
+
this.element.style.top = `${this.megamenuElement.offsetHeight}px`;
|
|
48
|
+
}
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
});
|
|
50
|
+
private setupMegamenuObserver(): void {
|
|
51
|
+
this.megamenuElement = this.findMegamenuElement();
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
if (!this.megamenuElement) {
|
|
54
|
+
this.element.style.top = "0px";
|
|
55
|
+
return;
|
|
55
56
|
}
|
|
57
|
+
|
|
58
|
+
this.updateStickyPosition();
|
|
59
|
+
window.addEventListener("scroll", this.scrollHandler, { passive: true });
|
|
60
|
+
|
|
61
|
+
this.resizeObserver = new ResizeObserver(
|
|
62
|
+
this.updateStickyPosition.bind(this),
|
|
63
|
+
);
|
|
64
|
+
this.resizeObserver.observe(this.megamenuElement);
|
|
56
65
|
}
|
|
57
66
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
private setupScrollSpy(): void {
|
|
68
|
+
// Set dynamic scroll margin for CSS
|
|
69
|
+
document.documentElement.style.setProperty(
|
|
70
|
+
"--extra-scroll-margin",
|
|
71
|
+
this.element.offsetHeight + "px",
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Get all anchor navigation links
|
|
75
|
+
this.navLinks = this.element.querySelectorAll(".anchor-navigation__item");
|
|
76
|
+
|
|
77
|
+
// Get all sections that correspond to the navigation links
|
|
78
|
+
this.sections = Array.from(this.navLinks || [])
|
|
79
|
+
.map((link) => link.getAttribute("href"))
|
|
80
|
+
.filter((href) => href?.includes("#"))
|
|
81
|
+
.map((href) => document.getElementById(href!.split("#")[1]))
|
|
82
|
+
.filter(Boolean) as HTMLElement[];
|
|
83
|
+
|
|
84
|
+
// Add click listeners to anchor navigation items
|
|
85
|
+
this.navLinks.forEach((anchor) => {
|
|
86
|
+
anchor.addEventListener("click", (event) => {
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
const href = anchor.getAttribute("href");
|
|
89
|
+
if (href && href.includes("#")) {
|
|
90
|
+
const targetId = href.split("#")[1];
|
|
91
|
+
const targetElement = document.getElementById(targetId);
|
|
92
|
+
|
|
93
|
+
if (targetElement) {
|
|
94
|
+
this.isAutoScrolling = true;
|
|
95
|
+
|
|
96
|
+
// Calculate scroll position
|
|
97
|
+
const scrollOffset = this.megamenuElement
|
|
98
|
+
? this.megamenuElement.offsetHeight
|
|
99
|
+
: 0;
|
|
100
|
+
const additionalOffset = this.element.offsetHeight;
|
|
101
|
+
const targetTop =
|
|
102
|
+
targetElement.offsetTop - scrollOffset - additionalOffset;
|
|
103
|
+
|
|
104
|
+
// Smooth scroll to target
|
|
105
|
+
window.scrollTo({
|
|
106
|
+
top: Math.max(0, targetTop),
|
|
107
|
+
behavior: "smooth",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Update active state
|
|
111
|
+
this.initScrollSpy(targetId);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
61
115
|
});
|
|
62
116
|
|
|
63
|
-
|
|
64
|
-
(this.
|
|
65
|
-
}
|
|
117
|
+
// Add scroll listeners
|
|
118
|
+
window.addEventListener("scroll", this.scrollSpyHandler, { passive: true });
|
|
66
119
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
120
|
+
// Add scrollend listener with fallback
|
|
121
|
+
try {
|
|
122
|
+
window.addEventListener("scrollend", this.scrollEndHandler);
|
|
123
|
+
} catch {
|
|
124
|
+
// Fallback for browsers that don't support scrollend
|
|
125
|
+
let scrollTimeout: ReturnType<typeof setTimeout>;
|
|
126
|
+
const scrollEndFallback = () => {
|
|
127
|
+
clearTimeout(scrollTimeout);
|
|
128
|
+
scrollTimeout = setTimeout(() => {
|
|
129
|
+
this.handleScrollEnd();
|
|
130
|
+
}, 150);
|
|
131
|
+
};
|
|
132
|
+
window.addEventListener("scroll", scrollEndFallback, { passive: true });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
window.addEventListener("resize", this.resizeHandler);
|
|
136
|
+
|
|
137
|
+
this.initScrollSpy();
|
|
70
138
|
}
|
|
71
139
|
|
|
72
|
-
private
|
|
73
|
-
|
|
74
|
-
|
|
140
|
+
private initScrollSpy(forcedSectionId: string | null = null): void {
|
|
141
|
+
if (!this.navLinks || !this.sections.length) return;
|
|
142
|
+
|
|
143
|
+
let targetSection: HTMLElement | undefined;
|
|
144
|
+
let targetIndex: number = -1;
|
|
145
|
+
|
|
146
|
+
// Remove active class from all links
|
|
147
|
+
this.navLinks.forEach((link) => link.classList.remove("is-active"));
|
|
148
|
+
|
|
149
|
+
if (forcedSectionId) {
|
|
150
|
+
targetSection = document.getElementById(forcedSectionId) || undefined;
|
|
151
|
+
if (targetSection) {
|
|
152
|
+
// Find the index of the forced section
|
|
153
|
+
targetIndex = this.sections.findIndex(
|
|
154
|
+
(section) => section.id === forcedSectionId,
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
// Calculate scroll offset from megamenu height and anchor nav height
|
|
159
|
+
const scrollOffset = this.megamenuElement
|
|
160
|
+
? this.megamenuElement.offsetHeight
|
|
161
|
+
: 0;
|
|
162
|
+
const anchorNavOffset = this.element.offsetHeight;
|
|
163
|
+
const totalOffset = scrollOffset + anchorNavOffset;
|
|
164
|
+
const effectiveCenter = window.scrollY + totalOffset + 50; // Add some buffer
|
|
165
|
+
|
|
166
|
+
// Find the section that's currently in view
|
|
167
|
+
for (let i = 0; i < this.sections.length; i++) {
|
|
168
|
+
const section = this.sections[i];
|
|
169
|
+
const { top: sectionTopRaw, height: sectionHeight } =
|
|
170
|
+
section.getBoundingClientRect();
|
|
171
|
+
const sectionTop = sectionTopRaw + window.scrollY;
|
|
172
|
+
const sectionBottom = sectionTop + sectionHeight;
|
|
75
173
|
|
|
76
|
-
|
|
77
|
-
|
|
174
|
+
if (effectiveCenter >= sectionTop && effectiveCenter < sectionBottom) {
|
|
175
|
+
targetSection = section;
|
|
176
|
+
targetIndex = i;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
78
181
|
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
182
|
+
// Fallback logic: if no section is found, use fallback rules
|
|
183
|
+
if (!targetSection) {
|
|
184
|
+
// If we're at the very top, activate first item
|
|
185
|
+
if (window.scrollY <= 100) {
|
|
186
|
+
targetIndex = 0;
|
|
187
|
+
targetSection = this.sections[0];
|
|
188
|
+
} else {
|
|
189
|
+
// Keep the last active item
|
|
190
|
+
targetIndex = this.lastActiveIndex;
|
|
191
|
+
targetSection = this.sections[targetIndex];
|
|
192
|
+
}
|
|
84
193
|
}
|
|
85
|
-
}
|
|
86
194
|
|
|
87
|
-
|
|
88
|
-
|
|
195
|
+
// Update last active index if we found a valid target
|
|
196
|
+
if (targetIndex >= 0) {
|
|
197
|
+
this.lastActiveIndex = targetIndex;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (targetSection) {
|
|
201
|
+
const id = targetSection.getAttribute("id");
|
|
89
202
|
|
|
90
|
-
|
|
91
|
-
|
|
203
|
+
// Find the matching navigation link - try different href patterns
|
|
204
|
+
let activeLink = this.element.querySelector(
|
|
205
|
+
`.anchor-navigation__item[href="#${id}"]`,
|
|
206
|
+
) as HTMLElement;
|
|
207
|
+
|
|
208
|
+
if (!activeLink) {
|
|
209
|
+
activeLink = this.element.querySelector(
|
|
210
|
+
`.anchor-navigation__item[href="${this.currentPath}#${id}"]`,
|
|
211
|
+
) as HTMLElement;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (!activeLink) {
|
|
215
|
+
// Try without current path for relative links
|
|
216
|
+
activeLink = Array.from(this.navLinks).find((link) => {
|
|
217
|
+
const href = link.getAttribute("href");
|
|
218
|
+
return href && href.endsWith(`#${id}`);
|
|
219
|
+
}) as HTMLElement;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (activeLink) {
|
|
223
|
+
activeLink.classList.add("is-active");
|
|
224
|
+
|
|
225
|
+
// Smooth scroll the navigation to center the active link
|
|
226
|
+
const contentLeft = this.element.querySelector(
|
|
227
|
+
".anchor-navigation__content-left",
|
|
228
|
+
) as HTMLElement;
|
|
229
|
+
if (contentLeft) {
|
|
230
|
+
contentLeft.scrollTo({
|
|
231
|
+
left:
|
|
232
|
+
activeLink.offsetLeft -
|
|
233
|
+
this.element.clientWidth / 2 +
|
|
234
|
+
activeLink.clientWidth / 2,
|
|
235
|
+
behavior: "smooth",
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
}
|
|
92
239
|
}
|
|
240
|
+
}
|
|
93
241
|
|
|
94
|
-
|
|
95
|
-
|
|
242
|
+
private handleScrollSpy(): void {
|
|
243
|
+
if (!this.isAutoScrolling) {
|
|
244
|
+
this.initScrollSpy();
|
|
96
245
|
}
|
|
97
246
|
}
|
|
98
247
|
|
|
99
|
-
|
|
100
|
-
|
|
248
|
+
private handleScrollEnd(): void {
|
|
249
|
+
this.isAutoScrolling = false;
|
|
250
|
+
this.initScrollSpy();
|
|
251
|
+
}
|
|
101
252
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
this.toggleItem(item, "on");
|
|
106
|
-
} else {
|
|
107
|
-
this.toggleItem(item, "off");
|
|
108
|
-
}
|
|
109
|
-
});
|
|
253
|
+
private init(): void {
|
|
254
|
+
this.setupMegamenuObserver();
|
|
255
|
+
this.setupScrollSpy();
|
|
110
256
|
}
|
|
111
257
|
|
|
112
|
-
|
|
113
|
-
|
|
258
|
+
destroy(): void {
|
|
259
|
+
window.removeEventListener("scroll", this.scrollHandler);
|
|
260
|
+
window.removeEventListener("scroll", this.scrollSpyHandler);
|
|
261
|
+
window.removeEventListener("scrollend", this.scrollEndHandler);
|
|
262
|
+
window.removeEventListener("resize", this.resizeHandler);
|
|
263
|
+
|
|
264
|
+
if (this.resizeObserver) {
|
|
265
|
+
this.resizeObserver.disconnect();
|
|
266
|
+
this.resizeObserver = null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.element.style.top = "";
|
|
270
|
+
this.megamenuElement = null;
|
|
271
|
+
this.navLinks = null;
|
|
272
|
+
this.sections = [];
|
|
273
|
+
this.lastActiveIndex = 0;
|
|
274
|
+
(this.element as any).ODS_AnchorNavigation = null;
|
|
114
275
|
}
|
|
115
|
-
|
|
276
|
+
|
|
277
|
+
update(): void {
|
|
278
|
+
window.removeEventListener("scroll", this.scrollHandler);
|
|
279
|
+
window.removeEventListener("scroll", this.scrollSpyHandler);
|
|
280
|
+
window.removeEventListener("scrollend", this.scrollEndHandler);
|
|
281
|
+
window.removeEventListener("resize", this.resizeHandler);
|
|
282
|
+
|
|
283
|
+
if (this.resizeObserver) {
|
|
284
|
+
this.resizeObserver.disconnect();
|
|
285
|
+
this.resizeObserver = null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
this.megamenuElement = null;
|
|
289
|
+
this.navLinks = null;
|
|
290
|
+
this.sections = [];
|
|
291
|
+
this.lastActiveIndex = 0;
|
|
292
|
+
|
|
293
|
+
this.init();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
import cx from "classnames";
|
|
5
|
-
import { Grid, GridCol } from "../Grid";
|
|
6
5
|
import { Link } from "../Link";
|
|
7
6
|
import { Container } from "../Container";
|
|
8
7
|
import { useStatic } from "../../utils/hooks";
|
|
@@ -28,6 +27,7 @@ const AnchorNavigation = ({
|
|
|
28
27
|
className,
|
|
29
28
|
colorScheme,
|
|
30
29
|
children,
|
|
30
|
+
...other
|
|
31
31
|
}: AnchorNavigationProps) => {
|
|
32
32
|
const classes = cx(
|
|
33
33
|
CLASS_ROOT,
|
|
@@ -41,31 +41,38 @@ const AnchorNavigation = ({
|
|
|
41
41
|
const [anchorNavRef] = useStatic(AnchorNavigationStatic);
|
|
42
42
|
|
|
43
43
|
return (
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
})}
|
|
57
|
-
>
|
|
58
|
-
{item.label}
|
|
59
|
-
</Link>
|
|
60
|
-
</GridCol>
|
|
61
|
-
))}
|
|
62
|
-
</Grid>
|
|
63
|
-
{children && (
|
|
64
|
-
<div className={`${CLASS_ROOT}__content-right`}>{children}</div>
|
|
44
|
+
<nav
|
|
45
|
+
className={classes}
|
|
46
|
+
ref={anchorNavRef}
|
|
47
|
+
data-anchor-navigation
|
|
48
|
+
aria-label="Sekcie stránky"
|
|
49
|
+
{...other}
|
|
50
|
+
>
|
|
51
|
+
<Container className={`${CLASS_ROOT}__content`}>
|
|
52
|
+
<ul
|
|
53
|
+
className={cx(
|
|
54
|
+
"list-inline horizontal-scroll mb-none",
|
|
55
|
+
`${CLASS_ROOT}__content-left`,
|
|
65
56
|
)}
|
|
66
|
-
|
|
57
|
+
>
|
|
58
|
+
{items.map((item) => (
|
|
59
|
+
<li key={item.href}>
|
|
60
|
+
<Link
|
|
61
|
+
href={item.href}
|
|
62
|
+
className={cx(`${CLASS_ROOT}__item`, {
|
|
63
|
+
"is-active": item.isActive,
|
|
64
|
+
})}
|
|
65
|
+
>
|
|
66
|
+
{item.label}
|
|
67
|
+
</Link>
|
|
68
|
+
</li>
|
|
69
|
+
))}
|
|
70
|
+
</ul>
|
|
71
|
+
{children && (
|
|
72
|
+
<div className={`${CLASS_ROOT}__content-right`}>{children}</div>
|
|
73
|
+
)}
|
|
67
74
|
</Container>
|
|
68
|
-
</
|
|
75
|
+
</nav>
|
|
69
76
|
);
|
|
70
77
|
};
|
|
71
78
|
|
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
@use "./../../../styles/tools/generate";
|
|
5
5
|
@use "./../../../styles/tools/convert";
|
|
6
6
|
@use "./../../../styles/typography/config" as typography;
|
|
7
|
+
@use "../../Megamenu/styles/config" as megamenuConfig;
|
|
7
8
|
@use "sass:map" as sass-map;
|
|
8
9
|
|
|
9
10
|
@mixin anchor-navigation() {
|
|
10
11
|
position: sticky;
|
|
11
12
|
top: 0;
|
|
12
|
-
z-index:
|
|
13
|
+
z-index: 10;
|
|
13
14
|
background-color: var(--color-background-primary) !important;
|
|
14
|
-
border-bottom: 1px solid var(--color-border-
|
|
15
|
+
border-bottom: 1px solid var(--color-border-strong);
|
|
15
16
|
|
|
16
|
-
// Štýly pre Grid s horizontal-scroll
|
|
17
17
|
.horizontal-scroll {
|
|
18
18
|
&::-webkit-scrollbar {
|
|
19
19
|
display: none !important;
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
background: transparent !important;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
// Pre Firefox
|
|
26
25
|
scrollbar-width: none !important;
|
|
27
26
|
-ms-overflow-style: none !important;
|
|
28
27
|
}
|
|
@@ -30,22 +29,13 @@
|
|
|
30
29
|
|
|
31
30
|
@mixin anchor-navigation-item() {
|
|
32
31
|
margin-right: space.get("large") !important;
|
|
32
|
+
margin-bottom: 0 !important;
|
|
33
33
|
padding: convert.to-rem(25px) 0 !important;
|
|
34
34
|
white-space: nowrap;
|
|
35
|
-
border-bottom: 4px solid transparent;
|
|
36
35
|
text-decoration: none !important;
|
|
37
36
|
display: inline-block;
|
|
38
37
|
cursor: pointer;
|
|
39
|
-
|
|
40
|
-
&:focus {
|
|
41
|
-
background-color: var(--color-background-primary) !important;
|
|
42
|
-
color: var(--color-text-default) !important;
|
|
43
|
-
outline: none !important;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
&:hover {
|
|
47
|
-
text-decoration: none !important;
|
|
48
|
-
}
|
|
38
|
+
font-weight: 700 !important;
|
|
49
39
|
|
|
50
40
|
&:last-child {
|
|
51
41
|
margin-right: 0;
|
|
@@ -56,9 +46,14 @@
|
|
|
56
46
|
padding: space.get("small") 0 !important;
|
|
57
47
|
}
|
|
58
48
|
|
|
49
|
+
&:hover,
|
|
50
|
+
&:focus-visible,
|
|
51
|
+
&:active,
|
|
59
52
|
&.is-active {
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
box-shadow: megamenuConfig.$active-line;
|
|
54
|
+
color: initial;
|
|
55
|
+
text-decoration: none !important;
|
|
56
|
+
outline: none;
|
|
62
57
|
}
|
|
63
58
|
}
|
|
64
59
|
|
|
@@ -75,6 +70,8 @@
|
|
|
75
70
|
}
|
|
76
71
|
|
|
77
72
|
@mixin anchor-navigation-content-left() {
|
|
73
|
+
display: flex;
|
|
74
|
+
|
|
78
75
|
@include breakpoint.get("xs", "down") {
|
|
79
76
|
width: 100%;
|
|
80
77
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { render } from "@testing-library/react";
|
|
2
|
+
import { axe } from "jest-axe";
|
|
3
|
+
|
|
4
|
+
import { AnchorNavigation } from "../";
|
|
5
|
+
|
|
6
|
+
const basicItems = [
|
|
7
|
+
{ label: "Key Features", href: "#features", isActive: true },
|
|
8
|
+
{ label: "Pricing", href: "#pricing" },
|
|
9
|
+
{ label: "Getting Started", href: "#getting-started" },
|
|
10
|
+
{ label: "Contact", href: "#contact" },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const example = (
|
|
14
|
+
<div id="root">
|
|
15
|
+
{/* Basic usage */}
|
|
16
|
+
<AnchorNavigation items={basicItems} aria-label="Basic navigation" />
|
|
17
|
+
|
|
18
|
+
{/* With color scheme */}
|
|
19
|
+
<AnchorNavigation
|
|
20
|
+
items={basicItems}
|
|
21
|
+
colorScheme="light"
|
|
22
|
+
aria-label="Light navigation"
|
|
23
|
+
/>
|
|
24
|
+
|
|
25
|
+
{/* With additional content */}
|
|
26
|
+
<AnchorNavigation
|
|
27
|
+
items={basicItems}
|
|
28
|
+
colorScheme="dark"
|
|
29
|
+
aria-label="Dark navigation with content"
|
|
30
|
+
>
|
|
31
|
+
<div className="bold">
|
|
32
|
+
<div className="align-sm-right">2 €</div>
|
|
33
|
+
<div className="reset-font-weight">No commitment</div>
|
|
34
|
+
</div>
|
|
35
|
+
<button type="button">Get Started</button>
|
|
36
|
+
</AnchorNavigation>
|
|
37
|
+
|
|
38
|
+
{/* Multiple items */}
|
|
39
|
+
<AnchorNavigation
|
|
40
|
+
items={[
|
|
41
|
+
{ label: "Overview", href: "#overview", isActive: true },
|
|
42
|
+
{ label: "Features", href: "#features" },
|
|
43
|
+
{ label: "Documentation", href: "#docs" },
|
|
44
|
+
{ label: "API Reference", href: "#api" },
|
|
45
|
+
{ label: "Examples", href: "#examples" },
|
|
46
|
+
{ label: "Support", href: "#support" },
|
|
47
|
+
]}
|
|
48
|
+
colorScheme="light"
|
|
49
|
+
aria-label="Extended navigation"
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
it("is valid html", () => {
|
|
55
|
+
const { container } = render(example);
|
|
56
|
+
expect(container).toHTMLValidate({
|
|
57
|
+
rules: {
|
|
58
|
+
"no-inline-style": "off",
|
|
59
|
+
"attribute-boolean-style": "off",
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("is accessible", async () => {
|
|
65
|
+
const { container } = render(example);
|
|
66
|
+
expect(await axe(container)).toHaveNoViolations();
|
|
67
|
+
});
|