UNPKG

jsim-lazy-expandable

Version:

Light weight and easy to use expansion panel with lazy loaded content.

200 lines (194 loc) 13.2 kB
import * as i0 from '@angular/core'; import { Directive, EventEmitter, Component, Input, Output, ViewChild, ContentChild, NgModule } from '@angular/core'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; class LazyContentDirective { constructor(templateRef, viewContainer) { this.templateRef = templateRef; this.viewContainer = viewContainer; this.viewLoaded = false; this.viewContainer.clear(); this.viewLoaded = false; } showContent() { if (!this.viewLoaded) { this.viewContainer.createEmbeddedView(this.templateRef); this.viewLoaded = true; } } } LazyContentDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyContentDirective, deps: [{ token: i0.TemplateRef }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); LazyContentDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "12.0.0", version: "13.2.7", type: LazyContentDirective, selector: "ng-template[jsimLazyContent]", ngImport: i0 }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyContentDirective, decorators: [{ type: Directive, args: [{ selector: 'ng-template[jsimLazyContent]' }] }], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: i0.ViewContainerRef }]; } }); class LazyExpandableComponent { constructor() { /** Is the panel open? */ this.isOpen = false; /** Event emitted when isOpen changes */ this.openChanged = new EventEmitter(); /** Hide the arrow icon */ this.hideIcon = false; /** Height of the header when collapsed (in pixels) */ this.headerHeight = 48; /** Height of the header when expanded (in pixels) */ this.headerHeightExpanded = 64; /** Speed of the expand and collapse animation (in pixel by milisecond) */ this.animationSpeed = 0.5; /** Event emitted when animation ends */ this.animationEnd = new EventEmitter(); /** Is expanding and collapsing disabled? */ this.disabled = false; this.headerHeightStyle = this.headerHeight + 'px'; this.contentHeight = this.headerHeight + 'px'; this.currentContentHeight = 0; this.desiredContentHeight = 0; this.timeLastFrame = Date.now(); this.animationDuration = 0; this.currentAnimationTime = 0; this.lerp = (x, y, a) => x * (1 - a) + y * a; } ngOnInit() { } ngAfterContentInit() { setTimeout(() => { this.setContentHeight(false); if (this.isOpen && this.directive) { this.directive.showContent(); } }, 0); } toggleOpen() { if (this.disabled) { return; } this.isOpen = !this.isOpen; if (this.isOpen && this.directive) { this.directive.showContent(); } this.openChanged.emit(this.isOpen); this.setContentHeight(); } setContentHeight(animate = true) { if (animate) { if (this.isOpen) { this.headerHeightStyle = this.headerHeightExpanded + 'px'; this.desiredContentHeight = this.content.nativeElement.clientHeight; this.currentContentHeight = 0; } else { this.headerHeightStyle = this.headerHeight + 'px'; this.desiredContentHeight = 0; this.currentContentHeight = this.content.nativeElement.clientHeight; } this.animationDuration = Math.abs(this.desiredContentHeight - this.currentContentHeight) / this.animationSpeed; this.startAnimation(); } else { if (this.isOpen) { this.headerHeightStyle = this.headerHeightExpanded + 'px'; this.contentHeight = 'unset'; } else { this.headerHeightStyle = this.headerHeight + 'px'; this.contentHeight = this.headerHeight + 'px'; } } } startAnimation() { this.timeLastFrame = Date.now(); this.currentAnimationTime = 0; if (this.animationFrameRef) { cancelAnimationFrame(this.animationFrameRef); } this.animationFrameRef = requestAnimationFrame(this.animateHeader.bind(this)); } animateHeader() { const time = Date.now(); const deltatime = time - this.timeLastFrame; this.timeLastFrame = time; this.currentAnimationTime += deltatime; const amount = this.currentAnimationTime / this.animationDuration; this.currentContentHeight = this.lerp(this.currentContentHeight, this.desiredContentHeight, amount); if (this.isOpen) { this.currentContentHeight = Math.min(this.currentContentHeight, this.desiredContentHeight); this.contentHeight = this.headerHeightExpanded + this.currentContentHeight + 'px'; } else { this.currentContentHeight = Math.max(this.currentContentHeight, this.desiredContentHeight); this.contentHeight = this.headerHeight + this.currentContentHeight + 'px'; } if (this.currentContentHeight == this.desiredContentHeight) { this.animationEnded(); return; } this.animationFrameRef = requestAnimationFrame(this.animateHeader.bind(this)); } animationEnded() { this.animationEnd.emit(this.isOpen); if (this.isOpen) { this.contentHeight = 'unset'; } } } LazyExpandableComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyExpandableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); LazyExpandableComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.7", type: LazyExpandableComponent, selector: "jsim-lazy-expandable", inputs: { isOpen: "isOpen", hideIcon: "hideIcon", headerHeight: "headerHeight", headerHeightExpanded: "headerHeightExpanded", animationSpeed: "animationSpeed", disabled: "disabled" }, outputs: { openChanged: "openChanged", animationEnd: "animationEnd" }, queries: [{ propertyName: "directive", first: true, predicate: LazyContentDirective, descendants: true }], viewQueries: [{ propertyName: "content", first: true, predicate: ["lazyContent"], descendants: true }], ngImport: i0, template: "<div class=\"lazy-exp-container\" [class.is-open]=\"isOpen\" [style.height]=\"contentHeight\" [class.disabled]=\"disabled\">\n <div class=\"lazy-exp-header\" (click)=\"toggleOpen()\" [style.height]=\"headerHeightStyle\">\n <div class=\"lazy-exp-header-title\">\n <ng-content select=\"[exp-header-title]\"></ng-content>\n </div>\n <div class=\"lazy-exp-header-subtitle\">\n <ng-content select=\"[exp-header-subtitle]\"></ng-content>\n </div>\n <div *ngIf=\"!hideIcon\" class=\"lazy-exp-header-icon\"></div>\n </div>\n <div #lazyContent class=\"lazy-exp-content\">\n <div class=\"lazy-exp-content-container\">\n <ng-content select=\"[exp-content]\"></ng-content>\n </div>\n </div>\n</div>\n", styles: [".lazy-exp-container{--background-color: white;--background-color-hover: rgba(0,0,0,.04);--icon-color: rgb(119, 119, 119);border-radius:4px;box-shadow:0 3px 1px -2px #0003,0 2px 2px #00000024,0 1px 5px #0000001f;background-color:var(--background-color);overflow:hidden}.lazy-exp-header{display:flex;align-items:center;cursor:pointer;transition:height 225ms cubic-bezier(.4,0,.2,1)}.lazy-exp-container:not(.is-open):not(.disabled) .lazy-exp-header:hover{background-color:var(--background-color-hover)}.lazy-exp-container.disabled .lazy-exp-header{cursor:not-allowed}.lazy-exp-header-title{margin-left:1rem;width:50%}.lazy-exp-header-subtitle{width:50%;color:#2e2e2e}.lazy-exp-header-icon{justify-self:flex-end;margin-right:1rem;transform:rotate(0);transition:transform .2s ease-out}.is-open .lazy-exp-header-icon{transform:rotate(180deg)}.lazy-exp-header-icon:after{border-color:var(--icon-color);border-style:solid;border-width:0 2px 2px 0;content:\"\";display:inline-block;padding:3px;transform:rotate(45deg);vertical-align:middle}.lazy-exp-content{box-sizing:border-box;padding:1rem}\n"], directives: [{ type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyExpandableComponent, decorators: [{ type: Component, args: [{ selector: 'jsim-lazy-expandable', template: "<div class=\"lazy-exp-container\" [class.is-open]=\"isOpen\" [style.height]=\"contentHeight\" [class.disabled]=\"disabled\">\n <div class=\"lazy-exp-header\" (click)=\"toggleOpen()\" [style.height]=\"headerHeightStyle\">\n <div class=\"lazy-exp-header-title\">\n <ng-content select=\"[exp-header-title]\"></ng-content>\n </div>\n <div class=\"lazy-exp-header-subtitle\">\n <ng-content select=\"[exp-header-subtitle]\"></ng-content>\n </div>\n <div *ngIf=\"!hideIcon\" class=\"lazy-exp-header-icon\"></div>\n </div>\n <div #lazyContent class=\"lazy-exp-content\">\n <div class=\"lazy-exp-content-container\">\n <ng-content select=\"[exp-content]\"></ng-content>\n </div>\n </div>\n</div>\n", styles: [".lazy-exp-container{--background-color: white;--background-color-hover: rgba(0,0,0,.04);--icon-color: rgb(119, 119, 119);border-radius:4px;box-shadow:0 3px 1px -2px #0003,0 2px 2px #00000024,0 1px 5px #0000001f;background-color:var(--background-color);overflow:hidden}.lazy-exp-header{display:flex;align-items:center;cursor:pointer;transition:height 225ms cubic-bezier(.4,0,.2,1)}.lazy-exp-container:not(.is-open):not(.disabled) .lazy-exp-header:hover{background-color:var(--background-color-hover)}.lazy-exp-container.disabled .lazy-exp-header{cursor:not-allowed}.lazy-exp-header-title{margin-left:1rem;width:50%}.lazy-exp-header-subtitle{width:50%;color:#2e2e2e}.lazy-exp-header-icon{justify-self:flex-end;margin-right:1rem;transform:rotate(0);transition:transform .2s ease-out}.is-open .lazy-exp-header-icon{transform:rotate(180deg)}.lazy-exp-header-icon:after{border-color:var(--icon-color);border-style:solid;border-width:0 2px 2px 0;content:\"\";display:inline-block;padding:3px;transform:rotate(45deg);vertical-align:middle}.lazy-exp-content{box-sizing:border-box;padding:1rem}\n"] }] }], ctorParameters: function () { return []; }, propDecorators: { isOpen: [{ type: Input }], openChanged: [{ type: Output }], hideIcon: [{ type: Input }], headerHeight: [{ type: Input }], headerHeightExpanded: [{ type: Input }], animationSpeed: [{ type: Input }], animationEnd: [{ type: Output }], disabled: [{ type: Input }], content: [{ type: ViewChild, args: ['lazyContent'] }], directive: [{ type: ContentChild, args: [LazyContentDirective] }] } }); class LazyExpandableModule { } LazyExpandableModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyExpandableModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); LazyExpandableModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyExpandableModule, declarations: [LazyExpandableComponent, LazyContentDirective], imports: [CommonModule], exports: [LazyExpandableComponent, LazyContentDirective] }); LazyExpandableModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyExpandableModule, imports: [[ CommonModule ]] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.7", ngImport: i0, type: LazyExpandableModule, decorators: [{ type: NgModule, args: [{ declarations: [ LazyExpandableComponent, LazyContentDirective ], imports: [ CommonModule ], exports: [ LazyExpandableComponent, LazyContentDirective ] }] }] }); /** * Generated bundle index. Do not edit. */ export { LazyContentDirective, LazyExpandableComponent, LazyExpandableModule }; //# sourceMappingURL=jsim-lazy-expandable.mjs.map