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
JavaScript
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