diff --git a/dev/pages/the-hero.vue b/dev/pages/the-hero.vue new file mode 100644 index 0000000..cd1b0f8 --- /dev/null +++ b/dev/pages/the-hero.vue @@ -0,0 +1,171 @@ + + + diff --git a/docs/examples/config/config.ts b/docs/examples/config/config.ts index 57d3959..75e18f4 100644 --- a/docs/examples/config/config.ts +++ b/docs/examples/config/config.ts @@ -132,6 +132,20 @@ export interface ParentConfig { * Function that is called when a node is set up. */ setupNode: SetupNode; + /** + * Configuration for scrolling behavior. + * + * If a parent of the dragged element is scrollable, the parent will scroll on its x and y axis. + * + * I.e. Setting x: 0.9 will begin scrolling the parent when the dragged element is 90% of the way dragged to the left or the right of the scrollable container. + * + * Scroll Outside determines whether or not the parent will scroll when the dragged element is outside of the parent. + */ + scrollBehavior: { + x: number; + y: number; + scrollOutside?: boolean; + }; /** * Flag for whether or not to allow sorting within a given parent. */ diff --git a/playwright.config.ts b/playwright.config.ts index 911f282..f88d145 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -21,38 +21,38 @@ export default defineConfig({ ...devices["Desktop Chrome"], }, }, - { - name: "Desktop Firefox Drag Tests", - testMatch: "tests/drag/**/*.spec.ts", - use: { - ...devices["Desktop Firefox"], - }, - }, - { - name: "Mobile Chrome Touch Tests", - testMatch: "tests/touch/**/*.spec.ts", - use: { - ...devices["Mobile Chrome"], - }, - }, - { - name: "Mobile Safari Touch Tests", - testMatch: "tests/touch/**/*.spec.ts", - use: { - ...devices["Mobile Safari"], - }, - }, - { - name: "Mobile Firefox Touch Tests", - testMatch: "tests/touch/**/*.spec.ts", - use: { - ...devices["Mobile Firefox"], - }, - }, - { - name: "Framework Tests", - testMatch: "tests-frameworks/**/*.spec.ts", - use: { ...devices["Desktop Chrome"] }, - }, + // { + // name: "Desktop Firefox Drag Tests", + // testMatch: "tests/drag/**/*.spec.ts", + // use: { + // ...devices["Desktop Firefox"], + // }, + // }, + // { + // name: "Mobile Chrome Touch Tests", + // testMatch: "tests/touch/**/*.spec.ts", + // use: { + // ...devices["Mobile Chrome"], + // }, + // }, + // { + // name: "Mobile Safari Touch Tests", + // testMatch: "tests/touch/**/*.spec.ts", + // use: { + // ...devices["Mobile Safari"], + // }, + // }, + // { + // name: "Mobile Firefox Touch Tests", + // testMatch: "tests/touch/**/*.spec.ts", + // use: { + // ...devices["Mobile Firefox"], + // }, + // }, + // { + // name: "Framework Tests", + // testMatch: "tests-frameworks/**/*.spec.ts", + // use: { ...devices["Desktop Chrome"] }, + // }, ], }); diff --git a/playwright/tests/drag/sort.spec.ts b/playwright/tests/drag/sort.spec.ts index 1d520b3..f23c6b4 100644 --- a/playwright/tests/drag/sort.spec.ts +++ b/playwright/tests/drag/sort.spec.ts @@ -9,28 +9,25 @@ test.beforeAll(async ({ browser }) => { }); test.describe("Sorting", async () => { - test("Drag sort works as expected.", async () => { + test.only("Drag sort works as expected.", async () => { await dragDrop(page, { - origin: "#Apple", - destination: "#Banana", + originEl: { id: "Apple", position: "center" }, + destinationEl: { id: "Banana", position: "center" }, dragStart: true, - drop: false, }); await expect(page.locator("#sort_values")).toHaveText( "Banana Apple Orange" ); await dragDrop(page, { - origin: "#Banana", - destination: "#Orange", - dragStart: false, - drop: true, + originEl: { id: "Banana", position: "center" }, + destinationEl: { id: "Orange", position: "center" }, }); await expect(page.locator("#sort_values")).toHaveText( "Banana Orange Apple" ); await dragDrop(page, { - origin: "#Banana", - destination: "#Orange", + originEl: { id: "Banana", position: "center" }, + destinationEl: { id: "Orange", position: "center" }, dragStart: true, drop: false, }); @@ -38,10 +35,8 @@ test.describe("Sorting", async () => { "Orange Banana Apple" ); await dragDrop(page, { - origin: "#Banana", - destination: "#Apple", - dragStart: false, - drop: true, + originEl: { id: "Banana", position: "center" }, + destinationEl: { id: "Apple", position: "center" }, }); await expect(page.locator("#sort_values")).toHaveText( "Orange Apple Banana" diff --git a/playwright/utils.ts b/playwright/utils.ts index 53d2be4..8d12aba 100644 --- a/playwright/utils.ts +++ b/playwright/utils.ts @@ -1,101 +1,70 @@ import type { Page } from "@playwright/test"; -export async function dragDrop( - page: Page, - { - origin, - destination, - dragStart, - drop, - dragleave, - }: { - origin?: string; - destination?: string; - dragStart?: boolean; - drop?: boolean; - dragleave?: boolean; - } -): Promise { - let originElement = origin && (await page.waitForSelector(origin)); - - if (!originElement) originElement = undefined; - - let destinationElement = - destination && (await page.waitForSelector(destination)); - - if (!destinationElement) destinationElement = undefined; - - return page.evaluate( - async ({ - originElement, - destinationElement, - dragStart, - drop, - }: { - originElement?: Element | undefined; - destinationElement?: Element | undefined; - dragStart?: boolean; - drop?: boolean; - dragleave?: boolean; - }) => { - const dataTransfer = new DataTransfer(); - - const getPayload = (element: Element) => { - const rect = element.getBoundingClientRect(); - - const [x, y] = [rect.x + rect.width / 2, rect.y + rect.height / 2]; - return { - bubbles: true, - cancelable: true, - clientX: x, - clientY: y, - dataTransfer, - screenX: x, - screenY: y, - }; - }; +interface El { + id: string; + position: string; +} - let originPayload; +interface DragDropData { + originEl: El; + destinationEl: El; + dragStart?: boolean; + drop?: boolean; +} - let destinationPayload; +/** + * Utility function used to simulate drag and drop events. + * + * @param page + * @param param1 + */ +export async function dragDrop(page: Page, data: DragDropData): Promise { + await new Promise((resolve) => setTimeout(resolve, 100)); + return page.evaluate(async (data) => { + const originElement = document.getElementById(data.originEl.id); - if (originElement) originPayload = getPayload(originElement); + const destinationElement = document.getElementById(data.destinationEl.id); - if (destinationElement) - destinationPayload = getPayload(destinationElement); + if (!originElement || !destinationElement) return; - if (dragStart && originElement) { - originElement.dispatchEvent( - new DragEvent("pointerdown", originPayload) - ); + const dataTransfer = new DataTransfer(); - originElement.dispatchEvent(new DragEvent("dragstart", originPayload)); - } + const getEventProps = (element: Element) => { + const rect = element.getBoundingClientRect(); - if (originElement) { - originElement.dispatchEvent(new DragEvent("dragover", originPayload)); - } + const [x, y] = [rect.x + rect.width / 2, rect.y + rect.height / 2]; - if (destinationElement) { - destinationElement.dispatchEvent( - new DragEvent("dragover", destinationPayload) - ); - } - - if (drop) { - if (destinationElement) { - destinationElement.dispatchEvent( - new DragEvent("dragover", destinationPayload) - ); - destinationElement.dispatchEvent( - new DragEvent("drop", destinationPayload) - ); - } - } - }, - - { originElement, destinationElement, dragStart, drop, dragleave } - ); + return { + bubbles: true, + cancelable: true, + clientX: x, + clientY: y, + dataTransfer, + screenX: x, + screenY: y, + }; + }; + + if (data.dragStart) { + originElement.dispatchEvent( + new DragEvent("dragstart", getEventProps(originElement)) + ); + } + + originElement.dispatchEvent( + new DragEvent("dragover", getEventProps(originElement)) + ); + + destinationElement.dispatchEvent( + new DragEvent("dragover", getEventProps(destinationElement)) + ); + + if (data.drop) { + destinationElement.dispatchEvent( + new DragEvent("drop", getEventProps(destinationElement)) + ); + } + }, data); } export async function touchDrop( @@ -159,6 +128,8 @@ export async function touchDrop( }); } + if (!destinationElement) return; + const touchMoveObj = new Touch({ identifier: 0, target: destinationElement, diff --git a/src/index.ts b/src/index.ts index fb3833f..7110ecb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,6 +22,7 @@ import type { NodeDragEventData, NodeTouchEventData, NodeRecord, + ScrollData, } from "./types"; import { isBrowser, @@ -543,6 +544,7 @@ function touchstart(data: NodeTouchEventData) { } export function dragstart(data: NodeDragEventData) { + console.log("DRAGSTART"); if (!validateDragHandle(data)) { data.e.preventDefault(); @@ -844,18 +846,6 @@ function shouldScroll( } } -interface ScrollData { - state: DragState | TouchState; - xThresh: number; - yThresh: number; - scrollParent: HTMLElement; - scrollOutside?: boolean; - x: number; - y: number; - width: number; - height: number; -} - function shouldScrollRight( state: TouchState | DragState, data: ScrollData @@ -1010,6 +1000,7 @@ function performScroll(direction: string, x: number, y: number) { } export function handleDragoverNode(data: NodeDragEventData) { + console.log("DRAGOVER NODE"); if (!state) return; const { x, y } = eventCoordinates(data.e); diff --git a/src/types.ts b/src/types.ts index c24b81c..04b8b1e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -651,3 +651,15 @@ export interface TouchStateProps { touchMoving: boolean; scrollParent: HTMLElement; } + +export interface ScrollData { + state: DragState | TouchState; + xThresh: number; + yThresh: number; + scrollParent: HTMLElement; + scrollOutside?: boolean; + x: number; + y: number; + width: number; + height: number; +}