Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dragging behavior after scrolling when scroll is locked due to a change in container visibility #773

Merged
merged 6 commits into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions packages/dflex-dnd/src/Mechanism/DFlexMechanismController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,20 @@ class DFlexMechanismController extends DFlexScrollableElement {
}
}

private _postScrollDragHandler(SK: string, x: number, y: number): void {
const isOutSiblingsContainer = this.draggable.isOutThreshold(SK);

if (!isOutSiblingsContainer && this.isParentLocked) {
const [scrollOffsetX, scrollOffsetY] = this._calculateScrollOffsets(SK);

// Update the position before calling the detector.
this.draggable.positions.setPos(x, y, scrollOffsetX, scrollOffsetY);
this._detectNearestElm();
}

this.hasBeenScrolling = false;
}

private _calculateScrollOffsets(SK: string): [number, number] {
const {
totalScrollRect: { left, top },
Expand Down Expand Up @@ -885,6 +899,12 @@ class DFlexMechanismController extends DFlexScrollableElement {

// If rect is entirely visible, do nothing.
if (isInside) {
if (this.hasBeenScrolling) {
this._postScrollDragHandler(SK, x, y);

return true;
}

return false;
}

Expand All @@ -911,18 +931,7 @@ class DFlexMechanismController extends DFlexScrollableElement {
}

if (this.hasBeenScrolling) {
isOutSiblingsContainer = this.draggable.isOutThreshold(SK);

if (!isOutSiblingsContainer && this.isParentLocked) {
const [scrollOffsetX, scrollOffsetY] = this._calculateScrollOffsets(SK);

// Update the position before calling the detector.
this.draggable.positions.setPos(x, y, scrollOffsetX, scrollOffsetY);

this._detectNearestElm();
}

this.hasBeenScrolling = false;
this._postScrollDragHandler(SK, x, y);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const ScrollablePage = () => {
return (
<div className="root">
<div className="todo">
<ul style={{ marginTop: "400px" }}>
<ul style={{ marginTop: "400px", marginBottom: "200px" }}>
{Array.from({ length: 4 }).map((_, i) => (
<DFlexDnDComponent
Component={"li"}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
Page,
Locator,
BrowserContext,
Browser,
expect,
} from "@playwright/test";

import {
DFlexPageTest as test,
// assertChildrenOrderIDs,
// assertDefaultChildrenIndex,
getDraggedRect,
initialize,
moveDragged,
} from "dflex-e2e-utils";

test.describe("The container is scrollable only when it's not visible", async () => {
let page: Page;
let context: BrowserContext;
let activeBrowser: Browser;

let elementSelectors: string[];
let elements: Locator[];

let scrollTop = 0;

test.beforeAll(async ({ browser, browserName }) => {
activeBrowser = browser;

context = await activeBrowser.newContext();
page = await context.newPage();
initialize(page, browserName, 100);
await page.goto("/scrollable-page");

elementSelectors = Array.from(
{ length: 4 },
(_, index) => `[id='id_${index}']`,
);

elements = await Promise.all(
elementSelectors.map((selector) => page.locator(selector)),
);
});

test.afterAll(async () => {
await page.close();
await context.close();
// await activeBrowser.close();
});

test("Move elm1 outside the container then scroll to the end", async () => {
await getDraggedRect(elements[0]);
await moveDragged(-270, -1);
await moveDragged(-1, 200);
await page.waitForFunction(
() => {
({ scrollTop } = document.documentElement);

return scrollTop >= 200;
},
{ timeout: 3000 },
);

await moveDragged(-1, -25);
});

test("the page is scrolled by the dragged", async () => {
scrollTop = await page.evaluate(() => document.documentElement.scrollTop);

expect(scrollTop).toBeGreaterThan(100);
});

test("insert drag into the bottom of the container", async () => {
await moveDragged(0, -1);

await page.dispatchEvent(elementSelectors[0], "mouseup", {
button: 0,
force: true,
});
});

test("Siblings transformed their positions", async () => {
await Promise.all([
expect(elements[0]).not.toHaveCSS("transform", "none"),
expect(elements[1]).not.toHaveCSS("transform", "none"),
expect(elements[2]).not.toHaveCSS("transform", "none"),
expect(elements[3]).not.toHaveCSS("transform", "none"),
]);
});

test("get the current top scroll value", async () => {
scrollTop = await page.evaluate(() => document.documentElement.scrollTop);
});

test("Move elm2 which is located first outside the container then scroll to the top", async () => {
await getDraggedRect(elements[1]);
await moveDragged(-270, -1);
await moveDragged(-1, -200);

await page.waitForTimeout(2000);
});

test("the page hasn't scrolled because container is visible", async () => {
const currentScrollTop = await page.evaluate(
() => document.documentElement.scrollTop,
);

expect(currentScrollTop).toBe(scrollTop);
});
});
Loading