Skip to content

Commit a879403

Browse files
authored
Merge pull request #68 from IATI/jump-menu
Jump menu tweaks
2 parents d71ba9b + 6bc873a commit a879403

File tree

3 files changed

+147
-11
lines changed

3 files changed

+147
-11
lines changed

src/js/components/jump-menu/jump-menu.js

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,52 @@
1515
jumpMenuToggle.setAttribute("aria-expanded", "false");
1616
}
1717
};
18-
document.addEventListener("DOMContentLoaded", () => {
19-
const jumpMenuItems = document.querySelector(".js-jump-menu-items");
20-
const jumpMenuToggle = document.querySelector(".js-jump-menu-toggle");
21-
if (jumpMenuItems && jumpMenuToggle) {
22-
toggleMenuMenuItemsVisibility(false, jumpMenuItems, jumpMenuToggle);
23-
jumpMenuToggle.addEventListener("click", () => {
24-
const isHidden = jumpMenuItems.getAttribute("aria-hidden");
25-
toggleMenuMenuItemsVisibility(isHidden, jumpMenuItems, jumpMenuToggle);
26-
});
18+
19+
const initialiseJumpMenu = (jumpMenuToggle) => {
20+
// Check if this toggle has already been initialised
21+
if (jumpMenuToggle.hasAttribute("data-jump-menu-initialised")) {
22+
return;
23+
}
24+
25+
// Find the corresponding menu items within the same jump menu container
26+
const jumpMenuContainer = jumpMenuToggle.closest(".iati-jump-menu");
27+
if (!jumpMenuContainer) {
28+
return;
29+
}
30+
31+
const jumpMenuItems = jumpMenuContainer.querySelector(
32+
".js-jump-menu-items",
33+
);
34+
if (!jumpMenuItems) {
35+
return;
2736
}
37+
38+
// Mark as initialised to prevent duplicate event listeners
39+
jumpMenuToggle.setAttribute("data-jump-menu-initialised", "true");
40+
41+
// Initialise menu as hidden on mobile
42+
jumpMenuItems.setAttribute("aria-hidden", "true");
43+
jumpMenuToggle.setAttribute("aria-expanded", "false");
44+
45+
const handleToggleClick = (event) => {
46+
event.preventDefault();
47+
event.stopPropagation();
48+
const isHidden = jumpMenuItems.getAttribute("aria-hidden") === "true";
49+
toggleMenuMenuItemsVisibility(isHidden, jumpMenuItems, jumpMenuToggle);
50+
};
51+
52+
jumpMenuToggle.addEventListener("click", handleToggleClick);
53+
};
54+
55+
const initialiseAllJumpMenus = () => {
56+
const jumpMenuToggles = document.querySelectorAll(".js-jump-menu-toggle");
57+
58+
jumpMenuToggles.forEach((toggle) => {
59+
initialiseJumpMenu(toggle);
60+
});
61+
};
62+
63+
document.addEventListener("DOMContentLoaded", () => {
64+
initialiseAllJumpMenus();
2865
});
2966
})();

src/scss/components/jump-menu/_jump-menu.scss

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
padding: 0.4em;
7777
transition: all 0.2s ease-in-out;
7878
&:hover {
79-
background-color: $color-green-20;
79+
background-color: $color-green-10;
8080
border-color: $color-teal-90;
8181
}
8282
}
@@ -95,4 +95,36 @@
9595
text-decoration: none;
9696
}
9797
}
98+
99+
&__subitem {
100+
line-height: 1;
101+
padding: 0.4em;
102+
padding-inline-start: 1rem;
103+
margin-left: 0.25rem;
104+
transition: all 0.2s ease-in-out;
105+
106+
&:hover {
107+
background-color: $color-green-10;
108+
}
109+
}
110+
111+
&__sublink {
112+
display: block;
113+
text-transform: uppercase;
114+
color: $color-teal-90;
115+
font-size: 0.75rem;
116+
font-weight: 800;
117+
line-height: 1.5;
118+
119+
&:active,
120+
&:focus,
121+
&:hover {
122+
text-decoration: none;
123+
}
124+
}
125+
126+
// Add top padding only to the first sublink in each subitems section
127+
&__subitem:first-child .iati-jump-menu__sublink {
128+
padding-top: 0.25rem;
129+
}
98130
}

src/scss/components/jump-menu/jump-menu.stories.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@ export const Default: Story = {
3030
<button
3131
class="iati-jump-menu__toggle js-jump-menu-toggle"
3232
aria-controls="iati-jump-menu-items"
33-
aria-expanded="true"
33+
aria-expanded="false"
3434
>
3535
Open
3636
</button>
3737
</div>
3838
<ul
3939
id="iati-jump-menu-items"
4040
class="iati-jump-menu__items js-jump-menu-items"
41+
aria-hidden="true"
4142
>
4243
${items.map(
4344
(item) =>
@@ -49,3 +50,69 @@ export const Default: Story = {
4950
</nav>
5051
`,
5152
};
53+
54+
export const WithSubMenus: Story = {
55+
args: {
56+
items: [
57+
{ text: "First section", link: "#" },
58+
{
59+
text: "Second section",
60+
children: [
61+
{ text: "First subsection", link: "#" },
62+
{ text: "Second subsection", link: "#" },
63+
{ text: "Another subsection", link: "#" },
64+
],
65+
},
66+
{ text: "Another section", link: "#" },
67+
{
68+
text: "A slightly longer title",
69+
children: [
70+
{ text: "Subsection", link: "#" },
71+
{ text: "Another subsection", link: "#" },
72+
],
73+
},
74+
{ text: "Final section", link: "#" },
75+
],
76+
},
77+
render: ({ items }) => html`
78+
<nav class="iati-jump-menu">
79+
<div class="iati-jump-menu__header">
80+
<h2 class="iati-jump-menu__title">Jump to section</h2>
81+
<button
82+
class="iati-jump-menu__toggle js-jump-menu-toggle"
83+
aria-controls="iati-jump-menu-items"
84+
aria-expanded="false"
85+
>
86+
Open
87+
</button>
88+
</div>
89+
<ul
90+
id="iati-jump-menu-items"
91+
class="iati-jump-menu__items js-jump-menu-items"
92+
aria-hidden="true"
93+
>
94+
${items.map((item) => {
95+
if (item.children) {
96+
return html`<li class="iati-jump-menu__item">
97+
<a href=${item.link || "#"} class="iati-jump-menu__link"
98+
>${item.text}</a
99+
>
100+
</li>
101+
${item.children.map(
102+
(child: any) =>
103+
html`<li class="iati-jump-menu__subitem">
104+
<a href=${child.link} class="iati-jump-menu__sublink"
105+
>${child.text}</a
106+
>
107+
</li>`,
108+
)}`;
109+
} else {
110+
return html`<li class="iati-jump-menu__item">
111+
<a href=${item.link} class="iati-jump-menu__link">${item.text}</a>
112+
</li>`;
113+
}
114+
})}
115+
</ul>
116+
</nav>
117+
`,
118+
};

0 commit comments

Comments
 (0)