import { CdkPortal, PortalModule } from "@angular/cdk/portal"; import { CommonModule } from "@angular/common"; import { ChangeDetectionStrategy, Component, effect, inject, input, model, viewChild, } from "@angular/core"; import { DrawerHostDirective } from "./drawer-host.directive"; /** * A drawer is a panel of supplementary content that is adjacent to the page's main content. * * Drawers render in `bit-layout`. Drawers must be a descendant of `bit-layout`, but they do not need to be a direct descendant. */ @Component({ selector: "bit-drawer", standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [CommonModule, PortalModule], templateUrl: "drawer.component.html", }) export class DrawerComponent { private drawerHost = inject(DrawerHostDirective); private portal = viewChild.required(CdkPortal); /** * Whether or not the drawer is open. * * Note: Does not support implicit boolean transform due to Angular limitation. Must be bound explicitly `[open]="true"` instead of just `open`. * https://github.com/angular/angular/issues/55166#issuecomment-2032150999 **/ open = model(false); /** * The ARIA role of the drawer. * * - [complementary](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/complementary_role) * - For drawers that contain content that is complementary to the page's main content. (default) * - [navigation](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/navigation_role) * - For drawers that primary contain links to other content. */ role = input<"complementary" | "navigation">("complementary"); constructor() { effect( () => { this.open() ? this.drawerHost.open(this.portal()) : this.drawerHost.close(this.portal()); }, { allowSignalWrites: true, }, ); // Set `open` to `false` when another drawer is opened. effect( () => { if (this.drawerHost.portal() !== this.portal()) { this.open.set(false); } }, { allowSignalWrites: true, }, ); } /** Toggle the drawer between open & closed */ toggle() { this.open.update((prev) => !prev); } }