UNPKG

ngx-split-view

Version:

A resizable flex-box split layout component for Angular

249 lines (243 loc) 8.62 kB
import { __decorate } from 'tslib'; import { ViewContainerRef, Input, Directive, TemplateRef, EventEmitter, Output, ContentChildren, ContentChild, HostBinding, Component, ChangeDetectionStrategy, NgModule } from '@angular/core'; import { Subject, Subscription } from 'rxjs'; import { startWith, switchMap, mergeAll, map } from 'rxjs/operators'; import Split from 'split.js'; let SplitPaneDirective = class SplitPaneDirective { constructor(viewContainerRef) { this.viewContainerRef = viewContainerRef; this.splitRatio = 1; this.minSize = 100; this.sizeChanges = new Subject(); this.minSizeChanges = new Subject(); } ngOnChanges(changes) { if (changes.splitRatio) { this.sizeChanges.next(); } if (changes.minSize) { this.minSizeChanges.next(); } } }; SplitPaneDirective.ctorParameters = () => [ { type: ViewContainerRef } ]; __decorate([ Input() ], SplitPaneDirective.prototype, "splitRatio", void 0); __decorate([ Input() ], SplitPaneDirective.prototype, "minSize", void 0); SplitPaneDirective = __decorate([ Directive({ // tslint:disable-next-line: directive-selector selector: '[splitPane]' }) ], SplitPaneDirective); let SplitViewGutterDirective = class SplitViewGutterDirective { constructor(template) { this.template = template; } }; SplitViewGutterDirective.ctorParameters = () => [ { type: TemplateRef } ]; SplitViewGutterDirective = __decorate([ Directive({ // tslint:disable-next-line: directive-selector selector: '[gutterTemplate]' }) ], SplitViewGutterDirective); let SplitViewComponent = class SplitViewComponent { constructor(viewContainerRef) { this.viewContainerRef = viewContainerRef; this.dragging = new EventEmitter(); this.dragStart = new EventEmitter(); this.dragEnd = new EventEmitter(); this.expandToMin = false; this.gutterSize = 10; this.gutterAlign = 'center'; this.snapOffset = 30; this.dragInterval = 1; this.direction = 'horizontal'; this.subscriptions = new Subscription(); } get isHorizontal() { return this.direction === 'horizontal'; } get isVertical() { return this.direction === 'vertical'; } ngOnChanges(changes) { if (changes.direction || changes.gutterSize || changes.gutterAlign || changes.snapOffset || changes.dragInterval || changes.expandToMin) { this.refresh(); } } ngAfterContentInit() { const splitPaneChanges = this.splitPanes.changes .pipe(startWith(this.splitPanes)); const childrenChanges = splitPaneChanges .subscribe(() => this.refresh()); const sizeChanges = splitPaneChanges .pipe(switchMap(() => this.splitPanes.map(p => p.sizeChanges)), mergeAll()) .subscribe(() => { var _a; return (_a = this.split) === null || _a === void 0 ? void 0 : _a.setSizes(this.getSizes()); }); const dragEndEvents = this.dragEnd .pipe(map(event => event.sizes)) .subscribe(sizes => { const panes = this.splitPanes.toArray(); for (let i = 0; i < panes.length; i++) { panes[i].splitRatio = sizes[i]; } }); this.subscriptions.add(childrenChanges); this.subscriptions.add(sizeChanges); this.subscriptions.add(dragEndEvents); } ngOnDestroy() { this.subscriptions.unsubscribe(); this.destroySplit(); } refresh() { this.destroySplit(); if (!this.splitPanes || this.splitPanes.length === 0) { return; } const panes = new Array(); const minSizes = new Array(); this.splitPanes.forEach(d => { panes.push(d.viewContainerRef.element.nativeElement); minSizes.push(d.minSize); }); const splitOptions = { sizes: this.getSizes(), minSize: minSizes, expandToMin: this.expandToMin, gutterSize: this.gutterSize, gutterAlign: this.gutterAlign, snapOffset: this.snapOffset, dragInterval: this.dragInterval, direction: this.direction, elementStyle: (dimension, size, gutterSize) => ({ flexBasis: 'calc(' + size + '% - ' + gutterSize + 'px)' }), gutterStyle: (dimension, gutterSize) => ({ flexBasis: gutterSize + 'px' }), onDrag: (sizes) => { if (this.dragging.observers.length > 0) { this.dragging.emit({ source: this, sizes }); } }, onDragStart: (sizes) => this.dragStart.emit({ source: this, sizes }), onDragEnd: (sizes) => this.dragEnd.emit({ source: this, sizes }) }; if (this.gutterDef) { splitOptions.gutter = (index, direction) => { const view = this.viewContainerRef.createEmbeddedView(this.gutterDef.template); const elements = view.rootNodes.filter(e => e instanceof HTMLElement); if (elements.length !== 1) { throw new Error('Gutter template must contain exactly one element'); } return elements[0]; }; } this.split = Split(panes, splitOptions); } destroySplit() { if (!this.split) { return; } this.viewContainerRef.clear(); this.split.destroy(false, !!this.gutterDef); this.split = undefined; } getSizes() { const panes = new Array(); const ratios = new Array(); let totalSize = 0; this.splitPanes.forEach(d => { panes.push(d.viewContainerRef.element.nativeElement); const sanitizedSize = d.splitRatio >= 0 ? d.splitRatio : 0; ratios.push(sanitizedSize); totalSize += sanitizedSize; }); return ratios.map(size => (size / totalSize) * 100); } }; SplitViewComponent.ctorParameters = () => [ { type: ViewContainerRef } ]; __decorate([ Output() ], SplitViewComponent.prototype, "dragging", void 0); __decorate([ Output() ], SplitViewComponent.prototype, "dragStart", void 0); __decorate([ Output() ], SplitViewComponent.prototype, "dragEnd", void 0); __decorate([ Input() ], SplitViewComponent.prototype, "expandToMin", void 0); __decorate([ Input() ], SplitViewComponent.prototype, "gutterSize", void 0); __decorate([ Input() ], SplitViewComponent.prototype, "gutterAlign", void 0); __decorate([ Input() ], SplitViewComponent.prototype, "snapOffset", void 0); __decorate([ Input() ], SplitViewComponent.prototype, "dragInterval", void 0); __decorate([ Input() ], SplitViewComponent.prototype, "direction", void 0); __decorate([ ContentChildren(SplitPaneDirective) ], SplitViewComponent.prototype, "splitPanes", void 0); __decorate([ ContentChild(SplitViewGutterDirective, { static: true }) ], SplitViewComponent.prototype, "gutterDef", void 0); __decorate([ HostBinding('class.split-view-horizontal') ], SplitViewComponent.prototype, "isHorizontal", null); __decorate([ HostBinding('class.split-view-vertical') ], SplitViewComponent.prototype, "isVertical", null); SplitViewComponent = __decorate([ Component({ // tslint:disable-next-line: component-selector selector: 'split-view', template: '<ng-content select="[splitPane]"></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:flex}:host.split-view-horizontal{flex-direction:row}:host.split-view-vertical{flex-direction:column}::ng-deep .gutter.gutter-horizontal{cursor:col-resize}::ng-deep .gutter.gutter-vertical{cursor:row-resize}"] }) ], SplitViewComponent); let SplitViewModule = class SplitViewModule { }; SplitViewModule = __decorate([ NgModule({ declarations: [ SplitPaneDirective, SplitViewGutterDirective, SplitViewComponent ], exports: [ SplitPaneDirective, SplitViewGutterDirective, SplitViewComponent ] }) ], SplitViewModule); /* * Public API Surface of ngx-split-view */ /** * Generated bundle index. Do not edit. */ export { SplitPaneDirective, SplitViewComponent, SplitViewGutterDirective, SplitViewModule }; //# sourceMappingURL=ngx-split-view.js.map