Skip to content

Commit

Permalink
fix(navigation): a11y focus trap when navigation is open in responsiv…
Browse files Browse the repository at this point in the history
…e mode

Signed-off-by: Bogdan Bogdanov <bbogdanov@vmware.com>
  • Loading branch information
bbogdanov committed Apr 13, 2022
1 parent 2fba7b8 commit af6c44c
Show file tree
Hide file tree
Showing 8 changed files with 910 additions and 45 deletions.
29 changes: 25 additions & 4 deletions projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2468,6 +2468,8 @@ export class ClrHeader implements OnDestroy {
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
openNav(navLevel: number): void;
// (undocumented)
openNavLevel: number;
// (undocumented)
resetNavTriggers(): void;
Expand All @@ -2479,7 +2481,7 @@ export class ClrHeader implements OnDestroy {
get responsiveNavCommonString(): string;
// (undocumented)
get responsiveOverflowCommonString(): string;
// (undocumented)
// @deprecated (undocumented)
toggleNav(navLevel: number): void;
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<ClrHeader, "clr-header", never, {}, {}, never, ["*"]>;
Expand Down Expand Up @@ -2998,29 +3000,48 @@ export class ClrNavigationModule {
static ɵmod: i0.ɵɵNgModuleDeclaration<ClrNavigationModule, [typeof i1_38.ClrHeader, typeof i2_28.ClrNavLevel, typeof i3_19.NavDetectionOompaLoompa, typeof i4_13.MainContainerWillyWonka], [typeof i6.CommonModule, typeof i3_2.ClrIconModule, typeof i8.ClrDropdownModule], [typeof i1_38.ClrHeader, typeof i2_28.ClrNavLevel, typeof i3_19.NavDetectionOompaLoompa, typeof i4_13.MainContainerWillyWonka]>;
}

// Warning: (ae-forgotten-export) The symbol "FocusTrap" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export class ClrNavLevel implements OnInit {
constructor(responsiveNavService: ResponsiveNavigationService, elementRef: ElementRef);
export class ClrNavLevel extends FocusTrap implements OnInit {
// Warning: (ae-forgotten-export) The symbol "FocusTrapElement" needs to be exported by the entry point index.d.ts
constructor(platformId: any, responsiveNavService: ResponsiveNavigationService, elementRef: ElementRef<FocusTrapElement>, renderer: Renderer2, injector: Injector);
// (undocumented)
addNavClass(level: number): void;
// (undocumented)
close(): void;
// (undocumented)
closeButtonAriaLabel: string;
// (undocumented)
protected hideCloseButton(): void;
// (undocumented)
protected hideNavigation(): void;
// (undocumented)
get isOpen(): boolean;
// (undocumented)
get level(): number;
// (undocumented)
_level: number;
// (undocumented)
ngAfterViewInit(): void;
// (undocumented)
ngOnDestroy(): void;
// (undocumented)
ngOnInit(): void;
// (undocumented)
onMouseClick(target: any): void;
// (undocumented)
onResize(event: Event): void;
// (undocumented)
open(): void;
// (undocumented)
get responsiveNavCodes(): ResponsiveNavCodes;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<ClrNavLevel, "[clr-nav-level]", never, { "_level": "clr-nav-level"; }, {}, never>;
protected showCloseButton(): void;
// (undocumented)
protected showNavigation(): void;
// (undocumented)
static ɵdir: i0.ɵɵDirectiveDeclaration<ClrNavLevel, "[clr-nav-level]", never, { "_level": "clr-nav-level"; "closeButtonAriaLabel": "closeAriaLabel"; }, {}, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ClrNavLevel, never>;
}
Expand Down
36 changes: 30 additions & 6 deletions projects/angular/src/layout/nav/_responsive-nav.clarity.scss
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@
}
}

@mixin clr-nav-close-trigger-animation() {
left: $clr_baselineRem_0_125;
transform-origin: 9%;
transition: $clr-trigger-animation;
}

@mixin overflow-menu-trigger-animation() {
& > span {
background: transparent;
Expand All @@ -78,12 +84,24 @@
@import './properties.responsive-nav';

@include exports('responsive-nav.clarity') {
.clr-nav-close {
margin: 0.75rem;

&:hover,
&:focus {
--color: var(--clr-responsive-nav-trigger-bg-color);
}

--color: var(--clr-color-neutral-500);
}

.header-hamburger-trigger,
.header-overflow-trigger {
display: none;
}

.header-hamburger-trigger {
.header-hamburger-trigger,
.clr-nav-close {
$trigger-span-psuedo-positioning: -1 * $clr_baselineRem_7px;

& > span,
Expand Down Expand Up @@ -131,7 +149,8 @@
}
}

.header-overflow-trigger {
.header-overflow-trigger,
.clr-nav-close {
$overflow-trigger-psuedo-positioning: -1 * $clr_baselineRem_8px;

& > span,
Expand Down Expand Up @@ -221,6 +240,11 @@
transition: $clr-sliding-panel-animation;
}

.sidenav.clr-nav-level-2 {
// This is to prevent the close button to be hidden by the sidenav content
overflow: inherit;
}

.subnav.clr-nav-level-1,
.sub-nav.clr-nav-level-1,
.subnav.clr-nav-level-2,
Expand Down Expand Up @@ -451,7 +475,7 @@
}
}

.header-hamburger-trigger {
.clr-nav-close {
@include menu-trigger();
@include hamburger-menu-trigger-animation();
}
Expand Down Expand Up @@ -487,7 +511,7 @@
padding-top: $clr_baselineRem_1;
}

.header-overflow-trigger {
.clr-nav-close {
@include menu-trigger(0, auto, (-1 * $clr-trigger-position));
@include overflow-menu-trigger-animation();
}
Expand Down Expand Up @@ -562,7 +586,7 @@
max-width: $clr-sliding-panel-width-sm;
}

.header-hamburger-trigger {
.clr-nav-close {
@include menu-trigger(auto, 0, $clr-trigger-position-sm);
}
}
Expand All @@ -577,7 +601,7 @@
max-width: $clr-sliding-panel-width-sm;
}

.header-overflow-trigger {
.clr-nav-close {
@include menu-trigger(0, auto, (-1 * $clr-trigger-position-sm));
}
}
Expand Down
37 changes: 32 additions & 5 deletions projects/angular/src/layout/nav/header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Subscription } from 'rxjs';
import { ResponsiveNavigationService } from './providers/responsive-navigation.service';
import { ResponsiveNavCodes } from './responsive-nav-codes';
import { ClrCommonStringsService } from '../../utils/i18n/common-strings.service';
import { filter } from 'rxjs/operators';

@Component({
selector: 'clr-header',
Expand All @@ -20,7 +21,7 @@ import { ClrCommonStringsService } from '../../utils/i18n/common-strings.service
class="header-hamburger-trigger"
[attr.aria-label]="responsiveNavCommonString"
[attr.aria-expanded]="openNavLevel === 1 ? 'true' : 'false'"
(click)="toggleNav(responsiveNavCodes.NAV_LEVEL_1)"
(click)="openNav(responsiveNavCodes.NAV_LEVEL_1)"
>
<span></span>
</button>
Expand All @@ -31,7 +32,7 @@ import { ClrCommonStringsService } from '../../utils/i18n/common-strings.service
class="header-overflow-trigger"
[attr.aria-label]="responsiveOverflowCommonString"
[attr.aria-expanded]="openNavLevel === 2 ? 'true' : 'false'"
(click)="toggleNav(responsiveNavCodes.NAV_LEVEL_2)"
(click)="openNav(responsiveNavCodes.NAV_LEVEL_2)"
>
<span></span>
</button>
Expand All @@ -55,6 +56,19 @@ export class ClrHeader implements OnDestroy {
this.initializeNavTriggers(navLevelList);
},
});

this._subscription.add(
this.responsiveNavService.navControl
.pipe(
filter(
({ controlCode }) =>
controlCode === ResponsiveNavCodes.NAV_CLOSE || controlCode === ResponsiveNavCodes.NAV_CLOSE_ALL
)
)
.subscribe(() => {
this.openNavLevel = null;
})
);
}

get responsiveNavCommonString() {
Expand Down Expand Up @@ -102,10 +116,23 @@ export class ClrHeader implements OnDestroy {
this.responsiveNavService.closeAllNavs();
}

// toggles the nav that is open
/**
* @deprecated Will be removed in with @clr/angular v15.0.0
*
* Use `openNav(navLevel)` instead to open the navigation and ResponsiveNavService to close it.
*/
toggleNav(navLevel: number) {
this.openNavLevel = this.openNavLevel === navLevel ? null : navLevel;
this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_TOGGLE, navLevel);
if (this.openNavLevel === navLevel) {
this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_CLOSE, navLevel);
return;
}

this.openNav(navLevel);
}

openNav(navLevel: number) {
this.openNavLevel = navLevel;
this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_OPEN, navLevel);
}

ngOnDestroy() {
Expand Down
Loading

0 comments on commit af6c44c

Please sign in to comment.