@onsvisual/svelte-components 1.0.58 → 1.0.59
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/css/main.css +1 -1
- package/dist/layout/Header/Header.svelte +31 -172
- package/dist/layout/Header/nav.d.ts +1 -0
- package/dist/layout/Header/nav.js +271 -0
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script>
|
|
2
2
|
import { onMount, getContext } from "svelte";
|
|
3
|
+
import initNav from "./nav.js";
|
|
3
4
|
import Theme from "../../wrappers/Theme/Theme.svelte";
|
|
4
5
|
import SkipLink from "../SkipLink/SkipLink.svelte";
|
|
5
6
|
|
|
@@ -46,15 +47,11 @@
|
|
|
46
47
|
let baseother = "https://cy.ons.gov.uk";
|
|
47
48
|
let path = "";
|
|
48
49
|
|
|
49
|
-
let menuExpanded = false;
|
|
50
|
-
let searchExpanded = false;
|
|
51
|
-
|
|
52
50
|
const menu = [
|
|
53
51
|
{
|
|
54
52
|
label_en: "Business, industry and trade",
|
|
55
53
|
label_cy: "Busnes, diwydiant a masnach",
|
|
56
54
|
url: "/businessindustryandtrade",
|
|
57
|
-
expanded: false,
|
|
58
55
|
children: [
|
|
59
56
|
{ label_en: "Business", label_cy: "Busnes", url: "/businessindustryandtrade/business" },
|
|
60
57
|
{
|
|
@@ -98,7 +95,6 @@
|
|
|
98
95
|
label_en: "Economy",
|
|
99
96
|
label_cy: "Yr economi",
|
|
100
97
|
url: "/economy",
|
|
101
|
-
expanded: false,
|
|
102
98
|
children: [
|
|
103
99
|
{
|
|
104
100
|
label_en: "Economic output and productivity",
|
|
@@ -151,7 +147,6 @@
|
|
|
151
147
|
label_en: "Employment and labour market",
|
|
152
148
|
label_cy: "Cyflogaeth a'r farchnad lafur",
|
|
153
149
|
url: "/employmentandlabourmarket",
|
|
154
|
-
expanded: false,
|
|
155
150
|
children: [
|
|
156
151
|
{
|
|
157
152
|
label_en: "People in work",
|
|
@@ -169,7 +164,6 @@
|
|
|
169
164
|
label_en: "People, population and community",
|
|
170
165
|
label_cy: "Pobl, y boblogaeth a chymunedau",
|
|
171
166
|
url: "/peoplepopulationandcommunity",
|
|
172
|
-
expanded: false,
|
|
173
167
|
children: [
|
|
174
168
|
{
|
|
175
169
|
label_en: "Births, deaths and marriages",
|
|
@@ -247,122 +241,11 @@
|
|
|
247
241
|
Search: "Chwilio",
|
|
248
242
|
Menu: "Dewislen",
|
|
249
243
|
"Hide search": "Cuddio",
|
|
250
|
-
"Office for National Statistics logo
|
|
244
|
+
"Office for National Statistics logo": "Logo Swyddfa Ystadegau Gwladol",
|
|
245
|
+
Homepage: "Hafan",
|
|
251
246
|
"Search for a keyword(s) or time series ID": "Chwilio am allweddair neu ID cyfres amser"
|
|
252
247
|
};
|
|
253
248
|
|
|
254
|
-
function toggle_sm(e, i) {
|
|
255
|
-
if (window.matchMedia("(max-width:767px)").matches) {
|
|
256
|
-
e.preventDefault();
|
|
257
|
-
menu[i].expanded = !menu[i].expanded;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function handleKeydown(event) {
|
|
262
|
-
const target = event.currentTarget;
|
|
263
|
-
// Find the currently focused expandable child link within the navigation item
|
|
264
|
-
const focusedExpandableChild = target.querySelector(".js-expandable__child a:focus");
|
|
265
|
-
|
|
266
|
-
// Find all child links in the current navigation item
|
|
267
|
-
const childLinks = Array.from(target.querySelectorAll(".js-expandable__child a"));
|
|
268
|
-
|
|
269
|
-
// Close any expanded items from mouse events
|
|
270
|
-
const allExpandedItems = document.querySelectorAll(".js-expandable-active");
|
|
271
|
-
allExpandedItems.forEach((item) => {
|
|
272
|
-
if (item !== target) {
|
|
273
|
-
item.classList.remove("js-expandable-active");
|
|
274
|
-
const content = item.querySelector(".js-expandable__content");
|
|
275
|
-
if (content) {
|
|
276
|
-
content.classList.add("js-nav-hidden");
|
|
277
|
-
content.setAttribute("aria-expanded", "false");
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
switch (event.key) {
|
|
283
|
-
case "Tab":
|
|
284
|
-
if (focusedExpandableChild) {
|
|
285
|
-
target.classList.remove("primary-nav__item--focus");
|
|
286
|
-
}
|
|
287
|
-
break;
|
|
288
|
-
|
|
289
|
-
case "Escape":
|
|
290
|
-
event.preventDefault();
|
|
291
|
-
target.classList.remove("primary-nav__item--focus");
|
|
292
|
-
const firstNavLink = target.closest(".js-nav").querySelector("a:first-child");
|
|
293
|
-
if (firstNavLink) {
|
|
294
|
-
firstNavLink.classList.add("hide-children");
|
|
295
|
-
firstNavLink.focus();
|
|
296
|
-
firstNavLink.addEventListener(
|
|
297
|
-
"focusout",
|
|
298
|
-
() => {
|
|
299
|
-
firstNavLink.classList.remove("hide-children");
|
|
300
|
-
},
|
|
301
|
-
{ once: true }
|
|
302
|
-
);
|
|
303
|
-
}
|
|
304
|
-
break;
|
|
305
|
-
|
|
306
|
-
case "ArrowDown":
|
|
307
|
-
event.preventDefault();
|
|
308
|
-
if (!focusedExpandableChild) {
|
|
309
|
-
// If no child is focused, focus the first child. Needs to start from 0 as first child is link to primary nav.
|
|
310
|
-
const firstChild = childLinks[1];
|
|
311
|
-
if (firstChild) {
|
|
312
|
-
console.log("add focus");
|
|
313
|
-
target.classList.add("primary-nav__item--focus");
|
|
314
|
-
firstChild.focus({ focusVisible: true });
|
|
315
|
-
}
|
|
316
|
-
} else {
|
|
317
|
-
// Find the current index and move to the next child
|
|
318
|
-
const currentIndex = childLinks.indexOf(focusedExpandableChild);
|
|
319
|
-
if (currentIndex < childLinks.length - 1) {
|
|
320
|
-
childLinks[currentIndex + 1].focus();
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
break;
|
|
324
|
-
|
|
325
|
-
case "ArrowUp":
|
|
326
|
-
event.preventDefault();
|
|
327
|
-
|
|
328
|
-
if (focusedExpandableChild) {
|
|
329
|
-
const currentIndex = childLinks.indexOf(focusedExpandableChild);
|
|
330
|
-
if (currentIndex > 0) {
|
|
331
|
-
// Move to previous child
|
|
332
|
-
childLinks[currentIndex - 1].focus();
|
|
333
|
-
} else {
|
|
334
|
-
// If at first child, move focus back to main nav link
|
|
335
|
-
target.classList.remove("primary-nav__item--focus");
|
|
336
|
-
const mainLink = target.querySelector("a:first-child");
|
|
337
|
-
if (mainLink) {
|
|
338
|
-
mainLink.focus();
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
break;
|
|
343
|
-
|
|
344
|
-
case "ArrowRight":
|
|
345
|
-
event.preventDefault();
|
|
346
|
-
target.classList.remove("primary-nav__item--focus");
|
|
347
|
-
const nextNav = target.closest(".js-nav").nextElementSibling;
|
|
348
|
-
if (nextNav) {
|
|
349
|
-
const firstLink = nextNav.querySelector("a:first-child");
|
|
350
|
-
if (firstLink) firstLink.focus();
|
|
351
|
-
}
|
|
352
|
-
break;
|
|
353
|
-
|
|
354
|
-
case "ArrowLeft":
|
|
355
|
-
event.preventDefault();
|
|
356
|
-
target.classList.remove("primary-nav__item--focus");
|
|
357
|
-
const prevNav = target.closest(".js-nav").previousElementSibling;
|
|
358
|
-
if (prevNav) {
|
|
359
|
-
const firstLink = prevNav.querySelector("a:first-child");
|
|
360
|
-
if (firstLink) firstLink.focus();
|
|
361
|
-
}
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
249
|
function setPaths() {
|
|
367
250
|
const url = page?.url || document.location;
|
|
368
251
|
lang = url.host.startsWith("cy") ? "cy" : "en";
|
|
@@ -372,18 +255,7 @@
|
|
|
372
255
|
}
|
|
373
256
|
onMount(() => {
|
|
374
257
|
setPaths();
|
|
375
|
-
|
|
376
|
-
/// Add keyboard event listeners
|
|
377
|
-
const navItems = document.querySelectorAll(".js-nav");
|
|
378
|
-
navItems.forEach((item) => {
|
|
379
|
-
item.addEventListener("keydown", handleKeydown);
|
|
380
|
-
});
|
|
381
|
-
|
|
382
|
-
return () => {
|
|
383
|
-
navItems.forEach((item) => {
|
|
384
|
-
item.removeEventListener("keydown", handleKeydown);
|
|
385
|
-
});
|
|
386
|
-
};
|
|
258
|
+
initNav();
|
|
387
259
|
});
|
|
388
260
|
|
|
389
261
|
$: i18n = (text) => (lang === "cy" && texts[text] ? texts[text] : text);
|
|
@@ -419,7 +291,11 @@
|
|
|
419
291
|
class="ons-header__grid-top ons-grid ons-grid-flex ons-grid-flex--between ons-grid-flex--vertical-center ons-grid-flex--no-wrap ons-grid--gutterless"
|
|
420
292
|
>
|
|
421
293
|
<div class="ons-grid__col ons-col-auto">
|
|
422
|
-
<a
|
|
294
|
+
<a
|
|
295
|
+
class="ons-header__org-logo-link"
|
|
296
|
+
href={baseurl}
|
|
297
|
+
aria-label="{i18n('Office for National Statistics logo')} - {i18n('Homepage')}"
|
|
298
|
+
>
|
|
423
299
|
<div class="ons-header__org-logo ons-header__org-logo--large">
|
|
424
300
|
<svg
|
|
425
301
|
class="ons-icon--logo"
|
|
@@ -430,7 +306,9 @@
|
|
|
430
306
|
aria-labelledby="ons-logo-en-alt"
|
|
431
307
|
role="img"
|
|
432
308
|
>
|
|
433
|
-
<title id="ons-logo-en-alt"
|
|
309
|
+
<title id="ons-logo-en-alt"
|
|
310
|
+
>{i18n("Office for National Statistics logo")} - {i18n("Homepage")}</title
|
|
311
|
+
>
|
|
434
312
|
<g
|
|
435
313
|
class="ons-icon--logo__group ons-icon--logo__group--secondary"
|
|
436
314
|
fill="#a8bd3a"
|
|
@@ -543,7 +421,7 @@
|
|
|
543
421
|
role="img"
|
|
544
422
|
>
|
|
545
423
|
<title id="ons-logo-stacked-en-alt">
|
|
546
|
-
Office for National Statistics logo
|
|
424
|
+
{i18n("Office for National Statistics logo")}
|
|
547
425
|
</title>
|
|
548
426
|
<g
|
|
549
427
|
class="ons-icon--logo__group ons-icon--logo__group--secondary"
|
|
@@ -577,7 +455,10 @@
|
|
|
577
455
|
<div class="ons-container">
|
|
578
456
|
<div class="header col-wrap">
|
|
579
457
|
<div class="col col--lg-one-third col--md-one-third">
|
|
580
|
-
<a
|
|
458
|
+
<a
|
|
459
|
+
href="{baseurl}/"
|
|
460
|
+
aria-label="{i18n('Office for National Statistics logo')} - {i18n('Homepage')}"
|
|
461
|
+
>
|
|
581
462
|
<svg
|
|
582
463
|
version="1.1"
|
|
583
464
|
xmlns="http://www.w3.org/2000/svg"
|
|
@@ -586,7 +467,7 @@
|
|
|
586
467
|
aria-hidden="true"
|
|
587
468
|
class="logo"
|
|
588
469
|
>
|
|
589
|
-
<title>Office for National Statistics logo - Homepage</title>
|
|
470
|
+
<title>{i18n("Office for National Statistics logo")} - {i18n("Homepage")}</title>
|
|
590
471
|
<path
|
|
591
472
|
class="ons-icon--logo__group ons-icon--logo__group--secondary"
|
|
592
473
|
d="M0,70.5c1.8-3.7,3.6-7.2,5.6-10.7C3.3,54.2,1.5,48.5,0,42.6V70.5 M10.9,0C10.9,0,0,0,0,13.5v7.2
|
|
@@ -683,46 +564,35 @@
|
|
|
683
564
|
<!-- Controls -->
|
|
684
565
|
<nav aria-label="Header links">
|
|
685
566
|
<ul class="nav--controls">
|
|
686
|
-
<li class="nav--controls__item"
|
|
567
|
+
<li class="nav--controls__item">
|
|
687
568
|
<a
|
|
688
569
|
href="#nav-primary"
|
|
689
570
|
id="menu-toggle"
|
|
690
571
|
aria-controls="nav-primary"
|
|
691
|
-
aria-expanded=
|
|
572
|
+
aria-expanded="false"
|
|
692
573
|
class="nav--controls__menu"
|
|
693
|
-
on:click|preventDefault={() => {
|
|
694
|
-
menuExpanded = !menuExpanded;
|
|
695
|
-
searchExpanded = false;
|
|
696
|
-
}}
|
|
697
574
|
>
|
|
698
575
|
<span class="nav--controls__text">{i18n("Menu")}</span>
|
|
699
576
|
</a>
|
|
700
577
|
</li>
|
|
701
|
-
<li class="nav--controls__item"
|
|
578
|
+
<li class="nav--controls__item">
|
|
702
579
|
<a
|
|
703
580
|
href="#nav-search"
|
|
704
581
|
id="search-toggle"
|
|
705
582
|
aria-controls="nav-search"
|
|
706
|
-
aria-expanded=
|
|
583
|
+
aria-expanded="false"
|
|
707
584
|
class="nav--controls__search"
|
|
708
|
-
on:click|preventDefault={() => {
|
|
709
|
-
searchExpanded = !searchExpanded;
|
|
710
|
-
menuExpanded = false;
|
|
711
|
-
}}
|
|
712
585
|
>
|
|
713
|
-
<span class="nav--controls__text"
|
|
714
|
-
>{searchExpanded ? i18n("Hide search") : i18n("Search")}</span
|
|
715
|
-
>
|
|
586
|
+
<span class="nav--controls__text">{i18n("Search")}</span>
|
|
716
587
|
</a>
|
|
717
588
|
</li>
|
|
718
589
|
</ul>
|
|
719
590
|
|
|
720
591
|
<!-- Main Navigation -->
|
|
721
592
|
<ul
|
|
722
|
-
class="ons-container primary-nav__list"
|
|
723
|
-
class:nav-main--hidden={!menuExpanded}
|
|
593
|
+
class="ons-container nav-main--hidden primary-nav__list"
|
|
724
594
|
id="nav-primary"
|
|
725
|
-
aria-expanded=
|
|
595
|
+
aria-expanded="false"
|
|
726
596
|
>
|
|
727
597
|
<!-- Home Link -->
|
|
728
598
|
<li class="primary-nav__item js-nav">
|
|
@@ -732,14 +602,9 @@
|
|
|
732
602
|
</li>
|
|
733
603
|
|
|
734
604
|
<!-- Menu Items -->
|
|
735
|
-
{#each
|
|
736
|
-
.filter((d) => d.children)
|
|
737
|
-
.sort( (a, b) => a["label_" + lang].localeCompare(b["label_" + lang]) ), ...menu.filter((d) => !d.children)] as item, i}
|
|
605
|
+
{#each menu.filter((d) => !d.secondary) as item, i}
|
|
738
606
|
{#if item.children}
|
|
739
|
-
<li
|
|
740
|
-
class="primary-nav__item js-nav js-expandable"
|
|
741
|
-
class:js-expandable-active={item.expanded}
|
|
742
|
-
>
|
|
607
|
+
<li class="primary-nav__item js-nav js-expandable">
|
|
743
608
|
<a
|
|
744
609
|
class="primary-nav__link col col--md-8 col--lg-10"
|
|
745
610
|
href="{baseurl}{item.url}"
|
|
@@ -753,16 +618,10 @@
|
|
|
753
618
|
</span>
|
|
754
619
|
</a>
|
|
755
620
|
<ul
|
|
756
|
-
class="primary-nav__child-list col col--md-16 col--lg-20 js-expandable__content jsEnhance"
|
|
757
|
-
|
|
758
|
-
aria-expanded={item.expanded}
|
|
621
|
+
class="primary-nav__child-list col col--md-16 col--lg-20 js-expandable__content js-nav-hidden jsEnhance"
|
|
622
|
+
aria-expanded="false"
|
|
759
623
|
aria-label="submenu"
|
|
760
624
|
>
|
|
761
|
-
<li class="primary-nav__child-item js-expandable__child hide--md">
|
|
762
|
-
<a class="primary-nav__child-link" tabindex="-1" href="{baseurl}{item.url}"
|
|
763
|
-
>{item[`label_${lang}`]}</a
|
|
764
|
-
>
|
|
765
|
-
</li>
|
|
766
625
|
{#each [...item.children].sort( (a, b) => a[`label_${lang}`].localeCompare(b[`label_${lang}`]) ) as child}
|
|
767
626
|
<li class="primary-nav__child-item js-expandable__child">
|
|
768
627
|
<a
|
|
@@ -775,7 +634,7 @@
|
|
|
775
634
|
</ul>
|
|
776
635
|
</li>
|
|
777
636
|
{:else}
|
|
778
|
-
<li class="primary-nav__item js-nav"
|
|
637
|
+
<li class="primary-nav__item js-nav">
|
|
779
638
|
<a
|
|
780
639
|
class="primary-nav__link col col--md-8 col--lg-10"
|
|
781
640
|
href="{baseurl}{item.url}"
|
|
@@ -799,7 +658,7 @@
|
|
|
799
658
|
</ul>
|
|
800
659
|
</nav>
|
|
801
660
|
</div>
|
|
802
|
-
<div class="search
|
|
661
|
+
<div class="search nav-search--hidden print--hide" id="searchBar">
|
|
803
662
|
<div class="ons-container" role="search">
|
|
804
663
|
<form class="col-wrap search__form" action="{baseurl}/search">
|
|
805
664
|
<label class="search__label col col--md-23 col--lg-24" for="nav-search"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function initNav(): void;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
function getBoolFromString(stringToConvert) {
|
|
2
|
+
return stringToConvert === "true";
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function toggleSubnav(element) {
|
|
6
|
+
const subnav = element;
|
|
7
|
+
subnav.classList.toggle("js-expandable-active");
|
|
8
|
+
subnav.querySelectorAll(".js-expandable__content").forEach((el) => {
|
|
9
|
+
el.classList.toggle("js-nav-hidden");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const elementAria = getBoolFromString(element.querySelector("a:first-child").ariaExpanded);
|
|
13
|
+
subnav.querySelector("a:first-child").ariaExpanded = !elementAria;
|
|
14
|
+
const subnavAria = getBoolFromString(
|
|
15
|
+
element.querySelector(".js-expandable__content").ariaExpanded
|
|
16
|
+
);
|
|
17
|
+
subnav.querySelector(".js-expandable__content").ariaExpanded = !subnavAria;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function toggleMenu(toggleElement, menuElement) {
|
|
21
|
+
const toggle = toggleElement;
|
|
22
|
+
const menu = menuElement;
|
|
23
|
+
toggle.classList.toggle("menu-is-expanded");
|
|
24
|
+
const toggleAriaState = getBoolFromString(toggle.querySelector("a").ariaExpanded);
|
|
25
|
+
toggle.querySelector("a").ariaExpanded = !toggleAriaState;
|
|
26
|
+
menu.classList.toggle("nav-main--hidden");
|
|
27
|
+
const menuAriaState = getBoolFromString(menuElement.ariaExpanded);
|
|
28
|
+
menu.ariaExpanded = !menuAriaState;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function toggleSearch(toggleElement, searchElement) {
|
|
32
|
+
const toggle = toggleElement;
|
|
33
|
+
const search = searchElement;
|
|
34
|
+
const langAttribute = document.documentElement.lang;
|
|
35
|
+
toggle.classList.toggle("search-is-expanded");
|
|
36
|
+
const toggleAriaState = getBoolFromString(toggle.querySelector("a").ariaExpanded);
|
|
37
|
+
toggle.querySelector("a").ariaExpanded = !toggleAriaState;
|
|
38
|
+
let searchStr = "";
|
|
39
|
+
if (langAttribute === "en") {
|
|
40
|
+
searchStr = "Hide search";
|
|
41
|
+
if (toggle.querySelector(".nav--controls__text").textContent.includes("Hide")) {
|
|
42
|
+
searchStr = "Search";
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
searchStr = "Cuddio";
|
|
46
|
+
if (toggle.querySelector(".nav--controls__text").textContent.includes("Cuddio")) {
|
|
47
|
+
searchStr = "Chwilio";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
toggle.querySelector(".nav--controls__text").textContent = searchStr;
|
|
51
|
+
search.classList.toggle("nav-search--hidden");
|
|
52
|
+
const searchAriaState = getBoolFromString(search.ariaExpanded);
|
|
53
|
+
search.ariaExpanded = !searchAriaState;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function cloneSecondaryNav() {
|
|
57
|
+
// On mobile move secondary nav items in header to primary nav
|
|
58
|
+
const navLink = document.querySelectorAll(".js-nav-clone__link");
|
|
59
|
+
const navList = document.querySelector(".js-nav-clone__list");
|
|
60
|
+
|
|
61
|
+
if (
|
|
62
|
+
document.body.classList.contains("viewport-sm") &&
|
|
63
|
+
navList.querySelectorAll(".js-nav-clone__link").length > 0
|
|
64
|
+
) {
|
|
65
|
+
// Remove from separate UL and add into primary
|
|
66
|
+
navLink.forEach((l) => {
|
|
67
|
+
const link = l;
|
|
68
|
+
link.parentNode.style.display = "none";
|
|
69
|
+
const newNavItem = document.createElement("li");
|
|
70
|
+
newNavItem.classList.add("primary-nav__item");
|
|
71
|
+
|
|
72
|
+
link.classList.remove("secondary-nav__link");
|
|
73
|
+
link.classList.add("primary-nav__link", "col");
|
|
74
|
+
|
|
75
|
+
newNavItem.insertAdjacentElement("beforeend", link);
|
|
76
|
+
|
|
77
|
+
const primaryNavList = document.querySelector(".primary-nav__list li.primary-nav__language");
|
|
78
|
+
primaryNavList.insertAdjacentElement("beforebegin", newNavItem);
|
|
79
|
+
});
|
|
80
|
+
} else if (
|
|
81
|
+
!document.body.classList.contains("viewport-sm") &&
|
|
82
|
+
document.querySelector(".secondary-nav__item").style.display === "none"
|
|
83
|
+
) {
|
|
84
|
+
// Remove from primary nav and add into separate secondary list
|
|
85
|
+
navLink.forEach((l, i) => {
|
|
86
|
+
const index = i + 1;
|
|
87
|
+
const link = l;
|
|
88
|
+
link.classList.add("secondary-nav__link");
|
|
89
|
+
link.classList.remove("primary-nav__link", "col");
|
|
90
|
+
link.parentNode.remove();
|
|
91
|
+
const cloneList = document.querySelector(`.js-nav-clone__list li:nth-child(${index})`);
|
|
92
|
+
cloneList.insertAdjacentElement("beforeend", link);
|
|
93
|
+
link.parentNode.style.display = "block";
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function clonePrimaryItems() {
|
|
99
|
+
const detectDuplicate = document.querySelectorAll(".js-nav__duplicate");
|
|
100
|
+
const expandableList = document.querySelectorAll(".js-expandable");
|
|
101
|
+
|
|
102
|
+
// Clone primary nav items into sub-menu on mobile, so it can still be selected on mobile
|
|
103
|
+
if (document.body.classList.contains("viewport-sm") && detectDuplicate.length === 0) {
|
|
104
|
+
expandableList.forEach((item) => {
|
|
105
|
+
const href = item.querySelector("a").getAttribute("href");
|
|
106
|
+
const text = item.querySelector(".submenu-title").innerText;
|
|
107
|
+
const childList = item.querySelector(".js-expandable__content");
|
|
108
|
+
|
|
109
|
+
const newLink = document.createElement("a");
|
|
110
|
+
newLink.classList.add("primary-nav__child-link");
|
|
111
|
+
newLink.href = href;
|
|
112
|
+
newLink.innerText = text.trim();
|
|
113
|
+
|
|
114
|
+
const newItem = document.createElement("li");
|
|
115
|
+
newItem.classList.add("primary-nav__child-item", "js-nav__duplicate", "js-expandable__child");
|
|
116
|
+
newItem.insertAdjacentElement("beforeend", newLink);
|
|
117
|
+
childList.insertBefore(newItem, childList.firstChild);
|
|
118
|
+
});
|
|
119
|
+
} else if (!document.body.classList.contains("viewport-sm") && detectDuplicate.length > 0) {
|
|
120
|
+
detectDuplicate.forEach((duplicate) => {
|
|
121
|
+
duplicate.remove();
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default function initNav() {
|
|
127
|
+
window.addEventListener("resize", () => {
|
|
128
|
+
clonePrimaryItems();
|
|
129
|
+
cloneSecondaryNav();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
document.addEventListener("keydown", (e) => {
|
|
133
|
+
if (e.key === "Escape") {
|
|
134
|
+
// Find all nav items currently hovered (with open submenu)
|
|
135
|
+
document.querySelectorAll(".primary-nav__item:hover > ul").forEach((submenu) => {
|
|
136
|
+
submenu.classList.add("ons-u-hidden");
|
|
137
|
+
const parentItem = submenu.closest(".primary-nav__item");
|
|
138
|
+
// Handler to restore submenu on mouse leave
|
|
139
|
+
const handleMouseLeave = () => {
|
|
140
|
+
submenu.classList.remove("ons-u-hidden");
|
|
141
|
+
parentItem.removeEventListener("mouseleave", handleMouseLeave);
|
|
142
|
+
};
|
|
143
|
+
parentItem.addEventListener("mouseleave", handleMouseLeave, { once: true });
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const primaryNav = document.querySelector("#nav-primary");
|
|
149
|
+
const searchBar = document.querySelector("#searchBar");
|
|
150
|
+
const navItem = document.querySelectorAll(".js-nav");
|
|
151
|
+
const expandableItems = document.querySelectorAll(".js-expandable");
|
|
152
|
+
|
|
153
|
+
clonePrimaryItems();
|
|
154
|
+
cloneSecondaryNav();
|
|
155
|
+
|
|
156
|
+
primaryNav.classList.add("nav-main--hidden");
|
|
157
|
+
primaryNav.ariaExpanded = false;
|
|
158
|
+
|
|
159
|
+
expandableItems.forEach((item) => {
|
|
160
|
+
item.addEventListener("click", (event) => {
|
|
161
|
+
if (document.body.classList.contains("viewport-sm")) {
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
toggleSubnav(item);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// stop parent element from taking over all click events
|
|
169
|
+
document.querySelectorAll(".js-expandable > .js-expandable__content").forEach((elem) => {
|
|
170
|
+
elem.addEventListener("click", (event) => {
|
|
171
|
+
event.stopPropagation();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
navItem.forEach((item) => {
|
|
176
|
+
item.addEventListener("keydown", (e) => {
|
|
177
|
+
const focusedItem = document.querySelector(".js-expandable__child a:focus"); // only selects child item that is in focus
|
|
178
|
+
const keycode = e.keyCode;
|
|
179
|
+
const up = 38;
|
|
180
|
+
const down = 40;
|
|
181
|
+
const right = 39;
|
|
182
|
+
const left = 37;
|
|
183
|
+
const esc = 27;
|
|
184
|
+
const tab = 9;
|
|
185
|
+
if (keycode === tab && focusedItem) {
|
|
186
|
+
item.classList.remove("primary-nav__item--focus");
|
|
187
|
+
item.nextElementSibling?.focus();
|
|
188
|
+
}
|
|
189
|
+
if (keycode === esc) {
|
|
190
|
+
item.classList.remove("primary-nav__item--focus");
|
|
191
|
+
const closestNav = item.closest(".js-nav");
|
|
192
|
+
const link = closestNav.querySelector("a");
|
|
193
|
+
link.classList.add("hide-children");
|
|
194
|
+
link.focus();
|
|
195
|
+
link.addEventListener("focusout", () => {
|
|
196
|
+
link.classList.remove("hide-children");
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (keycode === down) {
|
|
200
|
+
e.preventDefault();
|
|
201
|
+
item.classList.add("primary-nav__item--focus");
|
|
202
|
+
if (focusedItem) {
|
|
203
|
+
focusedItem.parentElement.nextElementSibling?.querySelector("a").focus();
|
|
204
|
+
} else {
|
|
205
|
+
item.querySelector(".js-expandable__child a")?.focus();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (keycode === up) {
|
|
209
|
+
e.preventDefault();
|
|
210
|
+
if (focusedItem && focusedItem.parentElement.previousElementSibling) {
|
|
211
|
+
focusedItem.parentElement.previousElementSibling?.querySelector("a").focus();
|
|
212
|
+
} else {
|
|
213
|
+
item.classList.remove("primary-nav__item--focus");
|
|
214
|
+
item.querySelector("a")?.focus();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
if (keycode === right) {
|
|
218
|
+
e.preventDefault();
|
|
219
|
+
item.classList.remove("primary-nav__item--focus");
|
|
220
|
+
const closestNav = item.closest(".js-nav");
|
|
221
|
+
closestNav.nextElementSibling?.querySelector("a").focus();
|
|
222
|
+
}
|
|
223
|
+
if (keycode === left) {
|
|
224
|
+
e.preventDefault();
|
|
225
|
+
item.classList.remove("primary-nav__item--focus");
|
|
226
|
+
const closestNav = item.closest(".js-nav");
|
|
227
|
+
closestNav.previousElementSibling?.querySelector("a").focus();
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
const expandBehaviour = (item, expandedBool) => {
|
|
233
|
+
if (!document.body.classList.contains("viewport-sm")) {
|
|
234
|
+
const navLink = item.querySelector(".primary-nav__link");
|
|
235
|
+
navLink.ariaExpanded = expandedBool;
|
|
236
|
+
const expandable = item.querySelector(".js-expandable__content");
|
|
237
|
+
expandable.ariaExpanded = expandedBool;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
expandableItems.forEach((item) => {
|
|
242
|
+
item.addEventListener("focusin", () => expandBehaviour(item, true));
|
|
243
|
+
item.addEventListener("pointerenter", () => expandBehaviour(item, true));
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
expandableItems.forEach((item) => {
|
|
247
|
+
item.addEventListener("focusout", () => expandBehaviour(item, false));
|
|
248
|
+
item.addEventListener("pointerleave", () => expandBehaviour(item, false));
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const menuToggle = document.querySelector("#menu-toggle");
|
|
252
|
+
const menuToggleContainer = menuToggle.parentNode;
|
|
253
|
+
const searchToggle = document.querySelector("#search-toggle");
|
|
254
|
+
const searchToggleContainer = searchToggle.parentNode;
|
|
255
|
+
|
|
256
|
+
menuToggle.addEventListener("click", (event) => {
|
|
257
|
+
event.preventDefault();
|
|
258
|
+
if (!searchBar.classList.contains("nav-search--hidden")) {
|
|
259
|
+
toggleSearch(searchToggleContainer, searchBar);
|
|
260
|
+
}
|
|
261
|
+
toggleMenu(menuToggleContainer, primaryNav);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
searchToggle.addEventListener("click", (event) => {
|
|
265
|
+
event.preventDefault();
|
|
266
|
+
if (!primaryNav.classList.contains("nav-main--hidden")) {
|
|
267
|
+
toggleMenu(menuToggleContainer, primaryNav);
|
|
268
|
+
}
|
|
269
|
+
toggleSearch(searchToggleContainer, searchBar);
|
|
270
|
+
});
|
|
271
|
+
}
|