-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #13980 from primefaces/issue-13970
Issue 13970
- Loading branch information
Showing
15 changed files
with
567 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common'; | ||
import { AfterViewInit, Directive, ElementRef, Input, NgModule, Renderer2, OnInit, Inject, PLATFORM_ID } from '@angular/core'; | ||
import { DomHandler } from 'primeng/dom'; | ||
|
||
interface AnimateOnScrollOptions { | ||
root?: HTMLElement; | ||
rootMargin?: string; | ||
threshold?: number; | ||
} | ||
|
||
/** | ||
* AnimateOnScroll is used to apply animations to elements when entering or leaving the viewport during scrolling. | ||
* @group Components | ||
*/ | ||
@Directive({ | ||
selector: '[pAnimateOnScroll]', | ||
host: { | ||
'[class.p-animateonscroll]': 'true' | ||
} | ||
}) | ||
export class AnimateOnScroll implements OnInit, AfterViewInit { | ||
/** | ||
* Selector to define the CSS class for enter animation. | ||
* @group Props | ||
*/ | ||
@Input() enterClass: string | undefined; | ||
/** | ||
* Selector to define the CSS class for leave animation. | ||
* @group Props | ||
*/ | ||
@Input() leaveClass: string | undefined; | ||
/** | ||
* Specifies the root option of the IntersectionObserver API. | ||
* @group Props | ||
*/ | ||
@Input() root: HTMLElement | undefined | null; | ||
/** | ||
* Specifies the rootMargin option of the IntersectionObserver API. | ||
* @group Props | ||
*/ | ||
@Input() rootMargin: string | undefined; | ||
/** | ||
* Specifies the threshold option of the IntersectionObserver API | ||
* @group Props | ||
*/ | ||
@Input() threshold: number | undefined; | ||
/** | ||
* Whether the scroll event listener should be removed after initial run. | ||
* @group Props | ||
*/ | ||
@Input() once: boolean = true; | ||
|
||
observer: IntersectionObserver | undefined; | ||
|
||
resetObserver: any; | ||
|
||
isObserverActive: boolean = false; | ||
|
||
animationState: any; | ||
|
||
animationEndListener: VoidFunction | undefined; | ||
|
||
constructor(@Inject(DOCUMENT) private document: Document, @Inject(PLATFORM_ID) private platformId: any, private host: ElementRef, public el: ElementRef, public renderer: Renderer2) {} | ||
|
||
ngOnInit() { | ||
if(isPlatformBrowser(this.platformId)){ | ||
this.renderer.setStyle(this.host.nativeElement, 'opacity', this.enterClass ? '0' : ''); | ||
} | ||
} | ||
|
||
ngAfterViewInit() { | ||
if(isPlatformBrowser(this.platformId)){ | ||
this.bindIntersectionObserver(); | ||
} | ||
} | ||
|
||
get options(): AnimateOnScrollOptions { | ||
return { | ||
root: this.root, | ||
rootMargin: this.rootMargin, | ||
threshold: this.threshold | ||
} | ||
} | ||
|
||
bindIntersectionObserver() { | ||
this.observer = new IntersectionObserver(([entry]) => { | ||
if(this.isObserverActive) { | ||
if(entry.boundingClientRect.top > 0) { | ||
entry.isIntersecting ? this.enter() : this.leave(); | ||
} | ||
} else if(entry.isIntersecting) { | ||
this.enter(); | ||
} | ||
|
||
this.isObserverActive = true; | ||
}, this.options); | ||
|
||
setTimeout(() => this.observer.observe(this.host.nativeElement), 0); | ||
|
||
// Reset | ||
|
||
this.resetObserver = new IntersectionObserver(([entry]) => { | ||
if (entry.boundingClientRect.top > 0 && !entry.isIntersecting) { | ||
this.host.nativeElement.style.opacity = this.enterClass ? '0' : ''; | ||
DomHandler.removeMultipleClasses(this.host.nativeElement, [this.enterClass, this.leaveClass]); | ||
|
||
this.resetObserver.unobserve(this.host.nativeElement); | ||
} | ||
|
||
this.animationState = undefined; | ||
}, {...this.options, threshold: 0}) | ||
} | ||
|
||
enter() { | ||
if (this.animationState !== 'enter' && this.enterClass) { | ||
this.host.nativeElement.style.opacity = ''; | ||
DomHandler.removeMultipleClasses(this.host.nativeElement, this.leaveClass); | ||
DomHandler.addMultipleClasses(this.host.nativeElement, this.enterClass); | ||
|
||
this.once && this.unbindIntersectionObserver(); | ||
|
||
this.bindAnimationEvents(); | ||
this.animationState = 'enter'; | ||
} | ||
} | ||
|
||
leave() { | ||
if (this.animationState !== 'leave' && this.leaveClass) { | ||
this.host.nativeElement.style.opacity = this.enterClass ? '0' : ''; | ||
DomHandler.removeMultipleClasses(this.host.nativeElement, this.enterClass); | ||
DomHandler.addMultipleClasses(this.host.nativeElement, this.leaveClass); | ||
|
||
this.bindAnimationEvents(); | ||
this.animationState = 'leave'; | ||
} | ||
} | ||
|
||
bindAnimationEvents() { | ||
if (!this.animationEndListener) { | ||
this.animationEndListener = this.renderer.listen(this.host.nativeElement, 'animationend', () => { | ||
DomHandler.removeMultipleClasses(this.host.nativeElement, [this.enterClass, this.leaveClass]); | ||
!this.once && this.resetObserver.observe(this.host.nativeElement); | ||
this.unbindAnimationEvents(); | ||
}) | ||
} | ||
} | ||
|
||
unbindAnimationEvents() { | ||
if (this.animationEndListener) { | ||
this.animationEndListener(); | ||
this.animationEndListener = null; | ||
} | ||
} | ||
|
||
unbindIntersectionObserver() { | ||
this.observer?.unobserve(this.host.nativeElement); | ||
this.resetObserver?.unobserve(this.host.nativeElement); | ||
this.isObserverActive = false; | ||
} | ||
|
||
ngOnDestroy() { | ||
this.unbindAnimationEvents(); | ||
this.unbindIntersectionObserver(); | ||
} | ||
} | ||
|
||
@NgModule({ | ||
imports: [CommonModule], | ||
exports: [AnimateOnScroll], | ||
declarations: [AnimateOnScroll] | ||
}) | ||
export class AnimateOnScrollModule {} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"$schema": "ng-packagr/ng-package.schema.json", | ||
"lib": { | ||
"entryFile": "public_api.ts" | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './animateonscroll'; |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { Component, Input } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'accessibility-doc', | ||
template: ` | ||
<div> | ||
<app-docsectiontext [title]="title" [id]="id"> | ||
<h3>Screen Reader</h3> | ||
<p> | ||
AnimateOnScroll does not require any roles and attributes. | ||
</p> | ||
<h3>Keyboard Support</h3> | ||
<p> | ||
Component does not include any interactive elements. | ||
</p> | ||
</app-docsectiontext> | ||
</div>` | ||
}) | ||
export class AccessibilityDoc { | ||
@Input() id: string; | ||
|
||
@Input() title: string; | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
src/app/showcase/doc/animateonscroll/animateonscrolldoc.module.ts
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { CommonModule } from '@angular/common'; | ||
import { NgModule } from '@angular/core'; | ||
import { RouterModule } from '@angular/router'; | ||
import { AppDocModule } from '../../layout/doc/app.doc.module'; | ||
import { AppCodeModule } from '../../layout/doc/code/app.code.component'; | ||
import { ImportDoc } from './importdoc'; | ||
import { BasicDoc } from './basicdoc'; | ||
import { AccessibilityDoc } from './accessibilitydoc'; | ||
import { AnimateOnScrollModule } from 'primeng/animateonscroll'; | ||
|
||
@NgModule({ | ||
imports: [CommonModule, RouterModule, AppCodeModule, AppDocModule, AnimateOnScrollModule], | ||
declarations: [ImportDoc, BasicDoc, AccessibilityDoc], | ||
exports: [AppDocModule] | ||
}) | ||
export class AnimateOnScrollDocModule {} |
Oops, something went wrong.
d5ce73f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
primeng-ssr-test – ./
primeng-ssr-test-primeng-test.vercel.app
primeng-ssr-test-git-master-primeng-test.vercel.app
primeng-ssr-test.vercel.app