diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..1d8a41914 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @jalal246 \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca66cd372..76def805a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -281,18 +281,183 @@ jobs: - name: Testing features for DnD with React APP - Chrome run: pnpm test-e2e-multi:chrome + e2e-linux: + runs-on: ubuntu-latest + timeout-minutes: 12 + if: github.event.pull_request.draft != true + strategy: + matrix: + node-version: [16.8] + browser: ["chromium", "firefox"] + env: + CI: true + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v2.0.1 + name: Install pnpm + id: pnpm-install + with: + version: ^7.0.0 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Build packages + run: "pnpm clean && pnpm -r emit && pnpm build --production --release --minify" + + - name: Build DnD React App + run: pnpm -F dflex-dnd-playground build + + - name: Install Playwright + run: pnpm dlx playwright install --with-deps + + - name: Test Playwright + run: pnpm run test-e2e-core-ci:${{ matrix.browser }} + + e2e-windows: + runs-on: windows-latest + timeout-minutes: 12 + if: github.event.pull_request.draft != true + strategy: + matrix: + node-version: [16.8] + browser: ["chromium", "firefox"] + env: + CI: true + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v2.0.1 + name: Install pnpm + id: pnpm-install + with: + version: ^7.0.0 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Build packages + run: "pnpm clean && pnpm -r emit && pnpm build --production --release --minify" + + - name: Build DnD React App + run: pnpm -F dflex-dnd-playground build + + - name: Install Playwright + run: pnpm dlx playwright install --with-deps + + - name: Test Playwright + run: pnpm run test-e2e-core-ci:${{ matrix.browser }} + + e2e-mac: + runs-on: macos-latest + timeout-minutes: 12 + if: github.event.pull_request.draft != true + strategy: + matrix: + node-version: [16.8] + browser: ["chromium", "firefox", "webkit"] + env: + CI: true + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + - uses: pnpm/action-setup@v2.0.1 + name: Install pnpm + id: pnpm-install + with: + version: ^7.0.0 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + + - name: Build packages + run: "pnpm clean && pnpm -r emit && pnpm build --production --release --minify" + + - name: Build DnD React App + run: pnpm -F dflex-dnd-playground build + + - name: Install Playwright + run: pnpm dlx playwright install --with-deps + + - name: Test Playwright + run: pnpm run test-e2e-core-ci:${{ matrix.browser }} + release: name: Publish to NPM if: ${{ github.ref_name == 'main' && github.repository_owner == 'dflex-js' }} runs-on: ubuntu-latest - needs: [ + needs: + [ lint, unit-test, types, install-build, e2e-same-container-vertical, - # e2e-same-container-horizontal, e2e-multi-containers, + e2e-mac, + e2e-windows, + e2e-linux, ] steps: - name: Check out repository diff --git a/docs/drag-drop/api.md b/docs/drag-drop/api.md index 38a8004e0..f545fb9bf 100644 --- a/docs/drag-drop/api.md +++ b/docs/drag-drop/api.md @@ -1,10 +1,8 @@ --- -title: Drag and Drop API -description: "DFlex drag and drop installation and API." +title: DFlex Drag and Drop API +description: "DFlex Drag and Drop API." --- -> A Simple, lightweight Solution for a Drag & Drop interactive App. - ## Installation ```bash @@ -13,7 +11,7 @@ npm install @dflex/dnd ## API -You can achieve a drag and drop with three steps only: +DFlex depends on three principles to achieve DOM interactivity: - Register element in the store. - Start dragging when mouse is down. @@ -25,29 +23,25 @@ import { store, DnD } from "@dflex/dnd"; ### Register element -Each element should be registered in DnD store in order to be active for Drag +Each element should be registered in DnD store in order to be active for drag and drop later. ```ts -store.register(RegisterInput); +store.register(RegisterInputOpts); ``` -Where `RegisterInput` is an object with the following properties: +Where `RegisterInputOpts` is an object with the following properties: -- `id?: string` is a unique identifier for an element in the registry. Duplicate - ids will cause confusion and prevent DnD from working properly. -- `parentID?: string` is the parent element id. If you have multiple lists in - the same layout you should provide the parent id so the registry can - distinguish between elements. -- `ref?: HTMLElement` targeted DOM element. Should be provided if you haven't - provided the id. -- `depth?: number` Element depth in tree. Start from bottom up. So the child is `0` - by default. Depth is necessary for nested elements. +- `id: string` Targeted element-id. +- `parentID: string` Parent element-id. Pass empty string if there's none. +- `depth?: number` The depth of targeted element starting from zero (The default value is zero). +- `readonly?: boolean` True for elements that won't be transformed during DnD + but belongs to the same interactive container. ### Create responsive DnD event -The responsive drag and drop event should be created when `onmousedown` is fired. So you -initialized the element and its siblings before start dragging. +The responsive drag and drop event should be created when `onmousedown` is +fired. So it can initialize the element and its siblings before start dragging. ```ts const dndEvent = new DnD(id, clickCoordinates, opts); @@ -56,7 +50,7 @@ const dndEvent = new DnD(id, clickCoordinates, opts); - `id: string` registered element-id in the store. - `clickCoordinates` is an object with `{x: number, y: number}` contains the coordinates of the mouse/touch click. -- `opts` is DnD options object. You can see [options full documentation by +- `opts?` is DnD options object. You can see [options full documentation by clicking here.](/docs/drag-drop/api/#options) ### Start responsive dragging @@ -87,7 +81,8 @@ store.unregister(id); ## Options -You can pass options when creating DnD event that controls each element individually. +You can pass options when creating DnD event that controls each element +individually. So your options can be different for each element. ### Dragging Threshold diff --git a/package.json b/package.json index c784abad3..425abb4a0 100644 --- a/package.json +++ b/package.json @@ -11,17 +11,26 @@ "author": "Jalal Maskoun", "scripts": { "start": "cross-env NODE_ENV=development pnpm -F dflex-dnd-playground dev", - "start:draggable-only": "cross-env NODE_ENV=development pnpm -F dflex-draggable-playground dev", - "dev-cypress": "cross-env NODE_ENV=development && pnpm start-server-and-test 'pnpm run start' http-get://localhost:3001 'cypress open --env extended=true --project packages/dflex-dnd-playground'", + "serve:dnd": "pnpm -F dflex-dnd-playground preview", + "build-app": "pnpm -F dflex-dnd-playground build", + "start:cy": "cross-env NODE_ENV=development && pnpm start-server-and-test 'pnpm run start' http-get://localhost:3001 'cypress open --env extended=true --project packages/dflex-dnd-playground'", "cy:run:vertical:chrome": "cypress run --env extended=true --project packages/dflex-dnd-playground --headless --spec 'packages/dflex-dnd-playground/cypress/e2e/same-container-vertical/**/*.cy.ts' --config-file cypress.config.ts --browser chrome", "cy:run:multi:chrome": "cypress run --project packages/dflex-dnd-playground --headless --spec 'packages/dflex-dnd-playground/cypress/e2e/multiple-containers/**/*.cy.ts' --config-file cypress.config.ts --browser chrome", "test-e2e-vertical:chrome": "start-server-and-test 'pnpm -F dflex-dnd-playground dev' http-get://localhost:3001 'pnpm cy:run:vertical:chrome'", "test-e2e-multi:chrome": "start-server-and-test 'pnpm -F dflex-dnd-playground preview' http-get://localhost:3001 'pnpm cy:run:multi:chrome'", "test-e2e-all": "pnpm build && pnpm -F dflex-dnd-playground build:app && start-server-and-test 'pnpm -F dflex-dnd-playground preview' http-get://localhost:3001 'cypress run --env extended=true --project packages/dflex-dnd-playground'", "test-unit": "jest", + "test-e2e-core:chromium": "playwright test --project=\"chromium\"", + "test-e2e-core:firefox": "playwright test --project=\"firefox\"", + "test-e2e-core:webkit": "playwright test --project=\"webkit\"", + "test-e2e-core-ci:chromium": "start-server-and-test serve:dnd 3001 test-e2e-core:chromium", + "test-e2e-core-ci:firefox": "start-server-and-test serve:dnd 3001 test-e2e-core:firefox", + "test-e2e-core-ci:webkit": "start-server-and-test serve:dnd 3001 test-e2e-core:webkit", + "debug-test-e2e:chromium": "playwright test --debug --project=\"chromium\"", + "debug-test-e2e:firefox": "playwright test --debug --project=\"firefox\"", + "debug-test-e2e:webkit": "playwright test --debug --project=\"webkit\"", "clean": "pnpm -r --parallel clean", "build": "node scripts/build/index.js", - "build-app": "pnpm -F dflex-dnd-playground build", "build-prod": "pnpm clean && pnpm -r emit && pnpm build -- --production --release --minify", "check-types": "tsc --noEmit", "emit-types": "pnpm -r emit", @@ -30,16 +39,14 @@ "update-version": "pnpm changeset version && pnpm install" }, "devDependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "react-router-dom": "^6.3.0", + "@changesets/cli": "^2.22.0", + "@playwright/test": "^1.22.2", + "@types/jest": "^28.1.0", + "@types/node": "^17.0.39", "@types/react": "^18.0.10", "@types/react-dom": "^18.0.5", "@types/react-router-dom": "^5.3.3", - "@types/jest": "^28.1.0", - "@types/node": "^17.0.39", - "ts-jest": "^28.0.4", - "@changesets/cli": "^2.22.0", + "@vitejs/plugin-react": "^1.3.2", "cross-env": "^7.0.3", "cypress": "^10.0.2", "eslint-config-dflex": "workspace:*", @@ -47,12 +54,15 @@ "jest": "^28.1.0", "jest-environment-jsdom": "^28.1.0", "prettier": "^2.6.2", + "react": "^18.1.0", + "react-dom": "^18.1.0", + "react-router-dom": "^6.3.0", "rimraf": "^3.0.2", "start-server-and-test": "^1.14.0", + "ts-jest": "^28.0.4", "ts-node": "^10.8.1", "typescript": "^4.7.3", - "@vitejs/plugin-react": "^1.3.2", - "vite-plugin-replace": "^0.1.1", - "vite": "^2.9.9" + "vite": "^2.9.9", + "vite-plugin-replace": "^0.1.1" } } diff --git a/packages/dflex-dnd-playground/cypress/e2e/same-container-vertical/essential/outPosition/horizontally.outPoistion.cy.ts b/packages/dflex-dnd-playground/cypress/e2e/same-container-vertical/essential/outPosition/horizontally.outPoistion.cy.ts deleted file mode 100644 index f718c11bd..000000000 --- a/packages/dflex-dnd-playground/cypress/e2e/same-container-vertical/essential/outPosition/horizontally.outPoistion.cy.ts +++ /dev/null @@ -1,483 +0,0 @@ -context("DnD/Testing is out position horizontally", () => { - const URLs = [ - { - url: "http://localhost:3001/", - desc: "Testing Container Based Event", - }, - ]; - - if (Cypress.env("extended")) { - URLs.push({ - url: "http://localhost:3001/component-based-event", - desc: "Testing Component Based Event", - }); - } - - function myContext() { - let startingPointX: number; - let startingPointY: number; - let elmBox: DOMRect; - - context("Moving strict horizontally - out form the right", () => { - it("Transforms (container3 |> elm-2) out", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX + ((2 / 3) * elmBox.width + 2), - clientY: startingPointY, - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Effects (container3 |> elm-4), lifts it up", () => { - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Resets all positions", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - }); - }); - - context("Moving strict horizontally - out form the left", () => { - it("Transforms (container3 |> elm-2) out", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX - ((2 / 3) * elmBox.width + 2), - clientY: startingPointY, - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Effects (container3 |> elm-4), lifts it up", () => { - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Resets all positions", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - }); - }); - - context("Moving horizontally & slightly down - out form the right", () => { - it("Transforms (container3 |> elm-2) out", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX + ((2 / 3) * elmBox.width + 2), - clientY: startingPointY + 10, - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Effects (container3 |> elm-4), lifts it up", () => { - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Resets all positions", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - }); - }); - - context("Moving horizontally & slightly down - out form the left", () => { - it("Transforms (container3 |> elm-2) out", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX - ((2 / 3) * elmBox.width + 2), - clientY: startingPointY + 10, - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Effects (container3 |> elm-4), lifts it up", () => { - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Resets all positions", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - }); - }); - - context("Moving horizontally & slightly up - out form the right", () => { - it("Transforms (container3 |> elm-2) out", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX + ((2 / 3) * elmBox.width + 2), - clientY: startingPointY - 10, - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Effects (container3 |> elm-4), lifts it up", () => { - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Resets all positions", () => { - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - }); - }); - - context("Moving horizontally & slightly up - out form the left", () => { - it("Transforms (container3 |> elm-2) out", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX - ((2 / 3) * elmBox.width + 2), - clientY: startingPointY - 10, - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Effects (container3 |> elm-4), lifts it up", () => { - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Resets all positions", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - }); - }); - } - - URLs.forEach(({ url, desc }) => { - context(desc, () => { - before(() => { - cy.visit(url); - }); - - myContext(); - }); - }); -}); diff --git a/packages/dflex-dnd-playground/cypress/e2e/same-container-vertical/essential/outPosition/vertically.outPoistion.cy.ts b/packages/dflex-dnd-playground/cypress/e2e/same-container-vertical/essential/outPosition/vertically.outPoistion.cy.ts deleted file mode 100644 index 04e70a572..000000000 --- a/packages/dflex-dnd-playground/cypress/e2e/same-container-vertical/essential/outPosition/vertically.outPoistion.cy.ts +++ /dev/null @@ -1,349 +0,0 @@ -context("DnD/Testing is out position vertically", () => { - const URLs = [ - { - url: "http://localhost:3001/", - desc: "Testing Container Based Event", - }, - ]; - - if (Cypress.env("extended")) { - URLs.push({ - url: "http://localhost:3001/component-based-event", - desc: "Testing Component Based Event", - }); - } - - function myContext() { - let startingPointX: number; - let startingPointY: number; - let elmBox: DOMRect; - - context("Moving strict vertically one siblings - out down", () => { - it("Transforms (container3 |> elm-2) out vertically", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX, - clientY: startingPointY + ((2 / 3) * elmBox.height + 2), - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Does not effect (container3 |> elm-4)", () => { - cy.get("#id-12").should("have.css", "transform", "none"); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Dragged takes new position switching the other element", () => { - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 58)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("ELement not involved are not effected", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - cy.get("#id-12").should("have.css", "transform", "none"); - }); - }); - - context("Moving strict vertically one siblings - out up", () => { - it("Transforms (container3 |> elm-2) out up vertically", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX, - clientY: startingPointY - ((2 / 3) * elmBox.height + 2), - force: true, - }); - }); - }); - - it("Effects (container3 |> elm-3), moves it down", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - }); - - it("Does not effect elements 9 and 12", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - cy.get("#id-12").should("have.css", "transform", "none"); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Effected elements are switched again", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-12").should("have.css", "transform", "none"); - }); - }); - - context("Moving strict vertically multi siblings - out down", () => { - it("Transforms (container3 |> elm-2) out down multi steps", () => { - cy.get("#id-10").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - - cy.get("#id-10") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX, - clientY: startingPointY + ((2 / 3) * elmBox.height + 2), - force: true, - }) - .trigger("mousemove", { - clientX: startingPointX, - clientY: - startingPointY + (2 * elmBox.height + (1 / 3) * elmBox.height), - force: true, - }); - }); - }); - - it("Does not effect (container3 |> elm-1)", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - }); - - it("Effects (container3 |> elm-3), lifts it up", () => { - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Effects (container3 |> elm-4), lifts it up", () => { - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Moves outside the parent preservers the last transformation", () => { - cy.get("#id-10").trigger("mousemove", { - clientX: startingPointX, - clientY: startingPointY + (2 * elmBox.height + 2 * elmBox.height), - force: true, - }); - - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - - it("Triggers mouseup", () => { - cy.get("#id-10").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Effected elements are switched ", () => { - cy.get("#id-9").should("have.css", "transform", "none"); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - }); - }); - - context("Moving strict vertically multi siblings - out up", () => { - it("Transforms (container3 |> elm-3) out from above", () => { - cy.get("#id-11").then((elm) => { - elmBox = elm[0].getBoundingClientRect(); - startingPointX = elmBox.x + elmBox.width / 2; - startingPointY = elmBox.y + elmBox.height / 2; - cy.get("#id-11") - .trigger("mousedown", { - button: 0, - }) - .trigger("mousemove", { - clientX: startingPointX, - clientY: startingPointY - ((2 / 3) * elmBox.height + 2), - force: true, - }) - .trigger("mousemove", { - clientX: startingPointX, - clientY: - startingPointY - (2 * elmBox.height + (1 / 3) * elmBox.height), - force: true, - }); - }); - }); - - it("Makes sure all siblings lifted up to fill the gap", () => { - cy.get("#id-9").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -116)" - ); - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 58)" - ); - }); - - it("Moves outside the parent", () => { - cy.get("#id-11").trigger("mousemove", { - clientX: startingPointX, - clientY: startingPointY - (2 * elmBox.height + elmBox.height), - force: true, - }); - }); - - it("Triggers mouseup", () => { - cy.get("#id-11").trigger("mouseup", { force: true }); - }); - - it("Makes sure list has four elements", () => { - cy.get("#id-p3") - .should("not.be.empty") - .and(($li) => { - expect($li[0].children).to.have.length(4); - }); - }); - - it("Resets all positions considering leaving from above is not suitable", () => { - cy.get("#id-9").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 0)" - ); - - cy.get("#id-11").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - - cy.get("#id-12").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, -58)" - ); - - cy.get("#id-10").should( - "have.css", - "transform", - "matrix(1, 0, 0, 1, 0, 116)" - ); - }); - }); - } - - URLs.forEach(({ url, desc }) => { - context(desc, () => { - before(() => { - cy.visit(url); - }); - - myContext(); - }); - }); -}); diff --git a/packages/dflex-dnd-playground/tests/outPosition/horizontally.spec.ts b/packages/dflex-dnd-playground/tests/outPosition/horizontally.spec.ts new file mode 100644 index 000000000..db772d9df --- /dev/null +++ b/packages/dflex-dnd-playground/tests/outPosition/horizontally.spec.ts @@ -0,0 +1,194 @@ +import { test, expect, Page, Locator } from "@playwright/test"; + +test.describe.serial("Dragged is out position horizontally", async () => { + let page: Page; + + const draggedID = "#id-10"; + let draggedRect: { x: number; y: number; width: number; height: number }; + + let elm10: Locator; + let elm09: Locator; + let elm11: Locator; + let elm12: Locator; + + let startingPointX: number; + let startingPointY: number; + + [ + { + url: "http://localhost:3001/", + desc: "Testing Container Based Event", + }, + { + url: "http://localhost:3001/component-based-event", + desc: "Testing Component Based Event", + }, + ].forEach(async (testCase) => { + test.describe(testCase.desc, async () => { + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + + page = await context.newPage(); + await page.goto(testCase.url); + + elm09 = page.locator("#id-9"); + elm10 = page.locator("#id-10"); + elm11 = page.locator("#id-11"); + elm12 = page.locator("#id-12"); + + // @ts-ignore + draggedRect = await elm10.boundingBox(); + + startingPointX = draggedRect.x + draggedRect.width / 2; + startingPointY = draggedRect.y + draggedRect.height / 2; + }); + + async function expectSiblingsPositions() { + test("Siblings have the correct position", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + await expect(elm12).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + }); + + test("Triggers mouseup", async () => { + await page.dispatchEvent(draggedID, "mouseup", { + button: 0, + force: true, + }); + }); + + test("Resets Siblings positions", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm10).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + await expect(elm12).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + }); + } + + test.describe(`Moving horizontally container3`, () => { + test.describe("Strictly out form the right", async () => { + test("Moving dragged element to the right", async () => { + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX + ((2 / 3) * draggedRect.width + 2), + startingPointY, + { + steps: 5, + } + ); + }); + + await expectSiblingsPositions(); + }); + + test.describe("Strictly out form the left", async () => { + test("Moving dragged element to the left", async () => { + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX - ((2 / 3) * draggedRect.width + 2), + startingPointY, + { + steps: 5, + } + ); + }); + + await expectSiblingsPositions(); + }); + + test.describe("Slightly down, out form the right", async () => { + test("Moving dragged element to the right", async () => { + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX + ((2 / 3) * draggedRect.width + 2), + startingPointY + 10, + { + steps: 5, + } + ); + }); + + await expectSiblingsPositions(); + }); + + test.describe("Slightly down, out form the left", async () => { + test("Moving dragged element to the left", async () => { + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX - ((2 / 3) * draggedRect.width + 2), + startingPointY + 10, + { + steps: 5, + } + ); + }); + + await expectSiblingsPositions(); + }); + + test.describe("Slightly up, out form the right", async () => { + test("Moving dragged element to the right", async () => { + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX + ((2 / 3) * draggedRect.width + 2), + startingPointY - 10, + { + steps: 5, + } + ); + }); + + await expectSiblingsPositions(); + }); + + test.describe("Slightly up, out form the left", async () => { + test("Moving dragged element to the left", async () => { + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX - ((2 / 3) * draggedRect.width + 2), + startingPointY - 10, + { + steps: 5, + } + ); + }); + + await expectSiblingsPositions(); + }); + }); + }); + }); +}); diff --git a/packages/dflex-dnd-playground/tests/outPosition/vertically.spec.ts b/packages/dflex-dnd-playground/tests/outPosition/vertically.spec.ts new file mode 100644 index 000000000..c5977f9c6 --- /dev/null +++ b/packages/dflex-dnd-playground/tests/outPosition/vertically.spec.ts @@ -0,0 +1,292 @@ +import { test, expect, Page, Locator } from "@playwright/test"; + +test.describe.serial("Dragged is out position vertically", async () => { + let page: Page; + + let draggedID = "#id-10"; + let draggedRect: { x: number; y: number; width: number; height: number }; + + let elm10: Locator; + let elm09: Locator; + let elm11: Locator; + let elm12: Locator; + + let startingPointX: number; + let startingPointY: number; + + [ + { + url: "http://localhost:3001/", + desc: "Testing Container Based Event", + }, + { + url: "http://localhost:3001/component-based-event", + desc: "Testing Component Based Event", + }, + ].forEach(async (testCase) => { + test.describe(testCase.desc, async () => { + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + + page = await context.newPage(); + await page.goto(testCase.url); + + elm09 = page.locator("#id-9"); + elm10 = page.locator("#id-10"); + elm11 = page.locator("#id-11"); + elm12 = page.locator("#id-12"); + }); + + async function getDraggedRect() { + // @ts-ignore + draggedRect = await elm10.boundingBox(); + + startingPointX = draggedRect.x + draggedRect.width / 2; + startingPointY = draggedRect.y + draggedRect.height / 2; + } + + test.describe(`Moving vertically container3`, () => { + test.describe("Strictly out form the bottom", async () => { + test("Moving dragged element to the bottom", async () => { + await getDraggedRect(); + + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX, + startingPointY + ((2 / 3) * draggedRect.height + 2), + { + steps: 5, + } + ); + }); + + test("Siblings have the correct position", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + await expect(elm12).toHaveCSS("transform", "none"); + }); + + test("Triggers mouseup", async () => { + await page.dispatchEvent(draggedID, "mouseup", { + button: 0, + force: true, + }); + }); + + test("Untransformed siblings not being effected", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm12).toHaveCSS("transform", "none"); + }); + + test("affected siblings switched their positions", async () => { + await expect(elm10).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 58)" + ); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + }); + }); + + test.describe("Strictly out form top", async () => { + test("Moving dragged element to the top", async () => { + await getDraggedRect(); + + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX, + startingPointY - ((2 / 3) * draggedRect.height + 2), + { + steps: 5, + } + ); + }); + + test("Siblings have the correct position", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + await expect(elm12).toHaveCSS("transform", "none"); + }); + + test("Triggers mouseup", async () => { + await page.dispatchEvent(draggedID, "mouseup", { + button: 0, + force: true, + }); + }); + + test("Untransformed siblings not being effected", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm12).toHaveCSS("transform", "none"); + }); + + test("affected siblings switched their positions", async () => { + await expect(elm10).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + }); + }); + + test.describe("Moving down multi siblings strictly", async () => { + test("Moving dragged element down", async () => { + await getDraggedRect(); + + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX, + startingPointY + 2 * draggedRect.height, + { + steps: 10, + } + ); + }); + + test("Siblings have the correct position", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + await expect(elm12).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + }); + + test("Moving dragged out the container, preservers the last transformation", async () => { + await page.mouse.move( + startingPointX, + startingPointY + 4 * draggedRect.height, + { + steps: 5, + } + ); + }); + + test("Siblings preserve their positions", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + await expect(elm12).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + }); + + test("Triggers mouseup", async () => { + await page.dispatchEvent(draggedID, "mouseup", { + button: 0, + force: true, + }); + }); + + test("Untransformed siblings not being effected", async () => { + await expect(elm09).toHaveCSS("transform", "none"); + }); + + test("affected siblings switched their positions", async () => { + await expect(elm12).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + }); + }); + + test.describe("Moving up multi siblings strictly", async () => { + test("Getting the last element to dragged", async () => { + draggedID = "#id-11"; + + // @ts-ignore + draggedRect = await elm11.boundingBox(); + + startingPointX = draggedRect.x + draggedRect.width / 2; + startingPointY = draggedRect.y + draggedRect.height / 2; + }); + + test("Moving dragged element up", async () => { + await page.mouse.move(startingPointX, startingPointY, { + steps: 1, + }); + await page.mouse.down({ button: "left", clickCount: 1 }); + await page.mouse.move( + startingPointX, + startingPointY - 3 * draggedRect.height, + { + steps: 5, + } + ); + }); + + test("Makes sure all siblings are lifted up to fill the gap", async () => { + await expect(elm09).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + await expect(elm10).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 58)" + ); + await expect(elm12).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -116)" + ); + }); + + test("Triggers mouseup", async () => { + await page.dispatchEvent(draggedID, "mouseup", { + button: 0, + force: true, + }); + }); + + test("Resets all positions considering leaving from above is not suitable", async () => { + await expect(elm09).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 0)" + ); + await expect(elm10).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, 116)" + ); + await expect(elm11).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + await expect(elm12).toHaveCSS( + "transform", + "matrix(1, 0, 0, 1, 0, -58)" + ); + }); + }); + }); + }); + }); +}); diff --git a/packages/dflex-dnd-playground/vite.config.ts b/packages/dflex-dnd-playground/vite.config.ts index ea34efaac..40f46506b 100644 --- a/packages/dflex-dnd-playground/vite.config.ts +++ b/packages/dflex-dnd-playground/vite.config.ts @@ -34,20 +34,8 @@ const moduleResolution = [ ]; const config: UserConfigExport = { - plugins: [react()], - server: { - port: PORT, - }, - preview: { - port: PORT, - }, - resolve: {}, -}; - -if (process.env.NODE_ENV === "development") { - Object.assign(config, { resolve: { alias: moduleResolution } }); - - config.plugins!.push( + plugins: [ + react(), replaceCodePlugin({ replacements: [ { @@ -55,9 +43,18 @@ if (process.env.NODE_ENV === "development") { to: "true", }, ], - }) - ); -} + }), + ], + server: { + port: PORT, + }, + preview: { + port: PORT, + }, + resolve: { + alias: moduleResolution, + }, +}; // https://vitejs.dev/config/ export default defineConfig(config); diff --git a/packages/dflex-dnd/README.md b/packages/dflex-dnd/README.md index 593a3a426..04598483d 100644 --- a/packages/dflex-dnd/README.md +++ b/packages/dflex-dnd/README.md @@ -31,13 +31,13 @@
-# @dflex/dnd +# DFlex -DFlex Drag and Drop is the main package that depends on the other packages. It -is responsible for the magical logic of the library to introduce the drag and -drop interactive functionality. +A Drag-and-Drop library for all JavaScript frameworks implementing an enhanced +transformation mechanism to manipulate DOM elements. It is so far the only +library on internet that manipulates the DOM instead of reconstructing it. -## DFlex Features ✅ +## Features ✅ - Dynamic architecture. - Traverse DOM without calling browser API. @@ -49,6 +49,28 @@ drop interactive functionality. - Event driven API. - Targeting each DOM node individually. - Extensible using JSON tree instead of flat recursion. +- Support three different types of restrictions: