UNPKG

angular-mixed-cdk-drag-drop

Version:

angular-mixed-cdk-drag-drop is an Angular `Directive` to support mixed orientation drag drop using angular cdk.

305 lines (298 loc) 13.8 kB
import * as i0 from '@angular/core'; import { EventEmitter, Input, Output, Self, Directive, SkipSelf, NgModule } from '@angular/core'; import * as i1 from '@angular/cdk/drag-drop'; import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; class MixedDragDropConfig { autoScrollStep = 6; } ; class MixedCdkDragDropDirective { element; cdkDropListGroup; /** @param {EventEmitter} dropped: emit previousIndex and currentIndex when dropList dropped. Valid when itemList is not being provided. **/ dropped = new EventEmitter(); itemList; orientation = 'horizontal'; containerSelector = ''; _resizeDragItem = new Set(); targetIndex = -1; sourceIndex = -1; source; observer; currentContentRect; animationFrame; constructor(element, cdkDropListGroup) { this.element = element; this.cdkDropListGroup = cdkDropListGroup; this.observer = new ResizeObserver((entries) => { this.animationFrame = window.requestAnimationFrame(() => { if (entries.length) { const element = this.containerSelector ? entries[0] : entries.find((e) => e.target === this.element.nativeElement); if (element) { this.currentContentRect = element.contentRect; for (let item of this._resizeDragItem) { item.onSizeChangeEmit(element.contentRect); } } } }); }); } ngAfterViewInit() { this.observeAll(); } ngOnChanges(changes) { if (changes['orientation']) { this.cdkDropListGroup._items.forEach((i) => { i.orientation = this.orientation; i.element.nativeElement.style.flexDirection = this.orientation === 'horizontal' ? 'row' : 'column'; }); } if (changes['containerSelector']) { this.observer?.disconnect(); this.observeAll(); } } addResizeDragItem(item) { this._resizeDragItem.add(item); if (this.currentContentRect) { item.onSizeChangeEmit(this.currentContentRect); } } deleteResizeDragItem(item) { this._resizeDragItem.delete(item); } onDropListDropped() { if (this.sourceIndex < 0 || this.targetIndex < 0) { return; } // if sourceIndex is before targetIndex then the real target should minus one, to remove the source placeholder which being counted. const target = this.targetIndex + (this.sourceIndex < this.targetIndex ? -1 : 0); if (this.sourceIndex !== this.targetIndex && target >= 0) { if (this.itemList) { moveItemInArray(this.itemList, this.sourceIndex, target); } else { this.dropped.emit({ previousIndex: this.sourceIndex, currentIndex: target, }); } this.sourceIndex = -1; this.targetIndex = -1; } // reset this.source = undefined; } onDropListEntered({ item, container, currentIndex }) { // dropList which the cdkDrag currently entered. const dropElement = container.element.nativeElement; // get all the dropList nodes in dropListGroup const dropListNodes = Array.from(dropElement.parentElement?.children ?? []); // dropList which the cdkDrag originally belonged. const sourceElement = item.dropContainer.element.nativeElement; // might enter multiple dropList after drag start, should only keep the index from the first time if (!this.source || this.sourceIndex === -1) { this.sourceIndex = dropListNodes.indexOf(sourceElement); this.source = item.dropContainer; } // target index should consider the currentIndex, which indicate drop before/after dropIndex (index of dropList which currently entered). this.targetIndex = dropListNodes.indexOf(dropElement) + currentIndex; } observeAll() { if (this.containerSelector) { const el = document.querySelector(this.containerSelector); if (el) { this.observer?.observe(el); } } else { this.observer?.observe(this.element.nativeElement); } } ngOnDestroy() { this.observer?.disconnect(); this.observer = undefined; this.currentContentRect = undefined; this._resizeDragItem.clear(); if (this.animationFrame) { window.cancelAnimationFrame(this.animationFrame); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragDropDirective, deps: [{ token: i0.ElementRef }, { token: i1.CdkDropListGroup, self: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.9", type: MixedCdkDragDropDirective, isStandalone: true, selector: "[cdkDropListGroup][mixedCdkDragDrop]", inputs: { itemList: "itemList", orientation: "orientation", containerSelector: "containerSelector" }, outputs: { dropped: "dropped" }, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragDropDirective, decorators: [{ type: Directive, args: [{ selector: '[cdkDropListGroup][mixedCdkDragDrop]', standalone: true }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i1.CdkDropListGroup, decorators: [{ type: Self }] }], propDecorators: { dropped: [{ type: Output }], itemList: [{ type: Input }], orientation: [{ type: Input }], containerSelector: [{ type: Input }] } }); class MixedCdkDropListDirective { cdkDropList; mixedDragDrop; config; lifecycleEmitter = new Subject(); constructor(cdkDropList, mixedDragDrop, config) { this.cdkDropList = cdkDropList; this.mixedDragDrop = mixedDragDrop; this.config = config; } ngOnInit() { this.cdkDropList.autoScrollStep = this.config.autoScrollStep; this.cdkDropList.orientation = this.mixedDragDrop.orientation; this.cdkDropList.element.nativeElement.style.flexDirection = this.mixedDragDrop.orientation === 'horizontal' ? 'row' : 'column'; this.cdkDropList.element.nativeElement.style.display = 'flex'; this.cdkDropList.element.nativeElement.style.flexWrap = 'nowrap'; this.cdkDropList.element.nativeElement.style.width = 'fit-content'; this.cdkDropList.element.nativeElement.style.height = 'fit-content'; this.cdkDropList.sorted .pipe(takeUntil(this.lifecycleEmitter)) .subscribe(event => this.mixedDragDrop.onDropListEntered(event)); this.cdkDropList.entered .pipe(takeUntil(this.lifecycleEmitter)) .subscribe(event => this.mixedDragDrop.onDropListEntered(event)); this.cdkDropList.dropped .pipe(takeUntil(this.lifecycleEmitter)) .subscribe(() => this.mixedDragDrop.onDropListDropped()); } ngOnDestroy() { this.lifecycleEmitter.next(); this.lifecycleEmitter.unsubscribe(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDropListDirective, deps: [{ token: i1.CdkDropList, self: true }, { token: MixedCdkDragDropDirective, skipSelf: true }, { token: MixedDragDropConfig }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.9", type: MixedCdkDropListDirective, isStandalone: true, selector: "[cdkDropList][mixedCdkDropList]", ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDropListDirective, decorators: [{ type: Directive, args: [{ selector: '[cdkDropList][mixedCdkDropList]', standalone: true }] }], ctorParameters: () => [{ type: i1.CdkDropList, decorators: [{ type: Self }] }, { type: MixedCdkDragDropDirective, decorators: [{ type: SkipSelf }] }, { type: MixedDragDropConfig }] }); class MixedCdkDragSizeHelperDirective { cdkDrag; mixedContainer; contentBoxSize = new EventEmitter(); constructor(cdkDrag, mixedContainer) { this.cdkDrag = cdkDrag; this.mixedContainer = mixedContainer; } ngAfterViewInit() { this.mixedContainer.addResizeDragItem(this); } ngOnDestroy() { this.mixedContainer.deleteResizeDragItem(this); } onSizeChangeEmit(rect) { this.contentBoxSize?.emit({ drag: this.cdkDrag, containerSize: rect }); } /** @param event :{MixedCdkDragContainerSize} contentSize observer event. * @param percentWidth :{number} set width to the percentage based on the dropListGroup Container width, valid from 0 to 100. * @param percentHeight :{number} set width to the percentage based on the dropListGroup Container width, valid from 0 to 100. **/ static defaultEmitter(event, percentWidth, percentHeight) { if (percentWidth) { event.drag.element.nativeElement.style.width = `${(percentWidth * event.containerSize.width) / 100}px`; } else { event.drag.element.nativeElement.style.width = ''; } if (percentHeight) { event.drag.element.nativeElement.style.height = `${(percentHeight * event.containerSize.height) / 100}px`; } else { event.drag.element.nativeElement.style.height = ''; } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragSizeHelperDirective, deps: [{ token: i1.CdkDrag, self: true }, { token: MixedCdkDragDropDirective, skipSelf: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.9", type: MixedCdkDragSizeHelperDirective, isStandalone: true, selector: "[cdkDrag][mixedCdkDragSizeHelper]", outputs: { contentBoxSize: "contentBoxSize" }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragSizeHelperDirective, decorators: [{ type: Directive, args: [{ selector: '[cdkDrag][mixedCdkDragSizeHelper]', standalone: true }] }], ctorParameters: () => [{ type: i1.CdkDrag, decorators: [{ type: Self }] }, { type: MixedCdkDragDropDirective, decorators: [{ type: SkipSelf }] }], propDecorators: { contentBoxSize: [{ type: Output }] } }); class MixedCdkDragDropModule { static forRoot(config) { return { ngModule: MixedCdkDragDropModule, providers: [ { provide: MixedDragDropConfig, useValue: config, }, ], }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragDropModule, imports: [DragDropModule, MixedCdkDragDropDirective, MixedCdkDropListDirective, MixedCdkDragSizeHelperDirective], exports: [MixedCdkDragDropDirective, MixedCdkDropListDirective, MixedCdkDragSizeHelperDirective] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragDropModule, providers: [ { provide: MixedDragDropConfig, useValue: MixedDragDropConfig, }, ], imports: [DragDropModule] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.9", ngImport: i0, type: MixedCdkDragDropModule, decorators: [{ type: NgModule, args: [{ imports: [ DragDropModule, MixedCdkDragDropDirective, MixedCdkDropListDirective, MixedCdkDragSizeHelperDirective ], exports: [ MixedCdkDragDropDirective, MixedCdkDropListDirective, MixedCdkDragSizeHelperDirective ], providers: [ { provide: MixedDragDropConfig, useValue: MixedDragDropConfig, }, ], }] }] }); /* * Public API Surface of angular-mixed-cdk-drag-drop */ /** * Generated bundle index. Do not edit. */ export { MixedCdkDragDropDirective, MixedCdkDragDropModule, MixedCdkDragSizeHelperDirective, MixedCdkDropListDirective, MixedDragDropConfig }; //# sourceMappingURL=angular-mixed-cdk-drag-drop.mjs.map