Last active
November 24, 2023 12:11
-
-
Save sod/26431ae994311e226829d57b7da827c9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {Directive, ElementRef, Input} from '@angular/core'; | |
import {Observable, Subscription, of} from 'rxjs'; | |
import {share} from 'rxjs/operators'; | |
/** | |
* Adds the css class `active-animate` to the element, if given expression is truthy, but after a setTimeout without triggering change detection | |
* This allows to animate an element entering the view, as you can't have an animation on an element that was just added to the DOM | |
* | |
* Example: | |
* | |
* <div class="example" class-active-animate>Hello World</div> | |
* <div class="example" [class-active-animate]="active">Hello World</div> | |
* | |
* <style> | |
* .example { | |
* // initial animation state of the element | |
* will-change: opacity; | |
* opacity: 0; | |
* transition: opacity 1s linear; | |
* | |
* .active-animate { | |
* // applies after a setTimeout | |
* opacity: 1; | |
* } | |
* } | |
* </style> | |
*/ | |
let environment_ssr = false; | |
@Directive({ | |
selector: '[class-active-animate]', | |
}) | |
export class ClassActiveAnimateDirective { | |
private static className = 'active-animate'; | |
private active = false; | |
private timeout?: Subscription; | |
private immediateForceReflow$ = environment_ssr | |
? of(undefined) | |
: new Observable<void>((subscriber) => { | |
const timeout = setTimeout(() => { | |
ClassActiveAnimateDirective.forceReflow(document.body); | |
subscriber.next(undefined); | |
subscriber.complete(); | |
}, 1); | |
return () => { | |
clearTimeout(timeout); | |
}; | |
}).pipe(share()); | |
@Input('class-active-animate') | |
set activate(value: boolean | undefined) { | |
if (environment_ssr || value === this.active || (!this.active && value === undefined)) { | |
return; | |
} | |
this.timeout?.unsubscribe(); | |
this.timeout = undefined; | |
this.active = !this.active; | |
if (this.active) { | |
this.timeout = this.immediateForceReflow$.subscribe(() => { | |
this.timeout = undefined; | |
this.elementRef.nativeElement.className += ' ' + ClassActiveAnimateDirective.className; | |
}); | |
} | |
if (!this.active) { | |
this.elementRef.nativeElement.classList.remove(ClassActiveAnimateDirective.className); | |
} | |
} | |
constructor(private elementRef: ElementRef) {} | |
private static forceReflow(element: HTMLElement): number { | |
return element.offsetWidth; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment