angular-draggable-droppable
Version:
Drag and drop for angular 15.0+
807 lines (797 loc) • 36 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Directive, EventEmitter, Optional, Inject, Input, Output, NgModule } from '@angular/core';
import { Subject, Observable, ReplaySubject, merge, combineLatest, fromEvent } from 'rxjs';
import { filter, mergeMap, startWith, map, share, takeUntil, take, takeLast, count, pairwise, distinctUntilChanged } from 'rxjs/operators';
import { DOCUMENT } from '@angular/common';
import autoScroll from '@mattlewis92/dom-autoscroller';
function addClass(renderer, element, classToAdd) {
if (classToAdd) {
classToAdd
.split(' ')
.forEach((className) => renderer.addClass(element.nativeElement, className));
}
}
function removeClass(renderer, element, classToRemove) {
if (classToRemove) {
classToRemove
.split(' ')
.forEach((className) => renderer.removeClass(element.nativeElement, className));
}
}
class DraggableHelper {
constructor() {
this.currentDrag = new Subject();
}
}
DraggableHelper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DraggableHelper, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
DraggableHelper.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DraggableHelper, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DraggableHelper, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
/**
* If the window isn't scrollable, then place this on the scrollable container that draggable elements are inside. e.g.
* ```html
<div style="overflow: scroll" mwlDraggableScrollContainer>
<div mwlDraggable>Drag me!</div>
</div>
```
*/
class DraggableScrollContainerDirective {
/**
* @hidden
*/
constructor(elementRef) {
this.elementRef = elementRef;
}
}
DraggableScrollContainerDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DraggableScrollContainerDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
DraggableScrollContainerDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.3", type: DraggableScrollContainerDirective, selector: "[mwlDraggableScrollContainer]", ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DraggableScrollContainerDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlDraggableScrollContainer]',
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }]; } });
class DraggableDirective {
/**
* @hidden
*/
constructor(element, renderer, draggableHelper, zone, vcr, scrollContainer, document) {
this.element = element;
this.renderer = renderer;
this.draggableHelper = draggableHelper;
this.zone = zone;
this.vcr = vcr;
this.scrollContainer = scrollContainer;
this.document = document;
/**
* The axis along which the element is draggable
*/
this.dragAxis = { x: true, y: true };
/**
* Snap all drags to an x / y grid
*/
this.dragSnapGrid = {};
/**
* Show a ghost element that shows the drag when dragging
*/
this.ghostDragEnabled = true;
/**
* Show the original element when ghostDragEnabled is true
*/
this.showOriginalElementWhileDragging = false;
/**
* The cursor to use when hovering over a draggable element
*/
this.dragCursor = '';
/*
* Options used to control the behaviour of auto scrolling: https://www.npmjs.com/package/dom-autoscroller
*/
this.autoScroll = {
margin: 20,
};
/**
* Called when the element can be dragged along one axis and has the mouse or pointer device pressed on it
*/
this.dragPointerDown = new EventEmitter();
/**
* Called when the element has started to be dragged.
* Only called after at least one mouse or touch move event.
* If you call $event.cancelDrag$.emit() it will cancel the current drag
*/
this.dragStart = new EventEmitter();
/**
* Called after the ghost element has been created
*/
this.ghostElementCreated = new EventEmitter();
/**
* Called when the element is being dragged
*/
this.dragging = new EventEmitter();
/**
* Called after the element is dragged
*/
this.dragEnd = new EventEmitter();
/**
* @hidden
*/
this.pointerDown$ = new Subject();
/**
* @hidden
*/
this.pointerMove$ = new Subject();
/**
* @hidden
*/
this.pointerUp$ = new Subject();
this.eventListenerSubscriptions = {};
this.destroy$ = new Subject();
this.timeLongPress = { timerBegin: 0, timerEnd: 0 };
}
ngOnInit() {
this.checkEventListeners();
const pointerDragged$ = this.pointerDown$.pipe(filter(() => this.canDrag()), mergeMap((pointerDownEvent) => {
// fix for https://github.com/mattlewis92/angular-draggable-droppable/issues/61
// stop mouse events propagating up the chain
if (pointerDownEvent.event.stopPropagation && !this.scrollContainer) {
pointerDownEvent.event.stopPropagation();
}
// hack to prevent text getting selected in safari while dragging
const globalDragStyle = this.renderer.createElement('style');
this.renderer.setAttribute(globalDragStyle, 'type', 'text/css');
this.renderer.appendChild(globalDragStyle, this.renderer.createText(`
body * {
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
user-select: none;
}
`));
requestAnimationFrame(() => {
this.document.head.appendChild(globalDragStyle);
});
const startScrollPosition = this.getScrollPosition();
const scrollContainerScroll$ = new Observable((observer) => {
const scrollContainer = this.scrollContainer
? this.scrollContainer.elementRef.nativeElement
: 'window';
return this.renderer.listen(scrollContainer, 'scroll', (e) => observer.next(e));
}).pipe(startWith(startScrollPosition), map(() => this.getScrollPosition()));
const currentDrag$ = new Subject();
const cancelDrag$ = new ReplaySubject();
if (this.dragPointerDown.observers.length > 0) {
this.zone.run(() => {
this.dragPointerDown.next({ x: 0, y: 0 });
});
}
const dragComplete$ = merge(this.pointerUp$, this.pointerDown$, cancelDrag$, this.destroy$).pipe(share());
const pointerMove = combineLatest([
this.pointerMove$,
scrollContainerScroll$,
]).pipe(map(([pointerMoveEvent, scroll]) => {
return {
currentDrag$,
transformX: pointerMoveEvent.clientX - pointerDownEvent.clientX,
transformY: pointerMoveEvent.clientY - pointerDownEvent.clientY,
clientX: pointerMoveEvent.clientX,
clientY: pointerMoveEvent.clientY,
scrollLeft: scroll.left,
scrollTop: scroll.top,
target: pointerMoveEvent.event.target,
};
}), map((moveData) => {
if (this.dragSnapGrid.x) {
moveData.transformX =
Math.round(moveData.transformX / this.dragSnapGrid.x) *
this.dragSnapGrid.x;
}
if (this.dragSnapGrid.y) {
moveData.transformY =
Math.round(moveData.transformY / this.dragSnapGrid.y) *
this.dragSnapGrid.y;
}
return moveData;
}), map((moveData) => {
if (!this.dragAxis.x) {
moveData.transformX = 0;
}
if (!this.dragAxis.y) {
moveData.transformY = 0;
}
return moveData;
}), map((moveData) => {
const scrollX = moveData.scrollLeft - startScrollPosition.left;
const scrollY = moveData.scrollTop - startScrollPosition.top;
return {
...moveData,
x: moveData.transformX + scrollX,
y: moveData.transformY + scrollY,
};
}), filter(({ x, y, transformX, transformY }) => !this.validateDrag ||
this.validateDrag({
x,
y,
transform: { x: transformX, y: transformY },
})), takeUntil(dragComplete$), share());
const dragStarted$ = pointerMove.pipe(take(1), share());
const dragEnded$ = pointerMove.pipe(takeLast(1), share());
dragStarted$.subscribe(({ clientX, clientY, x, y }) => {
if (this.dragStart.observers.length > 0) {
this.zone.run(() => {
this.dragStart.next({ cancelDrag$ });
});
}
this.scroller = autoScroll([
this.scrollContainer
? this.scrollContainer.elementRef.nativeElement
: this.document.defaultView,
], {
...this.autoScroll,
autoScroll() {
return true;
},
});
addClass(this.renderer, this.element, this.dragActiveClass);
if (this.ghostDragEnabled) {
const rect = this.element.nativeElement.getBoundingClientRect();
const clone = this.element.nativeElement.cloneNode(true);
if (!this.showOriginalElementWhileDragging) {
this.renderer.setStyle(this.element.nativeElement, 'visibility', 'hidden');
}
if (this.ghostElementAppendTo) {
this.ghostElementAppendTo.appendChild(clone);
}
else {
this.element.nativeElement.parentNode.insertBefore(clone, this.element.nativeElement.nextSibling);
}
this.ghostElement = clone;
this.document.body.style.cursor = this.dragCursor;
this.setElementStyles(clone, {
position: 'fixed',
top: `${rect.top}px`,
left: `${rect.left}px`,
width: `${rect.width}px`,
height: `${rect.height}px`,
cursor: this.dragCursor,
margin: '0',
willChange: 'transform',
pointerEvents: 'none',
});
if (this.ghostElementTemplate) {
const viewRef = this.vcr.createEmbeddedView(this.ghostElementTemplate);
clone.innerHTML = '';
viewRef.rootNodes
.filter((node) => node instanceof Node)
.forEach((node) => {
clone.appendChild(node);
});
dragEnded$.subscribe(() => {
this.vcr.remove(this.vcr.indexOf(viewRef));
});
}
if (this.ghostElementCreated.observers.length > 0) {
this.zone.run(() => {
this.ghostElementCreated.emit({
clientX: clientX - x,
clientY: clientY - y,
element: clone,
});
});
}
dragEnded$.subscribe(() => {
clone.parentElement.removeChild(clone);
this.ghostElement = null;
this.renderer.setStyle(this.element.nativeElement, 'visibility', '');
});
}
this.draggableHelper.currentDrag.next(currentDrag$);
});
dragEnded$
.pipe(mergeMap((dragEndData) => {
const dragEndData$ = cancelDrag$.pipe(count(), take(1), map((calledCount) => ({
...dragEndData,
dragCancelled: calledCount > 0,
})));
cancelDrag$.complete();
return dragEndData$;
}))
.subscribe(({ x, y, dragCancelled }) => {
this.scroller.destroy();
if (this.dragEnd.observers.length > 0) {
this.zone.run(() => {
this.dragEnd.next({ x, y, dragCancelled });
});
}
removeClass(this.renderer, this.element, this.dragActiveClass);
currentDrag$.complete();
});
merge(dragComplete$, dragEnded$)
.pipe(take(1))
.subscribe(() => {
requestAnimationFrame(() => {
this.document.head.removeChild(globalDragStyle);
});
});
return pointerMove;
}), share());
merge(pointerDragged$.pipe(take(1), map((value) => [, value])), pointerDragged$.pipe(pairwise()))
.pipe(filter(([previous, next]) => {
if (!previous) {
return true;
}
return previous.x !== next.x || previous.y !== next.y;
}), map(([previous, next]) => next))
.subscribe(({ x, y, currentDrag$, clientX, clientY, transformX, transformY, target, }) => {
if (this.dragging.observers.length > 0) {
this.zone.run(() => {
this.dragging.next({ x, y });
});
}
requestAnimationFrame(() => {
if (this.ghostElement) {
const transform = `translate3d(${transformX}px, ${transformY}px, 0px)`;
this.setElementStyles(this.ghostElement, {
transform,
'-webkit-transform': transform,
'-ms-transform': transform,
'-moz-transform': transform,
'-o-transform': transform,
});
}
});
currentDrag$.next({
clientX,
clientY,
dropData: this.dropData,
target,
});
});
}
ngOnChanges(changes) {
if (changes.dragAxis) {
this.checkEventListeners();
}
}
ngOnDestroy() {
this.unsubscribeEventListeners();
this.pointerDown$.complete();
this.pointerMove$.complete();
this.pointerUp$.complete();
this.destroy$.next();
}
checkEventListeners() {
const canDrag = this.canDrag();
const hasEventListeners = Object.keys(this.eventListenerSubscriptions).length > 0;
if (canDrag && !hasEventListeners) {
this.zone.runOutsideAngular(() => {
this.eventListenerSubscriptions.mousedown = this.renderer.listen(this.element.nativeElement, 'mousedown', (event) => {
this.onMouseDown(event);
});
this.eventListenerSubscriptions.mouseup = this.renderer.listen('document', 'mouseup', (event) => {
this.onMouseUp(event);
});
this.eventListenerSubscriptions.touchstart = this.renderer.listen(this.element.nativeElement, 'touchstart', (event) => {
this.onTouchStart(event);
});
this.eventListenerSubscriptions.touchend = this.renderer.listen('document', 'touchend', (event) => {
this.onTouchEnd(event);
});
this.eventListenerSubscriptions.touchcancel = this.renderer.listen('document', 'touchcancel', (event) => {
this.onTouchEnd(event);
});
this.eventListenerSubscriptions.mouseenter = this.renderer.listen(this.element.nativeElement, 'mouseenter', () => {
this.onMouseEnter();
});
this.eventListenerSubscriptions.mouseleave = this.renderer.listen(this.element.nativeElement, 'mouseleave', () => {
this.onMouseLeave();
});
});
}
else if (!canDrag && hasEventListeners) {
this.unsubscribeEventListeners();
}
}
onMouseDown(event) {
if (event.button === 0) {
if (!this.eventListenerSubscriptions.mousemove) {
this.eventListenerSubscriptions.mousemove = this.renderer.listen('document', 'mousemove', (mouseMoveEvent) => {
this.pointerMove$.next({
event: mouseMoveEvent,
clientX: mouseMoveEvent.clientX,
clientY: mouseMoveEvent.clientY,
});
});
}
this.pointerDown$.next({
event,
clientX: event.clientX,
clientY: event.clientY,
});
}
}
onMouseUp(event) {
if (event.button === 0) {
if (this.eventListenerSubscriptions.mousemove) {
this.eventListenerSubscriptions.mousemove();
delete this.eventListenerSubscriptions.mousemove;
}
this.pointerUp$.next({
event,
clientX: event.clientX,
clientY: event.clientY,
});
}
}
onTouchStart(event) {
let startScrollPosition;
let isDragActivated;
let hasContainerScrollbar;
if (this.touchStartLongPress) {
this.timeLongPress.timerBegin = Date.now();
isDragActivated = false;
hasContainerScrollbar = this.hasScrollbar();
startScrollPosition = this.getScrollPosition();
}
if (!this.eventListenerSubscriptions.touchmove) {
const contextMenuListener = fromEvent(this.document, 'contextmenu').subscribe((e) => {
e.preventDefault();
});
const touchMoveListener = fromEvent(this.document, 'touchmove', {
passive: false,
}).subscribe((touchMoveEvent) => {
if (this.touchStartLongPress &&
!isDragActivated &&
hasContainerScrollbar) {
isDragActivated = this.shouldBeginDrag(event, touchMoveEvent, startScrollPosition);
}
if (!this.touchStartLongPress ||
!hasContainerScrollbar ||
isDragActivated) {
touchMoveEvent.preventDefault();
this.pointerMove$.next({
event: touchMoveEvent,
clientX: touchMoveEvent.targetTouches[0].clientX,
clientY: touchMoveEvent.targetTouches[0].clientY,
});
}
});
this.eventListenerSubscriptions.touchmove = () => {
contextMenuListener.unsubscribe();
touchMoveListener.unsubscribe();
};
}
this.pointerDown$.next({
event,
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY,
});
}
onTouchEnd(event) {
if (this.eventListenerSubscriptions.touchmove) {
this.eventListenerSubscriptions.touchmove();
delete this.eventListenerSubscriptions.touchmove;
if (this.touchStartLongPress) {
this.enableScroll();
}
}
this.pointerUp$.next({
event,
clientX: event.changedTouches[0].clientX,
clientY: event.changedTouches[0].clientY,
});
}
onMouseEnter() {
this.setCursor(this.dragCursor);
}
onMouseLeave() {
this.setCursor('');
}
canDrag() {
return this.dragAxis.x || this.dragAxis.y;
}
setCursor(value) {
if (!this.eventListenerSubscriptions.mousemove) {
this.renderer.setStyle(this.element.nativeElement, 'cursor', value);
}
}
unsubscribeEventListeners() {
Object.keys(this.eventListenerSubscriptions).forEach((type) => {
this.eventListenerSubscriptions[type]();
delete this.eventListenerSubscriptions[type];
});
}
setElementStyles(element, styles) {
Object.keys(styles).forEach((key) => {
this.renderer.setStyle(element, key, styles[key]);
});
}
getScrollElement() {
if (this.scrollContainer) {
return this.scrollContainer.elementRef.nativeElement;
}
else {
return this.document.body;
}
}
getScrollPosition() {
if (this.scrollContainer) {
return {
top: this.scrollContainer.elementRef.nativeElement.scrollTop,
left: this.scrollContainer.elementRef.nativeElement.scrollLeft,
};
}
else {
return {
top: window.pageYOffset || this.document.documentElement.scrollTop,
left: window.pageXOffset || this.document.documentElement.scrollLeft,
};
}
}
shouldBeginDrag(event, touchMoveEvent, startScrollPosition) {
const moveScrollPosition = this.getScrollPosition();
const deltaScroll = {
top: Math.abs(moveScrollPosition.top - startScrollPosition.top),
left: Math.abs(moveScrollPosition.left - startScrollPosition.left),
};
const deltaX = Math.abs(touchMoveEvent.targetTouches[0].clientX - event.touches[0].clientX) - deltaScroll.left;
const deltaY = Math.abs(touchMoveEvent.targetTouches[0].clientY - event.touches[0].clientY) - deltaScroll.top;
const deltaTotal = deltaX + deltaY;
const longPressConfig = this.touchStartLongPress;
if (deltaTotal > longPressConfig.delta ||
deltaScroll.top > 0 ||
deltaScroll.left > 0) {
this.timeLongPress.timerBegin = Date.now();
}
this.timeLongPress.timerEnd = Date.now();
const duration = this.timeLongPress.timerEnd - this.timeLongPress.timerBegin;
if (duration >= longPressConfig.delay) {
this.disableScroll();
return true;
}
return false;
}
enableScroll() {
if (this.scrollContainer) {
this.renderer.setStyle(this.scrollContainer.elementRef.nativeElement, 'overflow', '');
}
this.renderer.setStyle(this.document.body, 'overflow', '');
}
disableScroll() {
/* istanbul ignore next */
if (this.scrollContainer) {
this.renderer.setStyle(this.scrollContainer.elementRef.nativeElement, 'overflow', 'hidden');
}
this.renderer.setStyle(this.document.body, 'overflow', 'hidden');
}
hasScrollbar() {
const scrollContainer = this.getScrollElement();
const containerHasHorizontalScroll = scrollContainer.scrollWidth > scrollContainer.clientWidth;
const containerHasVerticalScroll = scrollContainer.scrollHeight > scrollContainer.clientHeight;
return containerHasHorizontalScroll || containerHasVerticalScroll;
}
}
DraggableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DraggableDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: DraggableHelper }, { token: i0.NgZone }, { token: i0.ViewContainerRef }, { token: DraggableScrollContainerDirective, optional: true }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
DraggableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.3", type: DraggableDirective, selector: "[mwlDraggable]", inputs: { dropData: "dropData", dragAxis: "dragAxis", dragSnapGrid: "dragSnapGrid", ghostDragEnabled: "ghostDragEnabled", showOriginalElementWhileDragging: "showOriginalElementWhileDragging", validateDrag: "validateDrag", dragCursor: "dragCursor", dragActiveClass: "dragActiveClass", ghostElementAppendTo: "ghostElementAppendTo", ghostElementTemplate: "ghostElementTemplate", touchStartLongPress: "touchStartLongPress", autoScroll: "autoScroll" }, outputs: { dragPointerDown: "dragPointerDown", dragStart: "dragStart", ghostElementCreated: "ghostElementCreated", dragging: "dragging", dragEnd: "dragEnd" }, usesOnChanges: true, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DraggableDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlDraggable]',
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: DraggableHelper }, { type: i0.NgZone }, { type: i0.ViewContainerRef }, { type: DraggableScrollContainerDirective, decorators: [{
type: Optional
}] }, { type: undefined, decorators: [{
type: Inject,
args: [DOCUMENT]
}] }]; }, propDecorators: { dropData: [{
type: Input
}], dragAxis: [{
type: Input
}], dragSnapGrid: [{
type: Input
}], ghostDragEnabled: [{
type: Input
}], showOriginalElementWhileDragging: [{
type: Input
}], validateDrag: [{
type: Input
}], dragCursor: [{
type: Input
}], dragActiveClass: [{
type: Input
}], ghostElementAppendTo: [{
type: Input
}], ghostElementTemplate: [{
type: Input
}], touchStartLongPress: [{
type: Input
}], autoScroll: [{
type: Input
}], dragPointerDown: [{
type: Output
}], dragStart: [{
type: Output
}], ghostElementCreated: [{
type: Output
}], dragging: [{
type: Output
}], dragEnd: [{
type: Output
}] } });
function isCoordinateWithinRectangle(clientX, clientY, rect) {
return (clientX >= rect.left &&
clientX <= rect.right &&
clientY >= rect.top &&
clientY <= rect.bottom);
}
class DroppableDirective {
constructor(element, draggableHelper, zone, renderer, scrollContainer) {
this.element = element;
this.draggableHelper = draggableHelper;
this.zone = zone;
this.renderer = renderer;
this.scrollContainer = scrollContainer;
/**
* Called when a draggable element starts overlapping the element
*/
this.dragEnter = new EventEmitter();
/**
* Called when a draggable element stops overlapping the element
*/
this.dragLeave = new EventEmitter();
/**
* Called when a draggable element is moved over the element
*/
this.dragOver = new EventEmitter();
/**
* Called when a draggable element is dropped on this element
*/
this.drop = new EventEmitter(); // eslint-disable-line @angular-eslint/no-output-native
}
ngOnInit() {
this.currentDragSubscription = this.draggableHelper.currentDrag.subscribe((drag$) => {
addClass(this.renderer, this.element, this.dragActiveClass);
const droppableElement = {
updateCache: true,
};
const deregisterScrollListener = this.renderer.listen(this.scrollContainer
? this.scrollContainer.elementRef.nativeElement
: 'window', 'scroll', () => {
droppableElement.updateCache = true;
});
let currentDragEvent;
const overlaps$ = drag$.pipe(map(({ clientX, clientY, dropData, target }) => {
currentDragEvent = { clientX, clientY, dropData, target };
if (droppableElement.updateCache) {
droppableElement.rect =
this.element.nativeElement.getBoundingClientRect();
if (this.scrollContainer) {
droppableElement.scrollContainerRect =
this.scrollContainer.elementRef.nativeElement.getBoundingClientRect();
}
droppableElement.updateCache = false;
}
const isWithinElement = isCoordinateWithinRectangle(clientX, clientY, droppableElement.rect);
const isDropAllowed = !this.validateDrop ||
this.validateDrop({ clientX, clientY, target, dropData });
if (droppableElement.scrollContainerRect) {
return (isWithinElement &&
isDropAllowed &&
isCoordinateWithinRectangle(clientX, clientY, droppableElement.scrollContainerRect));
}
else {
return isWithinElement && isDropAllowed;
}
}));
const overlapsChanged$ = overlaps$.pipe(distinctUntilChanged());
let dragOverActive; // TODO - see if there's a way of doing this via rxjs
overlapsChanged$
.pipe(filter((overlapsNow) => overlapsNow))
.subscribe(() => {
dragOverActive = true;
addClass(this.renderer, this.element, this.dragOverClass);
if (this.dragEnter.observers.length > 0) {
this.zone.run(() => {
this.dragEnter.next(currentDragEvent);
});
}
});
overlaps$.pipe(filter((overlapsNow) => overlapsNow)).subscribe(() => {
if (this.dragOver.observers.length > 0) {
this.zone.run(() => {
this.dragOver.next(currentDragEvent);
});
}
});
overlapsChanged$
.pipe(pairwise(), filter(([didOverlap, overlapsNow]) => didOverlap && !overlapsNow))
.subscribe(() => {
dragOverActive = false;
removeClass(this.renderer, this.element, this.dragOverClass);
if (this.dragLeave.observers.length > 0) {
this.zone.run(() => {
this.dragLeave.next(currentDragEvent);
});
}
});
drag$.subscribe({
complete: () => {
deregisterScrollListener();
removeClass(this.renderer, this.element, this.dragActiveClass);
if (dragOverActive) {
removeClass(this.renderer, this.element, this.dragOverClass);
if (this.drop.observers.length > 0) {
this.zone.run(() => {
this.drop.next(currentDragEvent);
});
}
}
},
});
});
}
ngOnDestroy() {
if (this.currentDragSubscription) {
this.currentDragSubscription.unsubscribe();
}
}
}
DroppableDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DroppableDirective, deps: [{ token: i0.ElementRef }, { token: DraggableHelper }, { token: i0.NgZone }, { token: i0.Renderer2 }, { token: DraggableScrollContainerDirective, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
DroppableDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.0.3", type: DroppableDirective, selector: "[mwlDroppable]", inputs: { dragOverClass: "dragOverClass", dragActiveClass: "dragActiveClass", validateDrop: "validateDrop" }, outputs: { dragEnter: "dragEnter", dragLeave: "dragLeave", dragOver: "dragOver", drop: "drop" }, ngImport: i0 });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DroppableDirective, decorators: [{
type: Directive,
args: [{
selector: '[mwlDroppable]',
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: DraggableHelper }, { type: i0.NgZone }, { type: i0.Renderer2 }, { type: DraggableScrollContainerDirective, decorators: [{
type: Optional
}] }]; }, propDecorators: { dragOverClass: [{
type: Input
}], dragActiveClass: [{
type: Input
}], validateDrop: [{
type: Input
}], dragEnter: [{
type: Output
}], dragLeave: [{
type: Output
}], dragOver: [{
type: Output
}], drop: [{
type: Output
}] } });
class DragAndDropModule {
}
DragAndDropModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DragAndDropModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
DragAndDropModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.0.3", ngImport: i0, type: DragAndDropModule, declarations: [DraggableDirective,
DroppableDirective,
DraggableScrollContainerDirective], exports: [DraggableDirective,
DroppableDirective,
DraggableScrollContainerDirective] });
DragAndDropModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DragAndDropModule });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.0.3", ngImport: i0, type: DragAndDropModule, decorators: [{
type: NgModule,
args: [{
declarations: [
DraggableDirective,
DroppableDirective,
DraggableScrollContainerDirective,
],
exports: [
DraggableDirective,
DroppableDirective,
DraggableScrollContainerDirective,
],
}]
}] });
/*
* Public API Surface of angular-draggable-droppable
*/
/**
* Generated bundle index. Do not edit.
*/
export { DragAndDropModule, DraggableDirective, DraggableScrollContainerDirective, DroppableDirective };
//# sourceMappingURL=angular-draggable-droppable.mjs.map
//# sourceMappingURL=angular-draggable-droppable.mjs.map