diff --git a/libs/components/src/layout/index.ts b/libs/components/src/layout/index.ts index 6994a4f639f..a257a4dde85 100644 --- a/libs/components/src/layout/index.ts +++ b/libs/components/src/layout/index.ts @@ -1 +1,2 @@ export * from "./layout.component"; +export * from "./scroll-layout.directive"; diff --git a/libs/components/src/layout/layout.component.ts b/libs/components/src/layout/layout.component.ts index 6cb57ff1b99..0211ec16ff3 100644 --- a/libs/components/src/layout/layout.component.ts +++ b/libs/components/src/layout/layout.component.ts @@ -25,11 +25,14 @@ import { SharedModule } from "../shared"; }) export class LayoutComponent { protected mainContentId = "main-content"; - protected sideNavService = inject(SideNavService); protected drawerPortal = inject(DrawerService).portal; - focusMainContent() { - document.getElementById(this.mainContentId)?.focus(); + getMainContent() { + return document.getElementById(this.mainContentId)!; + } + + protected focusMainContent() { + this.getMainContent().focus(); } } diff --git a/libs/components/src/layout/scroll-layout.directive.ts b/libs/components/src/layout/scroll-layout.directive.ts new file mode 100644 index 00000000000..4bdf0b4eae7 --- /dev/null +++ b/libs/components/src/layout/scroll-layout.directive.ts @@ -0,0 +1,35 @@ +import { Directionality } from "@angular/cdk/bidi"; +import { CdkVirtualScrollable, ScrollDispatcher, VIRTUAL_SCROLLABLE } from "@angular/cdk/scrolling"; +import { Directive, ElementRef, NgZone, Optional } from "@angular/core"; + +import { LayoutComponent } from "./layout.component"; + +@Directive({ + selector: "cdk-virtual-scroll-viewport[bitScrollLayout]", + standalone: true, + providers: [{ provide: VIRTUAL_SCROLLABLE, useExisting: ScrollLayoutDirective }], +}) +export class ScrollLayoutDirective extends CdkVirtualScrollable { + private mainEl: ElementRef; + + constructor( + layout: LayoutComponent, + scrollDispatcher: ScrollDispatcher, + ngZone: NgZone, + @Optional() dir: Directionality, + ) { + const mainEl = new ElementRef(layout.getMainContent()); + super(mainEl, scrollDispatcher, ngZone, dir); + this.mainEl = mainEl; + } + + override getElementRef(): ElementRef { + return this.mainEl; + } + + override measureBoundingClientRectWithScrollOffset( + from: "left" | "top" | "right" | "bottom", + ): number { + return this.mainEl.nativeElement.getBoundingClientRect()[from] - this.measureScrollOffset(from); + } +} diff --git a/libs/components/src/stories/kitchen-sink/components/dialog-virtual-scroll-block.component.ts b/libs/components/src/stories/kitchen-sink/components/dialog-virtual-scroll-block.component.ts index 7709506f050..904b9e11c3a 100644 --- a/libs/components/src/stories/kitchen-sink/components/dialog-virtual-scroll-block.component.ts +++ b/libs/components/src/stories/kitchen-sink/components/dialog-virtual-scroll-block.component.ts @@ -3,15 +3,23 @@ import { Component, OnInit } from "@angular/core"; import { DialogModule, DialogService } from "../../../dialog"; import { IconButtonModule } from "../../../icon-button"; +import { ScrollLayoutDirective } from "../../../layout"; import { SectionComponent } from "../../../section"; import { TableDataSource, TableModule } from "../../../table"; @Component({ selector: "dialog-virtual-scroll-block", standalone: true, - imports: [DialogModule, IconButtonModule, SectionComponent, TableModule, ScrollingModule], + imports: [ + DialogModule, + IconButtonModule, + SectionComponent, + TableModule, + ScrollingModule, + ScrollLayoutDirective, + ], template: /*html*/ ` - +