quarc/router/directives/router-link-active.directiv...

86 lines
2.7 KiB
TypeScript

import { Directive, IDirective, input, effect, IComponent, InputSignal } from "../../core";
import { Router } from "../angular/router";
import { Subscription } from "../../rxjs";
@Directive({
selector: '[routerLinkActive]',
})
export class RouterLinkActive implements IDirective {
public routerLinkActive!: InputSignal<string>;
public routerLinkActiveOptions!: InputSignal<{ exact?: boolean }>;
private subscription?: Subscription;
constructor(
private router: Router,
public _nativeElement: HTMLElement,
) {
this.routerLinkActive = input<string>('routerLinkActive', this as unknown as IComponent, '');
this.routerLinkActiveOptions = input<{ exact?: boolean }>('routerLinkActiveOptions', this as unknown as IComponent, {});
this.updateActiveState();
this.subscription = this.router.events$.subscribe(() => {
this.updateActiveState();
});
effect(() => {
this.routerLinkActive();
this.routerLinkActiveOptions();
this.updateActiveState();
});
}
ngOnDestroy(): void {
this.subscription?.unsubscribe();
}
private updateActiveState(): void {
const isActive = this.checkIsActive();
const activeClass = this.routerLinkActive();
if (activeClass) {
if (isActive) {
this._nativeElement.classList.add(activeClass);
} else {
this._nativeElement.classList.remove(activeClass);
}
}
}
private checkIsActive(): boolean {
let routerLinkValue: string | string[] | undefined;
const inputs = (this._nativeElement as any).__inputs;
if (inputs?.routerLink) {
routerLinkValue = inputs.routerLink();
}
if (!routerLinkValue) {
routerLinkValue = this._nativeElement.getAttribute('router-link') || this._nativeElement.getAttribute('routerLink') || undefined;
}
if (!routerLinkValue) {
return false;
}
const linkPath = Array.isArray(routerLinkValue) ? routerLinkValue.join('/') : routerLinkValue;
const currentUrl = this.normalizeUrl(location.pathname);
const linkUrl = this.normalizeUrl(linkPath);
const options = this.routerLinkActiveOptions();
if (options.exact) {
return currentUrl === linkUrl;
}
return currentUrl === linkUrl || currentUrl.startsWith(linkUrl + '/');
}
private normalizeUrl(url: string): string {
let normalized = url.startsWith('/') ? url : '/' + url;
if (normalized.length > 1 && normalized.endsWith('/')) {
normalized = normalized.slice(0, -1);
}
return normalized;
}
}