Skip to content

Commit d2a0426

Browse files
authored
Merge pull request #234 from OpenSourceOrg/fix/t51eng-2081-review-findings-develop
Fix accessibility and robustness findings from the branch review (develop)
2 parents ffc0d85 + 511781f commit d2a0426

11 files changed

Lines changed: 104 additions & 44 deletions

‎themes/osi/assets/css/editor-style.css.map‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<?php return array('dependencies' => array(), 'version' => '0bfa516281fef59f8671');
1+
<?php return array('dependencies' => array(), 'version' => 'f179507f6e77a9763a06');

‎themes/osi/assets/js/build/theme.js‎

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎themes/osi/assets/js/src/theme/mega-menu.js‎

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ if ( header && megaItems.length ) {
2929
);
3030
};
3131

32+
const dismiss = ( item ) => {
33+
closeItem( item );
34+
item.classList.add( 'is-dismissed' );
35+
syncHeader();
36+
};
37+
3238
const closeItem = ( item ) => {
3339
item.classList.remove( 'is-open' );
3440
const trigger = triggerOf( item );
@@ -45,14 +51,14 @@ if ( header && megaItems.length ) {
4551
megaItems.forEach( ( item ) => {
4652
const trigger = triggerOf( item );
4753
let closeTimer = null;
54+
let suppressOpen = false;
4855

4956
if ( trigger ) {
50-
trigger.setAttribute( 'aria-haspopup', 'true' );
5157
trigger.setAttribute( 'aria-expanded', 'false' );
5258
}
5359

5460
const open = () => {
55-
if ( ! desktopNav.matches ) {
61+
if ( suppressOpen || ! desktopNav.matches ) {
5662
return;
5763
}
5864
window.clearTimeout( closeTimer );
@@ -96,19 +102,25 @@ if ( header && megaItems.length ) {
96102
}
97103

98104
item.addEventListener( 'mouseenter', open );
99-
item.addEventListener( 'mouseleave', () => close( false ) );
105+
item.addEventListener( 'mouseleave', () => {
106+
item.classList.remove( 'is-dismissed' );
107+
close( false );
108+
} );
100109
item.addEventListener( 'focusin', open );
101110
item.addEventListener( 'focusout', ( event ) => {
102111
if ( ! item.contains( event.relatedTarget ) ) {
103112
close( false );
104113
}
105114
} );
115+
// returning focus to the trigger fires focusin, which would reopen the panel
106116
item.addEventListener( 'keydown', ( event ) => {
107117
if ( 'Escape' === event.key && item.classList.contains( 'is-open' ) ) {
108-
close( true );
118+
suppressOpen = true;
119+
dismiss( item );
109120
if ( trigger ) {
110121
trigger.focus();
111122
}
123+
suppressOpen = false;
112124
}
113125
} );
114126
} );
@@ -122,6 +134,16 @@ if ( header && megaItems.length ) {
122134
}
123135
} );
124136

137+
// a panel opened by hover holds focus nowhere, so Escape has to be caught globally
138+
document.addEventListener( 'keydown', ( event ) => {
139+
if (
140+
'Escape' === event.key &&
141+
document.querySelector( '.nav-main--menu > .menu-item.megamenu.is-open' )
142+
) {
143+
megaItems.forEach( dismiss );
144+
}
145+
} );
146+
125147
desktopNav.addEventListener( 'change', ( event ) => {
126148
if ( ! event.matches ) {
127149
closeAll();

‎themes/osi/assets/scss/_1_settings.breakpoints.scss‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ $maxPadding: 48px; // duplicates var(--wp--custom--spacing--max-padding)
4646

4747
// header dimensions
4848
$headerInnerHeight: 125px; // .header--inner fixed height; admin-bar offsets come from core's --wp-admin--admin-bar--height
49+
$mobileRowHeight: 34px; // mobile accordion row: the caret's 44px tap target centres its glyph on this
4950
$midPadding: 32px; // duplicates var(--wp--custom--spacing--mid-padding);
5051
$smallPadding: 16px; // duplicates var(--wp--custom--spacing--small-padding);
5152

‎themes/osi/assets/scss/_6_components.header.scss‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@
182182
.header-main.is-nav-open {
183183
@include nav-open-layers;
184184
}
185-
.header-main:has(.menu-item.megamenu:hover) {
185+
// :not(.is-dismissed) so Escape clears the veil while the pointer is still on the item
186+
.header-main:has(.menu-item.megamenu:hover:not(.is-dismissed)) {
186187
@include nav-open-layers;
187188
}
188189
.header-main-small {

‎themes/osi/assets/scss/_6_components.navigation--subnav.scss‎

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
44
padding-right: 30px;
55
}
66

7-
.nav-main--menu, .nav-mobile--menu {
8-
ul.sub-menu a[href='#'] {
7+
// desktop only: on mobile these rows are the accordion trigger, and mobile-menu-toggle.js
8+
// needs the click. It calls preventDefault(), so the empty href never navigates.
9+
@media only screen and (min-width: #{$break-nav}) {
10+
.nav-main--menu ul.sub-menu a[href='#'] {
911
pointer-events: none;
1012
text-decoration: none;
1113
}
@@ -59,7 +61,7 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
5961
}
6062

6163
.megamenu-featured--heading {
62-
color: $brandColor1;
64+
color: $brandColor1_Dk;
6365
display: block;
6466
text-transform: uppercase;
6567
}
@@ -77,7 +79,7 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
7779
}
7880

7981
a.megamenu-featured--more {
80-
color: $brandColor1;
82+
color: $brandColor1_Dk;
8183
display: inline-block;
8284
font-weight: $baseWeightBold;
8385
padding: 0;
@@ -87,7 +89,7 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
8789
}
8890

8991
&:hover, &:focus {
90-
color: $brandColor1_Dk;
92+
color: $interactColor_Dk;
9193
text-decoration: underline;
9294
}
9395
}
@@ -159,12 +161,12 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
159161
.menu-item.current-menu-item > a,
160162
.menu-item.current-menu-parent > a,
161163
.menu-item.current-menu-ancestor > a {
162-
color: $brandColor1;
164+
color: $brandColor1_Dk;
163165
text-decoration: none;
164166
}
165167

166168
.menu-item.tab-active > a {
167-
color: $brandColor1;
169+
color: $brandColor1_Dk;
168170
font-weight: 700;
169171
}
170172

@@ -201,25 +203,34 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
201203
transition: all .3s;
202204

203205
&:after {
204-
color: $brandColor1;
206+
color: $brandColor1_Dk;
205207
}
206208
}
207209

210+
// the 44px tap target starts at the row's top edge, so centre the glyph on the
211+
// row height: 50% on the button would follow the expanded submenu down the page
208212
&:after {
209213
color: inherit;
210214
content: '\25BC';
211215
font-size: 12px;
212-
line-height: 44px;
216+
line-height: $mobileRowHeight;
213217
padding: 0;
214218
transform: none;
215219
}
216220
}
217221

218222
.menu-toggle-active:after {
219-
color: $brandColor1;
223+
color: $brandColor1_Dk;
220224
transform: rotate(180deg);
221225
}
222226

227+
// the generic sub-menu link hover (brand-links) outranks the shared card rule,
228+
// so the darker hover has to be set at this depth to win
229+
.megamenu-featured a.megamenu-featured--more:hover,
230+
.megamenu-featured a.megamenu-featured--more:focus {
231+
color: $interactColor_Dk;
232+
}
233+
223234
ul.sub-menu {
224235
margin-left: 0;
225236
margin-bottom: 20px;
@@ -426,7 +437,7 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
426437
margin-bottom: 1.25rem;
427438

428439
.megamenu-eyebrow {
429-
color: $brandColor1;
440+
color: $brandColor1_Dk;
430441
display: block;
431442
font-size: .85rem;
432443
font-weight: $baseWeightBold;
@@ -520,6 +531,11 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
520531
.megamenu-featured--more {
521532
margin-top: .75rem;
522533
padding: 0;
534+
535+
// as on mobile: the generic sub-menu link hover outranks the shared rule
536+
&:hover, &:focus {
537+
color: $interactColor_Dk;
538+
}
523539
}
524540
}
525541
}
@@ -531,10 +547,17 @@ $chevronDown: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/sv
531547
}
532548

533549
// separate rule, as above: an unparseable :has() would drop the JS one too
534-
.header-main:has(.menu-item.megamenu:hover) & > ul.sub-menu {
550+
.header-main:has(.menu-item.megamenu:hover:not(.is-dismissed)) & > ul.sub-menu {
535551
transition: none;
536552
}
537553

554+
// Escape sets .is-dismissed: without this the pointer still satisfies :hover below
555+
// and the panel stays up, since JS cannot clear a CSS hover state
556+
&.is-dismissed:hover > ul.sub-menu {
557+
opacity: 0;
558+
visibility: hidden;
559+
}
560+
538561
// keyboard open is JS-driven (.is-open); :focus-within here would defeat Escape
539562
&:hover > ul.sub-menu,
540563
&.is-open > ul.sub-menu {

‎themes/osi/assets/scss/_6_components.navigation.scss‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ footer {
176176
color: $Ndarkest;
177177

178178
&:hover, &:focus {
179-
color: $brandColor1;
179+
color: $brandColor1_Dk;
180180
}
181181
}
182182
}
@@ -195,7 +195,7 @@ footer {
195195
}
196196

197197
.nav-main .nav-main--cta {
198-
background-color: $brandColor1;
198+
background-color: $brandColor1_Dk;
199199
border-radius: 999px;
200200
bottom: 24px;
201201
color: $Nwhite;
@@ -216,7 +216,7 @@ footer {
216216
z-index: 5;
217217

218218
&:hover, &:focus {
219-
background-color: $brandColor1_Dk;
219+
background-color: $interactColor_Dk;
220220
color: $Nwhite;
221221
text-decoration: none;
222222
}

‎themes/osi/inc/template-functions.php‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ function osi_supporters_shortcode_renderer( array $args = array() ): string {
375375
*
376376
* @return array
377377
*/
378-
function osi_megamenu_placeholder_link_atts( array $atts, WP_Post $item, stdClass $args, int $depth ): array {
378+
function osi_megamenu_placeholder_link_atts( $atts, $item = null, $args = null, $depth = 0 ) { // phpcs:ignore Squiz.Commenting.FunctionComment.ScalarTypeHintMissing,Squiz.Commenting.FunctionComment.TypeHintMissing -- other walkers re-apply this filter with fewer arguments; typed params would fatal.
379379
if ( 0 < $depth && isset( $args->theme_location, $atts['href'] ) && 'primary_navigation' === $args->theme_location && '#' === $atts['href'] ) {
380380
$atts['tabindex'] = '-1';
381381
}

0 commit comments

Comments
 (0)