feat(ui-layout): add UiElementSizeObserverDirective for reactive element sizing

Adds a directive that uses ResizeObserver to track element dimensions
and exposes them as signals for reactive positioning calculations.
This commit is contained in:
Lorenz Hilpert
2025-12-05 21:05:20 +01:00
parent e3c60f14f7
commit e5c7c18c40
2 changed files with 52 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
export * from './lib/breakpoint.directive';
export * from './lib/breakpoint';
export * from './lib/close-on-scroll.directive';
export * from './lib/in-viewport.directive';
export * from './lib/breakpoint.directive';
export * from './lib/breakpoint';
export * from './lib/close-on-scroll.directive';
export * from './lib/in-viewport.directive';
export * from './lib/element-size-observer.directive';

View File

@@ -0,0 +1,47 @@
import {
AfterViewInit,
Directive,
ElementRef,
inject,
OnDestroy,
output,
Signal,
signal,
} from '@angular/core';
@Directive({
selector: '[uiElementSizeObserver]',
exportAs: 'uiElementSizeObserver',
})
export class UiElementSizeObserverDirective
implements AfterViewInit, OnDestroy
{
#element: HTMLElement = inject(ElementRef).nativeElement;
#resizeObserver?: ResizeObserver;
ngAfterViewInit(): void {
this.#resizeObserver = new ResizeObserver(() => {
this.#emitSize();
});
this.#resizeObserver.observe(this.#element);
this.#emitSize();
}
ngOnDestroy(): void {
this.#resizeObserver?.disconnect();
}
#emitSize() {
const size = this.#element.getBoundingClientRect();
this.#size.set(size);
this.uiElementSizeObserver.emit(size);
}
#size = signal<{ width: number; height: number }>({ height: 0, width: 0 });
readonly size: Signal<{ width: number; height: number }> =
this.#size.asReadonly();
readonly uiElementSizeObserver = output<{ width: number; height: number }>();
}