UNPKG

@hug/ngx-splitter

Version:
222 lines (217 loc) 13.4 kB
import { coerceNumberProperty, coerceBooleanProperty } from '@angular/cdk/coercion'; import * as i0 from '@angular/core'; import { Directive, HostBinding, Input, EventEmitter, inject, ElementRef, ChangeDetectorRef, DestroyRef, Component, ViewEncapsulation, ChangeDetectionStrategy, Output, ContentChildren } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { Subject, filter, switchMap, of, fromEvent, shareReplay, mergeWith, map, tap, takeUntil, take } from 'rxjs'; /** * Created by rtr on 22.12.2016. */ /** * Directive representing a panel in a Splitter Component */ class NgxSplitAreaDirective { elementRef; order; _size = null; direction = 'horizontal'; /** * Size in percent of the current area */ set size(value) { this._size = coerceNumberProperty(value); } get size() { const parentElement = this.elementRef.nativeElement.parentElement; const parentSizeInPixels = parentElement && (this.direction === 'horizontal' ? parentElement.offsetWidth : parentElement.offsetHeight) || undefined; return parentSizeInPixels && (100 * this.sizeinPixels / parentSizeInPixels); } get sizeinPixels() { return this.direction === 'horizontal' ? this.elementRef.nativeElement.offsetWidth : this.elementRef.nativeElement.offsetHeight; } /** * Min size in percent of the current area */ set minSizePixel(value) { this._minSizePixel = coerceNumberProperty(value); } get minSizePixel() { return this._minSizePixel; } get minWidth() { return this.direction === 'vertical' ? undefined : this._minSizePixel; } get minHeight() { return this.direction === 'horizontal' ? undefined : this._minSizePixel; } _minSizePixel = 0; constructor(elementRef) { this.elementRef = elementRef; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: NgxSplitAreaDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.1.4", type: NgxSplitAreaDirective, isStandalone: true, selector: "ngx-split-area", inputs: { size: "size", minSizePixel: "minSizePixel" }, host: { properties: { "style.order": "this.order", "style.flex-basis.%": "this._size", "style.min-width.px": "this.minWidth", "style.min-height.px": "this.minHeight" } }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: NgxSplitAreaDirective, decorators: [{ type: Directive, args: [{ selector: 'ngx-split-area', standalone: true }] }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { order: [{ type: HostBinding, args: ['style.order'] }], _size: [{ type: HostBinding, args: ['style.flex-basis.%'] }], size: [{ type: Input }], minSizePixel: [{ type: Input }], minWidth: [{ type: HostBinding, args: ['style.min-width.px'] }], minHeight: [{ type: HostBinding, args: ['style.min-height.px'] }] } }); /** * Splitter Component for Angular * * The splitter component allows to split horizontally or vertically, a container in N resizable part. */ class NgxSplitterComponent { /** * Event triggered when the user start to drag the cursor */ dragStart = new EventEmitter(false); /** * Event triggered during the cursor's drag */ dragProgress = new EventEmitter(false); /** * Event triggered when the user stop to drag the cursor */ dragEnd = new EventEmitter(false); /** * Direction of the split * Can be `horizontal` or `vertical` */ set direction(direction) { this._direction = direction; this.ensureDirections(); } get direction() { return this._direction; } /** * Size of the gutter in pixels * By default `10px` */ set gutterSize(gutterSize) { this._gutterSize = coerceNumberProperty(gutterSize); } get gutterSize() { return this._gutterSize; } get styleFlexDirection() { return this.direction === 'horizontal' ? 'row' : 'column'; } set spliterAreas(spliterAreas) { this.areas = spliterAreas.toArray(); this.areas.forEach((area, index) => area.order = 2 * index); this.ensureDirections(); } _direction = 'horizontal'; _disabled = null; startDragging$ = new Subject(); areas = new Array(); _gutterSize = 10; /** Retourne ou definit si le selecteur est desactivé. */ set disabled(value) { this._disabled = coerceBooleanProperty(value) || null; } get disabled() { return this._disabled; } elementRef = inject(ElementRef); changeDetectorRef = inject(ChangeDetectorRef); destroyRef = inject(DestroyRef); constructor() { this.startDragging$.pipe(filter(() => !this.disabled), switchMap(draggingEvent => { const areaA = this.areas.find(a => a.order === draggingEvent.index - 1); const areaB = this.areas.find(a => a.order === draggingEvent.index + 1); const mouseEvent = draggingEvent.event; if (!areaA || !areaB) { return of(mouseEvent); } const startPos = this.direction === 'horizontal' ? mouseEvent.pageX || mouseEvent.screenX : mouseEvent.pageY || mouseEvent.screenY; const containerSizeInPixels = this.direction === 'horizontal' ? this.elementRef.nativeElement.offsetWidth : this.elementRef.nativeElement.offsetHeight; const startSizeInPixelsA = areaA.sizeinPixels; const startSizeInPixelsB = areaB.sizeinPixels; this.dragStart.emit(); const mouseMove$ = fromEvent(document, 'mousemove').pipe(shareReplay({ bufferSize: 1, refCount: true })); const stopDragging$ = mouseMove$.pipe(filter(event => event.buttons !== 1), mergeWith(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend'), fromEvent(document, 'touchcancel')), map(event => { this.dragEnd.emit(); return event; }), shareReplay({ bufferSize: 1, refCount: true })); const drag$ = mouseMove$.pipe(filter(event => event.buttons === 1), mergeWith(fromEvent(document, 'touchmove')), tap(event => { const pos = this.direction === 'horizontal' ? event.pageX || event.screenX : event.pageY || event.screenY; const diffInPixels = startPos - pos; const areaSizeInPixelsA = startSizeInPixelsA - diffInPixels; const areaSizeInPixelsB = startSizeInPixelsB + diffInPixels; const areaSizeInPercentA = areaA.size = Math.min(100, Math.max(0, 100 * areaSizeInPixelsA / containerSizeInPixels)); areaB.size = Math.min(100, Math.max(0, 100 * areaSizeInPixelsB / containerSizeInPixels)); const percentWithTwoDigits = Math.round(areaSizeInPercentA * 100) / 100; this.dragProgress.emit(percentWithTwoDigits); }), takeUntil(stopDragging$)); return stopDragging$.pipe(take(1), mergeWith(drag$)); }), takeUntilDestroyed(this.destroyRef)).subscribe(event => { if (event.type !== 'mouseup' && event.type !== 'touchend' && event.type !== 'touchcancel') { this.elementRef.nativeElement.setAttribute('splitting', 'true'); } else { this.elementRef.nativeElement.removeAttribute('splitting'); } event.preventDefault(); this.changeDetectorRef.markForCheck(); return false; }); } ensureDirections() { this.areas.forEach(area => area.direction = this.direction); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: NgxSplitterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.4", type: NgxSplitterComponent, isStandalone: true, selector: "ngx-splitter", inputs: { direction: "direction", gutterSize: "gutterSize", disabled: "disabled" }, outputs: { dragStart: "dragStart", dragProgress: "dragProgress", dragEnd: "dragEnd" }, host: { properties: { "style.flex-direction": "this.styleFlexDirection", "attr.direction": "this._direction", "attr.disabled": "this._disabled" } }, queries: [{ propertyName: "spliterAreas", predicate: NgxSplitAreaDirective }], ngImport: i0, template: "<ng-content></ng-content>\n@for (area of areas; track $index; let index = $index, last = $last) {\n @if (last === false) {\n <div\n class=\"ngx-split-gutter\"\n [style.order]=\"index * 2 + 1\"\n [style.flex-basis.px]=\"gutterSize\"\n (mousedown)=\"startDragging$.next({ event: $event, index: index * 2 + 1 })\"\n (touchstart)=\"startDragging$.next({ event: $event, index: index * 2 + 1 })\"></div>\n }\n}\n", styles: ["ngx-splitter{display:flex;flex-wrap:nowrap;justify-content:flex-start;overflow:hidden}ngx-splitter[splitting] *{-moz-user-select:none;-webkit-user-select:none;user-select:none}ngx-splitter ngx-split-area{flex:1 1 auto;overflow:hidden}ngx-splitter .ngx-split-gutter{flex-shrink:0;flex-grow:0;background-position:50%;background-repeat:no-repeat;content:none;cursor:default;background-image:none}ngx-splitter[direction=horizontal] ngx-split-area{width:100%}ngx-splitter[direction=horizontal]:not([disabled]) .ngx-split-gutter{cursor:col-resize;content:\" \";background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==)}ngx-splitter[direction=vertical] ngx-split-area{height:100%}ngx-splitter[direction=vertical]:not([disabled]) .ngx-split-gutter{cursor:row-resize;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFCAMAAABl/6zIAAAABlBMVEUAAADMzMzIT8AyAAAAAXRSTlMAQObYZgAAABRJREFUeAFjYGRkwIMJSeMHlBkOABP7AEGzSuPKAAAAAElFTkSuQmCC)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: NgxSplitterComponent, decorators: [{ type: Component, args: [{ encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ngx-splitter', standalone: true, template: "<ng-content></ng-content>\n@for (area of areas; track $index; let index = $index, last = $last) {\n @if (last === false) {\n <div\n class=\"ngx-split-gutter\"\n [style.order]=\"index * 2 + 1\"\n [style.flex-basis.px]=\"gutterSize\"\n (mousedown)=\"startDragging$.next({ event: $event, index: index * 2 + 1 })\"\n (touchstart)=\"startDragging$.next({ event: $event, index: index * 2 + 1 })\"></div>\n }\n}\n", styles: ["ngx-splitter{display:flex;flex-wrap:nowrap;justify-content:flex-start;overflow:hidden}ngx-splitter[splitting] *{-moz-user-select:none;-webkit-user-select:none;user-select:none}ngx-splitter ngx-split-area{flex:1 1 auto;overflow:hidden}ngx-splitter .ngx-split-gutter{flex-shrink:0;flex-grow:0;background-position:50%;background-repeat:no-repeat;content:none;cursor:default;background-image:none}ngx-splitter[direction=horizontal] ngx-split-area{width:100%}ngx-splitter[direction=horizontal]:not([disabled]) .ngx-split-gutter{cursor:col-resize;content:\" \";background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAeCAYAAADkftS9AAAAIklEQVQoU2M4c+bMfxAGAgYYmwGrIIiDjrELjpo5aiZeMwF+yNnOs5KSvgAAAABJRU5ErkJggg==)}ngx-splitter[direction=vertical] ngx-split-area{height:100%}ngx-splitter[direction=vertical]:not([disabled]) .ngx-split-gutter{cursor:row-resize;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAFCAMAAABl/6zIAAAABlBMVEUAAADMzMzIT8AyAAAAAXRSTlMAQObYZgAAABRJREFUeAFjYGRkwIMJSeMHlBkOABP7AEGzSuPKAAAAAElFTkSuQmCC)}\n"] }] }], ctorParameters: () => [], propDecorators: { dragStart: [{ type: Output }], dragProgress: [{ type: Output }], dragEnd: [{ type: Output }], direction: [{ type: Input }], gutterSize: [{ type: Input }], styleFlexDirection: [{ type: HostBinding, args: ['style.flex-direction'] }], spliterAreas: [{ type: ContentChildren, args: [NgxSplitAreaDirective] }], _direction: [{ type: HostBinding, args: ['attr.direction'] }], _disabled: [{ type: HostBinding, args: ['attr.disabled'] }], disabled: [{ type: Input }] } }); /** * Generated bundle index. Do not edit. */ export { NgxSplitAreaDirective, NgxSplitterComponent }; //# sourceMappingURL=hug-ngx-splitter.mjs.map