clients/libs/components/src/layout/layout.component.ts
Will Martin b8a1856fc6
Some checks failed
Chromatic / Check PR run (push) Has been cancelled
Scan / Check PR run (push) Has been cancelled
Testing / Run tests (push) Has been cancelled
Testing / Run Rust tests on ${{ matrix.os }} (macos-14) (push) Has been cancelled
Testing / Run Rust tests on ${{ matrix.os }} (ubuntu-22.04) (push) Has been cancelled
Testing / Run Rust tests on ${{ matrix.os }} (windows-2022) (push) Has been cancelled
Testing / Rust Coverage (push) Has been cancelled
Chromatic / Chromatic (push) Has been cancelled
Scan / SAST scan (push) Has been cancelled
Scan / Quality scan (push) Has been cancelled
Testing / Upload to Codecov (push) Has been cancelled
[CL-696] un-revert "various drawer improvements" + bug fix (#14887)
* Revert "Revert "[CL-622][CL-562][CL-621][CL-632] various drawer improvements …"

This reverts commit 4b32d1f9dd.

* fix virtual scroll: add .cdk-virtual-scrollable to scroll viewport target

* remove references to main el

* use directives instead of querySelector (#14950)

* remove references to main el

* wip

* banish querySelector to the shadow realm

* revert apps/ files

* Add virtual scrolling docs

Co-authored-by: Vicki League <vleague@bitwarden.com>

* add jsdoc

* run eslint

* fix skip links bug

* Update libs/components/src/layout/layout.component.ts

Co-authored-by: Vicki League <vleague@bitwarden.com>

* update tab handler

* only run on tab

* fix lint

* fix virtual scroll issue due to Angular 19 upgrade (#15193)

thanks Vicki

---------

Co-authored-by: Vicki League <vleague@bitwarden.com>
2025-06-17 11:05:14 -04:00

62 lines
1.9 KiB
TypeScript

import { A11yModule, CdkTrapFocus } from "@angular/cdk/a11y";
import { PortalModule } from "@angular/cdk/portal";
import { CommonModule } from "@angular/common";
import { Component, ElementRef, inject, viewChild } from "@angular/core";
import { RouterModule } from "@angular/router";
import { DrawerHostDirective } from "../drawer/drawer-host.directive";
import { DrawerService } from "../drawer/drawer.service";
import { LinkModule } from "../link";
import { SideNavService } from "../navigation/side-nav.service";
import { SharedModule } from "../shared";
import { ScrollLayoutHostDirective } from "./scroll-layout.directive";
@Component({
selector: "bit-layout",
templateUrl: "layout.component.html",
imports: [
CommonModule,
SharedModule,
LinkModule,
RouterModule,
PortalModule,
A11yModule,
CdkTrapFocus,
ScrollLayoutHostDirective,
],
host: {
"(document:keydown.tab)": "handleKeydown($event)",
},
hostDirectives: [DrawerHostDirective],
})
export class LayoutComponent {
protected sideNavService = inject(SideNavService);
protected drawerPortal = inject(DrawerService).portal;
private mainContent = viewChild.required<ElementRef<HTMLElement>>("main");
protected focusMainContent() {
this.mainContent().nativeElement.focus();
}
/**
* Angular CDK's focus trap utility is silly and will not respect focus order.
* This is a workaround to explicitly focus the skip link when tab is first pressed, if no other item already has focus.
*
* @see https://github.com/angular/components/issues/10247#issuecomment-384060265
**/
private skipLink = viewChild.required<ElementRef<HTMLElement>>("skipLink");
handleKeydown(ev: KeyboardEvent) {
if (isNothingFocused()) {
ev.preventDefault();
this.skipLink().nativeElement.focus();
}
}
}
const isNothingFocused = (): boolean => {
return [document.documentElement, document.body, null].includes(
document.activeElement as HTMLElement,
);
};