From 4828c5c8839aae6f50df358f18ba715af0fbf03d Mon Sep 17 00:00:00 2001 From: Kevin Buhmann Date: Thu, 8 Dec 2022 12:06:12 -0600 Subject: [PATCH] feat: use `cdkTrapFocus` directive from `@angular/cdk` --- projects/angular/clarity.api.md | 88 +++++++++---------- .../data/datagrid/datagrid-action-overflow.ts | 2 +- .../data/datagrid/datagrid-column-toggle.ts | 2 +- .../src/data/datagrid/datagrid-detail.spec.ts | 6 +- .../src/data/datagrid/datagrid-detail.ts | 5 +- .../src/data/datagrid/datagrid-filter.ts | 2 +- .../src/data/datagrid/datagrid.module.ts | 4 +- .../src/forms/datepicker/date-container.ts | 2 +- .../src/forms/datepicker/datepicker.module.ts | 4 +- .../angular/src/layout/nav/nav-level.spec.ts | 19 ++-- projects/angular/src/layout/nav/nav-level.ts | 25 ++++-- projects/angular/src/modal/modal.html | 2 +- projects/angular/src/modal/modal.module.ts | 4 +- projects/angular/src/modal/modal.spec.ts | 7 +- projects/angular/src/modal/modal.ts | 6 -- .../src/utils/cdk/cdk-trap-focus.module.ts | 25 ++++++ projects/angular/src/utils/popover/README.md | 2 +- .../demo/src/app/modal/modal-trap.demo.html | 4 +- .../demo/src/app/modal/modal.demo.module.ts | 3 +- 19 files changed, 124 insertions(+), 88 deletions(-) create mode 100644 projects/angular/src/utils/cdk/cdk-trap-focus.module.ts diff --git a/projects/angular/clarity.api.md b/projects/angular/clarity.api.md index 0664691b18..82037a7d5c 100644 --- a/projects/angular/clarity.api.md +++ b/projects/angular/clarity.api.md @@ -13,6 +13,7 @@ import { AnimationEvent as AnimationEvent_2 } from '@angular/animations'; import { AnimationMetadata } from '@angular/animations'; import { BehaviorSubject } from 'rxjs'; import { CdkDrag } from '@angular/cdk/drag-drop'; +import { CdkTrapFocus } from '@angular/cdk/a11y'; import { ChangeDetectorRef } from '@angular/core'; import { ComponentFactoryResolver } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; @@ -24,7 +25,7 @@ import { FormGroup } from '@angular/forms'; import { FormGroupDirective } from '@angular/forms'; import { FormGroupName } from '@angular/forms'; import * as i0 from '@angular/core'; -import * as i41 from '@angular/forms'; +import * as i42 from '@angular/forms'; import * as i6 from '@angular/common'; import { InjectionToken } from '@angular/core'; import { Injector } from '@angular/core'; @@ -74,7 +75,7 @@ export class ClarityModule { // Warning: (ae-forgotten-export) The symbol "i4_11" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i5_7" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i6_2" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "i7_5" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i7_6" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i8_6" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i9_5" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i10_4" needs to be exported by the entry point index.d.ts @@ -89,7 +90,7 @@ export class ClarityModule { // Warning: (ae-forgotten-export) The symbol "i19_2" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -835,10 +836,10 @@ export class ClrComboboxModule { // Warning: (ae-forgotten-export) The symbol "i4_6" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i5_4" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i6_5" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "i48" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i49" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -1589,11 +1590,12 @@ export class ClrDatagridModule { // Warning: (ae-forgotten-export) The symbol "i35" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i36" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i38" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "i44" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i39" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i45" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i46" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -1885,13 +1887,13 @@ export class ClrDatalistModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_24" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_23" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_19" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i3_14" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i6_7" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -2021,7 +2023,7 @@ export class ClrDatepickerModule { // Warning: (ae-forgotten-export) The symbol "i9_3" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -2234,10 +2236,10 @@ export class ClrFocusOnViewInitModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_28" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_27" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -2279,7 +2281,7 @@ export class ClrFormsModule { // Warning: (ae-forgotten-export) The symbol "i3_7" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i4_5" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i5_5" needs to be exported by the entry point index.d.ts - // Warning: (ae-forgotten-export) The symbol "i7_6" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i7_5" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i8_5" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i9_4" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i10_3" needs to be exported by the entry point index.d.ts @@ -2287,7 +2289,7 @@ export class ClrFormsModule { // Warning: (ae-forgotten-export) The symbol "i12_2" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -2497,11 +2499,11 @@ export class ClrInputModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_18" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_17" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_13" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -2608,10 +2610,10 @@ export class ClrLoadingModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_25" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_24" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -2674,8 +2676,6 @@ export class ClrModal implements OnChanges, OnDestroy { // (undocumented) fadeDone(e: AnimationEvent_2): void; // (undocumented) - focusTrap: ÇlrFocusTrapDirective; - // (undocumented) labelledBy: string; // (undocumented) modalId: string; @@ -2723,11 +2723,11 @@ export class ClrModalModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_31" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_30" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_23" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -2761,12 +2761,10 @@ export class ClrNavigationModule { static ɵmod: i0.ɵɵNgModuleDeclaration; } -// Warning: (ae-forgotten-export) The symbol "FocusTrap" needs to be exported by the entry point index.d.ts -// // @public (undocumented) -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, renderer: Renderer2, injector: Injector); +export class ClrNavLevel implements OnInit { + // Warning: (ae-forgotten-export) The symbol "StandaloneCdkTrapFocus" needs to be exported by the entry point index.d.ts + constructor(platformId: any, cdkTrapFocus: StandaloneCdkTrapFocus, responsiveNavService: ResponsiveNavigationService, elementRef: ElementRef, renderer: Renderer2, injector: Injector); // (undocumented) addNavClass(level: number): void; // (undocumented) @@ -2802,7 +2800,7 @@ export class ClrNavLevel extends FocusTrap implements OnInit { // (undocumented) protected showNavigation(): void; // (undocumented) - static ɵdir: i0.ɵɵDirectiveDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; // (undocumented) static ɵfac: i0.ɵɵFactoryDeclaration; } @@ -2953,11 +2951,11 @@ export class ClrPasswordModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_19" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_18" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_14" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -3212,12 +3210,12 @@ export class ClrRadioModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_20" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_19" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_15" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i3_13" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -3266,11 +3264,11 @@ export class ClrRangeModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_23" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_22" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_18" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -3354,11 +3352,11 @@ export class ClrSelectModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_21" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_20" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_16" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -3584,14 +3582,14 @@ export class ClrStackViewModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_29" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_28" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_21" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i3_15" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i4_9" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i5_8" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -3851,7 +3849,7 @@ export class ClrTabsModule { // Warning: (ae-forgotten-export) The symbol "i11_4" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -3880,11 +3878,11 @@ export class ClrTextareaModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_22" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_21" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_17" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -4145,14 +4143,14 @@ export class ClrTreeViewModule { static ɵfac: i0.ɵɵFactoryDeclaration; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration; - // Warning: (ae-forgotten-export) The symbol "i1_30" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_29" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i2_22" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i3_17" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i4_10" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "i5_9" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } // @public (undocumented) @@ -4883,10 +4881,10 @@ export class ÇlrClrFocusTrapModule { static ɵfac: i0.ɵɵFactoryDeclaration<ÇlrClrFocusTrapModule, never>; // (undocumented) static ɵinj: i0.ɵɵInjectorDeclaration<ÇlrClrFocusTrapModule>; - // Warning: (ae-forgotten-export) The symbol "i1_17" needs to be exported by the entry point index.d.ts + // Warning: (ae-forgotten-export) The symbol "i1_31" needs to be exported by the entry point index.d.ts // // (undocumented) - static ɵmod: i0.ɵɵNgModuleDeclaration<ÇlrClrFocusTrapModule, [typeof i1_17.FocusTrapDirective], [typeof i6.CommonModule], [typeof i1_17.FocusTrapDirective]>; + static ɵmod: i0.ɵɵNgModuleDeclaration<ÇlrClrFocusTrapModule, [typeof i1_31.FocusTrapDirective], [typeof i6.CommonModule], [typeof i1_31.FocusTrapDirective]>; } // @public (undocumented) diff --git a/projects/angular/src/data/datagrid/datagrid-action-overflow.ts b/projects/angular/src/data/datagrid/datagrid-action-overflow.ts index 4cacb9c1a3..b498fb3fde 100644 --- a/projects/angular/src/data/datagrid/datagrid-action-overflow.ts +++ b/projects/angular/src/data/datagrid/datagrid-action-overflow.ts @@ -57,7 +57,7 @@ let clrDgActionId = 0; [attr.aria-hidden]="!open" [attr.id]="popoverId" clrKeyFocus - clrFocusTrap + cdkTrapFocus (click)="closeOverflowContent($event)" *clrPopoverContent="open; at: smartPosition; outsideClickToClose: true; scrollToClose: true" > diff --git a/projects/angular/src/data/datagrid/datagrid-column-toggle.ts b/projects/angular/src/data/datagrid/datagrid-column-toggle.ts index 3c256a710a..1a9d2bdf3a 100644 --- a/projects/angular/src/data/datagrid/datagrid-column-toggle.ts +++ b/projects/angular/src/data/datagrid/datagrid-column-toggle.ts @@ -42,7 +42,7 @@ import { ColumnsService } from './providers/columns.service'; role="dialog" [attr.aria-label]="commonStrings.keys.showColumnsMenuDescription" [id]="popoverId" - clrFocusTrap + cdkTrapFocus *clrPopoverContent="openState; at: smartPosition; outsideClickToClose: true; scrollToClose: true" >
diff --git a/projects/angular/src/data/datagrid/datagrid-detail.spec.ts b/projects/angular/src/data/datagrid/datagrid-detail.spec.ts index 3feb68d525..e81e3703d1 100644 --- a/projects/angular/src/data/datagrid/datagrid-detail.spec.ts +++ b/projects/angular/src/data/datagrid/datagrid-detail.spec.ts @@ -65,13 +65,13 @@ export default function (): void { })); it('conditionally enables focus trap when opened', () => { - expect(context.clarityElement.innerHTML).not.toContain('clrfocustrap'); + expect(context.clarityElement.innerHTML).not.toContain('cdkfocustrap'); detailService.open({}); context.detectChanges(); - expect(context.clarityElement.innerHTML).toContain('clrfocustrap'); + expect(context.clarityElement.innerHTML).toContain('cdkfocustrap'); detailService.close(); context.detectChanges(); - expect(context.clarityElement.innerHTML).not.toContain('clrfocustrap'); + expect(context.clarityElement.innerHTML).not.toContain('cdkfocustrap'); }); it('should have text based boundaries for screen readers', () => { diff --git a/projects/angular/src/data/datagrid/datagrid-detail.ts b/projects/angular/src/data/datagrid/datagrid-detail.ts index ad589811a9..d045843e0d 100644 --- a/projects/angular/src/data/datagrid/datagrid-detail.ts +++ b/projects/angular/src/data/datagrid/datagrid-detail.ts @@ -15,11 +15,12 @@ import { DetailService } from './providers/detail.service'; host: { '[class.datagrid-detail-pane]': 'true', }, - // We put the *ngIf on the clrFocusTrap so it doesn't always exist on the page + // We put the *ngIf on the cdkTrapFocus so it doesn't always exist on the page // have to test for presence of header for aria-describedby because it was causing unit tests to crash template: ` [] = [ @NgModule({ imports: [ CommonModule, + CdkTrapFocusModule, ClrHostWrappingModule, ClrConditionalModule, ClrPopoverModuleNext, ClrIconModule, - ClrFocusTrapModule, ClrCommonFormsModule, ], declarations: [CLR_DATEPICKER_DIRECTIVES], diff --git a/projects/angular/src/layout/nav/nav-level.spec.ts b/projects/angular/src/layout/nav/nav-level.spec.ts index d1d610b07c..a6aa21c4c3 100644 --- a/projects/angular/src/layout/nav/nav-level.spec.ts +++ b/projects/angular/src/layout/nav/nav-level.spec.ts @@ -85,6 +85,11 @@ describe('NavLevelDirective', function () { expect(this.clarityDirective.isOpen).toBe(false); }); + it('should disable focus trap by default', function () { + const cdkTrapFocus = getCdkTrapFocus(this.clarityDirective); + expect(cdkTrapFocus.enabled).toBe(false); + }); + describe('ResponsiveNavLevel intergration:', function () { it('#registers nav on init. sends the registration code on registerNavSubject in the service', function () { const service = new ResponsiveNavigationService(); @@ -140,10 +145,10 @@ describe('NavLevelDirective', function () { expect(this.clarityDirective.showNavigation).toHaveBeenCalled(); }); - it('should call enableFocusTrap()', function () { - spyOn(this.clarityDirective, 'enableFocusTrap'); + it('should enable focus trap', function () { + const cdkTrapFocus = getCdkTrapFocus(this.clarityDirective); this.clarityDirective.open(); - expect(this.clarityDirective.enableFocusTrap).toHaveBeenCalled(); + expect(cdkTrapFocus.enabled).toBe(true); }); it('should call showCloseButton()', function () { @@ -170,9 +175,9 @@ describe('NavLevelDirective', function () { }); it('should call removeFocusTrap()', function () { - const spy = spyOn(this.clarityDirective, 'removeFocusTrap'); + const cdkTrapFocus = getCdkTrapFocus(this.clarityDirective); this.clarityDirective.close(); - expect(spy).toHaveBeenCalled(); + expect(cdkTrapFocus.enabled).toBeFalse(); }); it('should call hideCloseButton()', function () { @@ -203,3 +208,7 @@ describe('NavLevelDirective', function () { }); }); }); + +function getCdkTrapFocus(clrNavLevel: ClrNavLevel) { + return (clrNavLevel as any).cdkTrapFocus; +} diff --git a/projects/angular/src/layout/nav/nav-level.ts b/projects/angular/src/layout/nav/nav-level.ts index ec9c5f23b4..d82755e6e6 100644 --- a/projects/angular/src/layout/nav/nav-level.ts +++ b/projects/angular/src/layout/nav/nav-level.ts @@ -4,6 +4,7 @@ * The full license information can be found in LICENSE in the root directory of this project. */ +import { CdkTrapFocus } from '@angular/cdk/a11y'; import { DOCUMENT, isPlatformBrowser } from '@angular/common'; import { Directive, @@ -21,9 +22,9 @@ import { filter } from 'rxjs/operators'; import { commonStringsDefault } from '../../utils'; import { LARGE_BREAKPOINT } from '../../utils/breakpoints/breakpoints'; -import { FocusTrap, FocusTrapElement } from '../../utils/focus-trap/focus-trap'; import { ResponsiveNavigationService } from './providers/responsive-navigation.service'; import { ResponsiveNavCodes } from './responsive-nav-codes'; + import '@cds/core/internal-components/close-button/register.js'; const createCdsCloseButton = (document: Document, ariaLabel: string) => { @@ -40,10 +41,16 @@ const createCdsCloseButton = (document: Document, ariaLabel: string) => { return cdsCloseButton; }; +@Directive({ + standalone: true, +}) +class StandaloneCdkTrapFocus extends CdkTrapFocus {} + @Directive({ selector: '[clr-nav-level]', + hostDirectives: [StandaloneCdkTrapFocus], }) -export class ClrNavLevel extends FocusTrap implements OnInit { +export class ClrNavLevel implements OnInit { @Input('clr-nav-level') _level: number; @Input('closeAriaLabel') closeButtonAriaLabel: string; @@ -51,16 +58,16 @@ export class ClrNavLevel extends FocusTrap implements OnInit { private _subscription: Subscription; private _isOpen = false; + private _document: Document; constructor( @Inject(PLATFORM_ID) platformId: any, + private cdkTrapFocus: StandaloneCdkTrapFocus, private responsiveNavService: ResponsiveNavigationService, - private elementRef: ElementRef, - renderer: Renderer2, + private elementRef: ElementRef, + private renderer: Renderer2, injector: Injector ) { - super(renderer, injector, platformId, elementRef.nativeElement); - if (isPlatformBrowser(platformId)) { this._document = injector.get(DOCUMENT); } @@ -91,6 +98,8 @@ export class ClrNavLevel extends FocusTrap implements OnInit { } ngOnInit() { + this.cdkTrapFocus.enabled = false; + if (!this.closeButtonAriaLabel) { this.closeButtonAriaLabel = this._level === ResponsiveNavCodes.NAV_LEVEL_1 @@ -159,7 +168,7 @@ export class ClrNavLevel extends FocusTrap implements OnInit { open(): void { this._isOpen = true; this.showNavigation(); - this.enableFocusTrap(); + this.cdkTrapFocus.enabled = true; this.showCloseButton(); this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_OPEN, this.level); } @@ -167,7 +176,7 @@ export class ClrNavLevel extends FocusTrap implements OnInit { close(): void { this._isOpen = false; this.hideNavigation(); - this.removeFocusTrap(); + this.cdkTrapFocus.enabled = false; this.hideCloseButton(); this.responsiveNavService.sendControlMessage(ResponsiveNavCodes.NAV_CLOSE, this.level); } diff --git a/projects/angular/src/modal/modal.html b/projects/angular/src/modal/modal.html index f14a7ea36d..b76d109a8b 100644 --- a/projects/angular/src/modal/modal.html +++ b/projects/angular/src/modal/modal.html @@ -4,7 +4,7 @@ ~ The full license information can be found in LICENSE in the root directory of this project. --> -