@ciri/ngx-popup
Version:
An angular popup component that can customize animation.
826 lines (817 loc) • 24.3 kB
JavaScript
import { Injectable, ɵɵdefineInjectable, ɵɵinject, EventEmitter, Component, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, ViewChild, ApplicationRef, ComponentFactoryResolver, Injector, Inject, INJECTOR, forwardRef, ElementRef, Renderer2, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { AnimationBuilder, style, animate } from '@angular/animations';
import { Observable, Subject, Subscription } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { DOCUMENT, CommonModule } from '@angular/common';
/**
* @fileoverview added by tsickle
* Generated from: lib/animation.service.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class AnimationService {
/**
* @param {?} builder
*/
constructor(builder) {
this.builder = builder;
}
/**
* @param {?} element
* @param {?} animation
* @return {?}
*/
makeAnimation(element, animation) {
return new Observable((/**
* @param {?} observer
* @return {?}
*/
observer => {
// first define a reusable animation
/** @type {?} */
const myAnimation = this.builder.build(animation)
// use the returned factory object to create a player
;
// use the returned factory object to create a player
/** @type {?} */
const player = myAnimation.create(element);
player.play();
player.onDone((/**
* @return {?}
*/
() => {
observer.next();
observer.complete();
}));
return (/**
* @return {?}
*/
() => {
player.destroy();
});
}));
}
}
AnimationService.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
AnimationService.ctorParameters = () => [
{ type: AnimationBuilder }
];
/** @nocollapse */ AnimationService.ngInjectableDef = ɵɵdefineInjectable({ factory: function AnimationService_Factory() { return new AnimationService(ɵɵinject(AnimationBuilder)); }, token: AnimationService, providedIn: "root" });
if (false) {
/**
* @type {?}
* @private
*/
AnimationService.prototype.builder;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/overlay/overlay.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class OverlayComponent {
/**
* @param {?} animation
* @param {?} cdr
*/
constructor(animation, cdr) {
this.animation = animation;
this.cdr = cdr;
this.opacity = 0.5;
this.clickOverlay = new EventEmitter();
this.afterClose = new EventEmitter();
this._visible = false;
this.destroy$ = new Subject();
}
/**
* @param {?} value
* @return {?}
*/
set visible(value) {
this.animationSub && this.animationSub.unsubscribe();
if (value) {
this._visible = true;
this.cdr.detectChanges();
this.animationSub = this.makeAnimation('enter')
.pipe(takeUntil(this.destroy$))
.subscribe((/**
* @return {?}
*/
() => { }));
}
else {
this.animationSub = this.makeAnimation('leave')
.pipe(takeUntil(this.destroy$))
.subscribe((/**
* @return {?}
*/
() => {
this._visible = false;
this.cdr.detectChanges();
this.afterClose.emit();
}));
}
}
/**
* @return {?}
*/
get visible() {
return this._visible;
}
/**
* @return {?}
*/
get styles() {
return {
'z-index': this.zIndex,
'background': `rgba(0, 0, 0, ${this.opacity})`,
};
}
/**
* @return {?}
*/
ngOnInit() { }
/**
* @return {?}
*/
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
/**
* @return {?}
*/
onClick() {
this.clickOverlay.emit();
}
/**
* @param {?} state
* @return {?}
*/
makeAnimation(state) {
/** @type {?} */
const isEnter = state === 'enter';
/** @type {?} */
const el = this.container.nativeElement;
/** @type {?} */
const animation = isEnter
? [style({ opacity: 0 }), animate('.3s ease', style({ opacity: 1 }))]
: [style({ opacity: 1 }), animate('.3s ease', style({ opacity: 0 }))];
return this.animation.makeAnimation(el, animation);
}
}
OverlayComponent.decorators = [
{ type: Component, args: [{
selector: 'popup-overlay',
template: "<div\n class=\"overlay\"\n #container\n [hidden]=\"!visible\"\n [ngStyle]=\"styles\"\n (click)=\"onClick()\"\n></div>\n",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
styles: [".overlay{position:fixed;top:0;right:0;bottom:0;left:0}"]
}] }
];
/** @nocollapse */
OverlayComponent.ctorParameters = () => [
{ type: AnimationService },
{ type: ChangeDetectorRef }
];
OverlayComponent.propDecorators = {
zIndex: [{ type: Input }],
opacity: [{ type: Input }],
visible: [{ type: Input }],
clickOverlay: [{ type: Output }],
afterClose: [{ type: Output }],
container: [{ type: ViewChild, args: ['container', { static: false },] }]
};
if (false) {
/** @type {?} */
OverlayComponent.prototype.zIndex;
/** @type {?} */
OverlayComponent.prototype.opacity;
/** @type {?} */
OverlayComponent.prototype.clickOverlay;
/** @type {?} */
OverlayComponent.prototype.afterClose;
/**
* @type {?}
* @private
*/
OverlayComponent.prototype.container;
/**
* @type {?}
* @private
*/
OverlayComponent.prototype._visible;
/**
* @type {?}
* @private
*/
OverlayComponent.prototype.destroy$;
/**
* @type {?}
* @private
*/
OverlayComponent.prototype.animationSub;
/**
* @type {?}
* @private
*/
OverlayComponent.prototype.animation;
/**
* @type {?}
* @private
*/
OverlayComponent.prototype.cdr;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/overlay/overlay-helper.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @record
*/
function OverlayOptions() { }
if (false) {
/** @type {?} */
OverlayOptions.prototype.opacity;
/** @type {?|undefined} */
OverlayOptions.prototype.zIndex;
/** @type {?|undefined} */
OverlayOptions.prototype.onClick;
/** @type {?|undefined} */
OverlayOptions.prototype.getContainer;
}
/**
* \@dynamic
*/
class OverlayHelper {
/**
* @param {?} appRef
* @param {?} cfr
* @param {?} injector
* @param {?} document
*/
constructor(appRef, cfr, injector, document) {
this.appRef = appRef;
this.cfr = cfr;
this.injector = injector;
this.document = document;
}
/**
* @param {?} options
* @return {?}
*/
open(options) {
/** @type {?} */
const opts = Object.assign(this.getDefaultOptions(), options);
const { opacity, zIndex, getContainer } = opts;
/** @type {?} */
const factory = this.cfr.resolveComponentFactory(OverlayComponent);
/** @type {?} */
const componentRef = factory.create(this.injector);
this.appRef.attachView(componentRef.hostView);
const { nativeElement } = componentRef.location;
/** @type {?} */
const container = getContainer();
container.insertBefore(nativeElement, container.firstChild);
/** @type {?} */
const inst = componentRef.instance;
inst.opacity = opacity;
inst.zIndex = zIndex;
inst.visible = true;
this.setListener(componentRef, opts);
return (/**
* @return {?}
*/
() => {
inst.visible = false;
});
}
/**
* @private
* @return {?}
*/
getDefaultOptions() {
return {
opacity: 0.5,
getContainer: (/**
* @return {?}
*/
() => document.body)
};
}
/**
* @private
* @param {?} componentRef
* @param {?} opts
* @return {?}
*/
setListener(componentRef, opts) {
/** @type {?} */
const inst = componentRef.instance;
/** @type {?} */
const subs = new Subscription();
const { onClick } = opts;
subs.add(inst.afterClose.subscribe((/**
* @return {?}
*/
() => {
componentRef.destroy();
})));
if (onClick) {
subs.add(inst.clickOverlay.subscribe((/**
* @return {?}
*/
() => {
onClick();
})));
}
componentRef.onDestroy((/**
* @return {?}
*/
() => {
subs.unsubscribe();
}));
}
}
OverlayHelper.decorators = [
{ type: Injectable, args: [{
providedIn: 'root'
},] }
];
/** @nocollapse */
OverlayHelper.ctorParameters = () => [
{ type: ApplicationRef },
{ type: ComponentFactoryResolver },
{ type: Injector },
{ type: Document, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
];
/** @nocollapse */ OverlayHelper.ngInjectableDef = ɵɵdefineInjectable({ factory: function OverlayHelper_Factory() { return new OverlayHelper(ɵɵinject(ApplicationRef), ɵɵinject(ComponentFactoryResolver), ɵɵinject(INJECTOR), ɵɵinject(DOCUMENT)); }, token: OverlayHelper, providedIn: "root" });
if (false) {
/**
* @type {?}
* @private
*/
OverlayHelper.prototype.appRef;
/**
* @type {?}
* @private
*/
OverlayHelper.prototype.cfr;
/**
* @type {?}
* @private
*/
OverlayHelper.prototype.injector;
/**
* @type {?}
* @private
*/
OverlayHelper.prototype.document;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/popup/popup.component.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
let zIndex = 9999;
/**
* @record
*/
function PopupAnimations() { }
if (false) {
/** @type {?|undefined} */
PopupAnimations.prototype.enter;
/** @type {?|undefined} */
PopupAnimations.prototype.leave;
}
/** @enum {string} */
const Position = {
center: "center",
top: "top",
right: "right",
bottom: "bottom",
left: "left",
};
class PopupComponent {
/**
* @param {?} hostElRef
* @param {?} cdr
* @param {?} renderer
* @param {?} overlayHelper
* @param {?} animation
*/
constructor(hostElRef, cdr, renderer, overlayHelper, animation) {
this.hostElRef = hostElRef;
this.cdr = cdr;
this.renderer = renderer;
this.overlayHelper = overlayHelper;
this.animation = animation;
/* inputs
-------------------------- */
this.position = Position.center; /** 弹窗位置 */
/**
* 弹窗位置
*/
this.animations = {}; /** 自定义动画 */
/**
* 自定义动画
*/
this.overlay = true; /** 是否显示蒙版 */
/**
* 是否显示蒙版
*/
this.overlayOpacity = 0.5; /** 蒙版透明度 0~1 */
/**
* 蒙版透明度 0~1
*/
this.closeOnClickOverlay = true; /** 是否允许点击蒙版时自动关闭弹框 */
/**
* 是否允许点击蒙版时自动关闭弹框
*/
this.zIndex = zIndex++; /** 同 css z-index */
/**
* 同 css z-index
*/
this.externalClass = {}; /** 自定义类名 */
/**
* 自定义类名
*/
/* outputs
-------------------------- */
this.clickOverlay = new EventEmitter(); /** 点击蒙版时触发 */
/**
* 点击蒙版时触发
*/
this.beforeOpen = new EventEmitter(); /** 打开之前触发(还未执行进场动画) */
/**
* 打开之前触发(还未执行进场动画)
*/
this.afterOpen = new EventEmitter(); /** 打开之后触发(进场动画执行完毕) */
/**
* 打开之后触发(进场动画执行完毕)
*/
this.beforeClose = new EventEmitter(); /** 关闭之前触发(还未执行离场动画) */
/**
* 关闭之前触发(还未执行离场动画)
*/
this.afterClose = new EventEmitter(); /** 关闭之后触发(离场动画执行完毕) */
this.destroy$ = new Subject();
this.dirty = false;
this.leaving = false;
}
/**
* @return {?}
*/
get el() {
return this.container.nativeElement;
}
/**
* @return {?}
*/
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
/**
* @param {?} fn
* @return {?}
*/
registerOnChange(fn) {
this.onChange = fn;
}
/**
* @param {?} fn
* @return {?}
*/
registerOnTouched(fn) { }
/**
* @param {?} value
* @return {?}
*/
writeValue(value) {
if (value === null) {
return;
}
if (!this.dirty && !value) {
return;
}
if (this.animationSub) {
this.animationSub.unsubscribe();
}
if (value) {
this.open();
}
else {
this.close();
}
this.onChange(value);
this.dirty = true;
}
/**
* @private
* @return {?}
*/
open() {
// 避免闪烁
this.renderer.setStyle(this.el, 'opacity', 0);
this.visible = true;
this.cdr.markForCheck();
this.beforeOpen.emit();
this.leaving = false;
// 优化性能
setTimeout((/**
* @return {?}
*/
() => {
this.renderer.removeStyle(this.el, 'opacity');
this.overlay && this.openOverlay();
this.animationSub = this.makeAnimation('enter')
.pipe(takeUntil(this.destroy$))
.subscribe((/**
* @return {?}
*/
() => {
this.afterOpen.emit();
}));
}), 0);
}
/**
* @private
* @return {?}
*/
close() {
this.beforeClose.emit();
this.leaving = true;
this.overlay && this.closeOverlay();
this.animationSub = this.makeAnimation('leave')
.pipe(takeUntil(this.destroy$))
.subscribe((/**
* @return {?}
*/
() => {
this.visible = false;
this.cdr.detectChanges();
this.afterClose.emit();
this.leaving = false;
}));
}
/**
* @private
* @return {?}
*/
openOverlay() {
this.closeOverlay = this.overlayHelper.open({
opacity: this.overlayOpacity,
zIndex: this.zIndex,
getContainer: (/**
* @return {?}
*/
() => this.hostElRef.nativeElement),
onClick: (/**
* @return {?}
*/
() => {
this.clickOverlay.emit();
if (this.closeOnClickOverlay && this.visible && !this.leaving) {
this.writeValue(false);
}
})
});
}
/**
* @private
* @param {?} state
* @return {?}
*/
makeAnimation(state) {
/** @type {?} */
const el = this.container.nativeElement;
/** @type {?} */
const animation = state === 'leave' ? this.getLeaveAnimation() : this.getEnterAnimation();
return this.animation.makeAnimation(el, animation);
}
/**
* @private
* @return {?}
*/
getEnterAnimation() {
return this.animations.enter || {
[Position.center]: [style({ opacity: 0 }), animate('.3s ease', style({ opacity: 1 }))],
[Position.top]: [style({ transform: 'translate3d(0, -100%, 0)' }), animate('.3s ease', style({ transform: 'translate3d(0, 0, 0)' }))],
[Position.right]: [style({ transform: 'translate3d(100%, 0, 0)' }), animate('.3s ease', style({ transform: 'translate3d(0, 0, 0)' }))],
[Position.bottom]: [style({ transform: 'translate3d(0, 100%, 0)' }), animate('.3s ease', style({ transform: 'translate3d(0, 0, 0)' }))],
[Position.left]: [style({ transform: 'translate3d(-100%, 0, 0)' }), animate('.3s ease', style({ transform: 'translate3d(0, 0, 0)' }))]
}[this.position];
}
/**
* @private
* @return {?}
*/
getLeaveAnimation() {
return this.animations.leave || {
[Position.center]: [style({ opacity: 1 }), animate('.3s ease', style({ opacity: 0 }))],
[Position.top]: [style({ transform: 'translate3d(0, 0, 0)' }), animate('.3s ease', style({ transform: 'translate3d(0, -100%, 0)' }))],
[Position.right]: [style({ transform: 'translate3d(0, 0, 0)' }), animate('.3s ease', style({ transform: 'translate3d(100%, 0, 0)' }))],
[Position.bottom]: [style({ transform: 'translate3d(0, 0, 0)' }), animate('.3s ease', style({ transform: 'translate3d(0, 100%, 0)' }))],
[Position.left]: [style({ transform: 'translate3d(0, 0, 0)' }), animate('.3s ease', style({ transform: 'translate3d(-100%, 0, 0)' }))]
}[this.position];
}
}
PopupComponent.decorators = [
{ type: Component, args: [{
selector: 'ngx-popup',
template: "<div class=\"ngx-popup-wrapper is-{{ position }}\" [hidden]=\"!visible\" [style.zIndex]=\"zIndex\">\n <div class=\"ngx-popup\" #container [ngClass]=\"externalClass\">\n <ng-content></ng-content>\n </div>\n</div>\n",
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef((/**
* @return {?}
*/
() => PopupComponent)),
multi: true
}
],
styles: [".ngx-popup-wrapper{position:fixed;top:0;right:0;bottom:0;left:0;display:flex;pointer-events:none}.ngx-popup-wrapper[hidden]{display:none}.ngx-popup-wrapper .ngx-popup{pointer-events:auto}.ngx-popup-wrapper.is-center{align-items:center;justify-content:center}.ngx-popup-wrapper.is-top{align-items:flex-start;justify-content:center}.ngx-popup-wrapper.is-top .ngx-popup{width:100%}.ngx-popup-wrapper.is-right{align-items:center;justify-content:flex-end}.ngx-popup-wrapper.is-right .ngx-popup{height:100%}.ngx-popup-wrapper.is-bottom{align-items:flex-end;justify-content:center}.ngx-popup-wrapper.is-bottom .ngx-popup{width:100%}.ngx-popup-wrapper.is-left{align-items:center;justify-content:flex-start}.ngx-popup-wrapper.is-left .ngx-popup{height:100%}"]
}] }
];
/** @nocollapse */
PopupComponent.ctorParameters = () => [
{ type: ElementRef },
{ type: ChangeDetectorRef },
{ type: Renderer2 },
{ type: OverlayHelper },
{ type: AnimationService }
];
PopupComponent.propDecorators = {
position: [{ type: Input }],
animations: [{ type: Input }],
overlay: [{ type: Input }],
overlayOpacity: [{ type: Input }],
closeOnClickOverlay: [{ type: Input }],
zIndex: [{ type: Input }],
externalClass: [{ type: Input }],
clickOverlay: [{ type: Output }],
beforeOpen: [{ type: Output }],
afterOpen: [{ type: Output }],
beforeClose: [{ type: Output }],
afterClose: [{ type: Output }],
container: [{ type: ViewChild, args: ['container', { static: false },] }]
};
if (false) {
/** @type {?} */
PopupComponent.prototype.position;
/**
* 弹窗位置
* @type {?}
*/
PopupComponent.prototype.animations;
/**
* 自定义动画
* @type {?}
*/
PopupComponent.prototype.overlay;
/**
* 是否显示蒙版
* @type {?}
*/
PopupComponent.prototype.overlayOpacity;
/**
* 蒙版透明度 0~1
* @type {?}
*/
PopupComponent.prototype.closeOnClickOverlay;
/**
* 是否允许点击蒙版时自动关闭弹框
* @type {?}
*/
PopupComponent.prototype.zIndex;
/**
* 同 css z-index
* @type {?}
*/
PopupComponent.prototype.externalClass;
/**
* 自定义类名
* @type {?}
*/
PopupComponent.prototype.clickOverlay;
/**
* 点击蒙版时触发
* @type {?}
*/
PopupComponent.prototype.beforeOpen;
/**
* 打开之前触发(还未执行进场动画)
* @type {?}
*/
PopupComponent.prototype.afterOpen;
/**
* 打开之后触发(进场动画执行完毕)
* @type {?}
*/
PopupComponent.prototype.beforeClose;
/**
* 关闭之前触发(还未执行离场动画)
* @type {?}
*/
PopupComponent.prototype.afterClose;
/**
* 关闭之后触发(离场动画执行完毕)
* @type {?}
* @private
*/
PopupComponent.prototype.container;
/** @type {?} */
PopupComponent.prototype.visible;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.destroy$;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.animationSub;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.dirty;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.leaving;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.onChange;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.closeOverlay;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.hostElRef;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.cdr;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.renderer;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.overlayHelper;
/**
* @type {?}
* @private
*/
PopupComponent.prototype.animation;
}
/**
* @fileoverview added by tsickle
* Generated from: lib/popup.module.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
class PopupModule {
}
PopupModule.decorators = [
{ type: NgModule, args: [{
declarations: [OverlayComponent, PopupComponent],
imports: [CommonModule, FormsModule],
exports: [CommonModule, FormsModule, PopupComponent],
entryComponents: [OverlayComponent]
},] }
];
/**
* @fileoverview added by tsickle
* Generated from: public-api.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* Generated from: ciri-ngx-popup.ts
* @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
export { PopupComponent, PopupModule, Position, OverlayHelper as ɵa, AnimationService as ɵb, OverlayComponent as ɵc };
//# sourceMappingURL=ciri-ngx-popup.js.map