diff --git a/doc/API.md b/doc/API.md index a768851d1..62d46004f 100644 --- a/doc/API.md +++ b/doc/API.md @@ -4288,7 +4288,7 @@ Subclasses should override to perform additional cleanup. drop(e): void; ``` -Defined in: [dd-droppable.ts:143](https://github.com/adumesny/gridstack.js/blob/master/src/dd-droppable.ts#L143) +Defined in: [dd-droppable.ts:146](https://github.com/adumesny/gridstack.js/blob/master/src/dd-droppable.ts#L146) item is being dropped on us - called by the drag mouseup handler - this calls the client drop event diff --git a/src/dd-draggable.ts b/src/dd-draggable.ts index 8db34274b..1cf2bcf2f 100644 --- a/src/dd-draggable.ts +++ b/src/dd-draggable.ts @@ -410,7 +410,7 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt /** @internal starts or continues auto-scroll when the dragged helper is clipped by the scroll container. * Takes the grid's own element to find the scroll container so external/sidebar drags work too (#2074). */ public updateScrollPosition(gridEl: HTMLElement): void { - this._autoScrollContainer ??= Utils.getScrollElement(gridEl); + this._autoScrollContainer = Utils.getScrollElement(gridEl); // always use latest active grid const clipping = this._getClipping(this.helper, this._autoScrollContainer); if (clipping === 0) { this._stopScrolling(); @@ -419,11 +419,12 @@ export class DDDraggable extends DDBaseImplement implements HTMLElementExtendOpt } } - /** @internal compute how many pixels the element is clipped: negative = above, positive = below, 0 = fully visible */ + /** @internal compute how many pixels the element is clipped: negative = above, positive = below, 0 = fully inside OR outside (stop scrolling) */ protected _getClipping(el: HTMLElement, scrollEl: HTMLElement): number { const elRect = el.getBoundingClientRect(); const scrollRect = scrollEl.getBoundingClientRect(); const viewportH = window.innerHeight || document.documentElement.clientHeight; + if (elRect.bottom < scrollRect.top || elRect.top > scrollRect.bottom) return 0; // fully outside const clippedBelow = elRect.bottom - Math.min(scrollRect.bottom, viewportH); const clippedAbove = elRect.top - Math.max(scrollRect.top, 0); if (clippedAbove < 0) return clippedAbove; diff --git a/src/dd-droppable.ts b/src/dd-droppable.ts index 8a65b0620..e6c2987e7 100644 --- a/src/dd-droppable.ts +++ b/src/dd-droppable.ts @@ -82,7 +82,7 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt /** @internal called when the cursor enters our area - prepare for a possible drop and track leaving */ protected _mouseEnter(e: MouseEvent): void { - // console.log(`${count++} Enter ${this.el.id || (this.el as GridHTMLElement).gridstack.opts.id}`); // TEST + // console.log(`${count++} Enter ${this.el.id}`); // TEST if (!DDManager.dragElement) return; // During touch drag operations, ignore real browser-generated mouseenter events (isTrusted:true) vs our simulated ones (isTrusted:false). // The browser can fire spurious mouseenter events when we dispatch simulated mousemove events. @@ -91,6 +91,7 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt if (!this._canDrop(DDManager.dragElement.el)) return; e.preventDefault(); e.stopPropagation(); + DDManager.dragElement._stopScrolling(); // make sure when we enter this, that the last one gets a leave FIRST to correctly cleanup as we don't always do if (DDManager.dropElement && DDManager.dropElement !== this) { @@ -109,10 +110,12 @@ export class DDDroppable extends DDBaseImplement implements HTMLElementExtendOpt /** @internal called when the item is leaving our area, stop tracking if we had moving item */ protected _mouseLeave(e: MouseEvent, calledByEnter = false): void { - // console.log(`${count++} Leave ${this.el.id || (this.el as GridHTMLElement).gridstack.opts.id}`); // TEST + // console.log(`${count++} Leave ${this.el.id}`); // TEST if (!DDManager.dragElement || DDManager.dropElement !== this) return; e.preventDefault(); e.stopPropagation(); + // stop the old grid's auto-scroll only when entering a new grid; if leaving to empty space keep scrolling until mouseup + if (calledByEnter) DDManager.dragElement._stopScrolling(); const ev = Utils.initEvent(e, { target: this.el, type: 'dropout' }); if (this.option.out) { diff --git a/src/utils.ts b/src/utils.ts index e5e0f3f21..a5bab118b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -573,7 +573,7 @@ export class Utils { static getScrollElement(el?: HTMLElement): HTMLElement { if (!el) return document.scrollingElement as HTMLElement || document.documentElement; // IE support const overflowY = getComputedStyle(el).overflowY; - if (overflowY === 'auto' || overflowY === 'scroll') { + if ((overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight) { return el; } else { return Utils.getScrollElement(el.parentElement);