From 4e4389584c7f4517b2a94e6b79ffe600a3c67b46 Mon Sep 17 00:00:00 2001
From: Louis Brunner
Date: Thu, 19 Dec 2024 23:55:30 +0000
Subject: [PATCH] feat: add support for React v19
---
__mocks__/react-dnd-preview.ts | 2 +
biome.json | 2 +-
package-lock.json | 109 +++++++-----------
package.json | 9 +-
.../dnd-multi-backend/examples/Backends.ts | 15 ++-
packages/dnd-multi-backend/examples/DnD.ts | 17 +--
packages/dnd-multi-backend/examples/index.ts | 19 +--
.../react-dnd-multi-backend/examples/App.tsx | 59 ++++++----
.../examples/Basket.tsx | 15 +--
.../react-dnd-multi-backend/examples/Card.tsx | 6 +-
.../examples/MultiBasket.tsx | 28 +++--
.../examples/MultiCard.tsx | 22 +++-
.../examples/common.ts | 13 +++
.../examples/index.tsx | 8 +-
packages/react-dnd-multi-backend/package.json | 4 +-
.../src/components/DndProvider.tsx | 2 +-
.../src/components/Preview.tsx | 2 +-
.../src/components/__tests__/Preview.test.tsx | 2 +-
.../react-dnd-preview/examples/main/App.tsx | 12 +-
.../react-dnd-preview/examples/main/index.tsx | 8 +-
.../examples/main/methods/Components.tsx | 12 +-
.../examples/main/methods/Hooks.tsx | 8 +-
.../examples/main/methods/common.tsx | 31 ++---
.../react-dnd-preview/examples/offset/App.tsx | 50 ++++----
.../examples/offset/index.tsx | 8 +-
.../react-dnd-preview/examples/shared.tsx | 43 ++++---
packages/react-dnd-preview/package.json | 2 +-
packages/react-dnd-preview/src/Preview.tsx | 2 +-
packages/react-dnd-preview/src/offsets.ts | 2 +-
29 files changed, 297 insertions(+), 215 deletions(-)
diff --git a/__mocks__/react-dnd-preview.ts b/__mocks__/react-dnd-preview.ts
index 075a2648..91d0b16e 100644
--- a/__mocks__/react-dnd-preview.ts
+++ b/__mocks__/react-dnd-preview.ts
@@ -1,6 +1,8 @@
import {MockDragMonitor} from '@mocks/mocks'
import type {PreviewProps, PreviewState, usePreviewState} from 'react-dnd-preview'
+import type {JSX} from 'react'
+
const preview = jest.createMockFromModule>('react-dnd-preview')
const state: PreviewState = {
diff --git a/biome.json b/biome.json
index 90088c38..01208092 100644
--- a/biome.json
+++ b/biome.json
@@ -24,6 +24,6 @@
}
},
"files": {
- "ignore": ["examples", "coverage", "packages/*/dist"]
+ "ignore": ["examples/*.js", "coverage", "packages/*/dist"]
}
}
diff --git a/package-lock.json b/package-lock.json
index 89998e6c..44d7af5d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,20 +16,21 @@
"@testing-library/react": "^16.1.0",
"@types/jest": "^29.5.14",
"@types/jsdom": "^21.1.7",
- "@types/react-dom": "^18.3.5",
+ "@types/react": "^19.0.2",
+ "@types/react-dom": "^19.0.2",
"esbuild": "^0.24",
"esbuild-jest": "^0.5.0",
- "esbuild-node-externals": "^1.15.0",
+ "esbuild-node-externals": "^1.16.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"node-notifier": "^10.0.1",
- "react": "^18.3.1",
+ "react": "^19.0.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dnd-test-backend": "^16.0.1",
"react-dnd-test-utils": "^16.0.1",
"react-dnd-touch-backend": "^16.0.1",
- "react-dom": "^18.3.1",
+ "react-dom": "^19.0.0",
"typescript": "^5.7.2"
},
"engines": {
@@ -3220,32 +3221,24 @@
"undici-types": "~5.26.4"
}
},
- "node_modules/@types/prop-types": {
- "version": "15.7.12",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
- "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
- "devOptional": true,
- "peer": true
- },
"node_modules/@types/react": {
- "version": "18.3.3",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz",
- "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==",
+ "version": "19.0.2",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.2.tgz",
+ "integrity": "sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==",
"devOptional": true,
- "peer": true,
+ "license": "MIT",
"dependencies": {
- "@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
- "version": "18.3.5",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz",
- "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==",
+ "version": "19.0.2",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.2.tgz",
+ "integrity": "sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==",
"dev": true,
"license": "MIT",
"peerDependencies": {
- "@types/react": "^18.0.0"
+ "@types/react": "^19.0.0"
}
},
"node_modules/@types/stack-utils": {
@@ -4110,8 +4103,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "devOptional": true,
- "peer": true
+ "devOptional": true
},
"node_modules/data-urls": {
"version": "3.0.2",
@@ -4373,10 +4365,11 @@
}
},
"node_modules/esbuild-node-externals": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/esbuild-node-externals/-/esbuild-node-externals-1.15.0.tgz",
- "integrity": "sha512-lM5f3CQL9Ctv6mBwwYAEMcphK2qrjVRnemT1mufECpFaidZvFVvQDPcuno/MQfLVk4utVuSVxm1RHLyg/ONQ/A==",
+ "version": "1.16.0",
+ "resolved": "https://registry.npmjs.org/esbuild-node-externals/-/esbuild-node-externals-1.16.0.tgz",
+ "integrity": "sha512-g16pp/yDFqBJ9/9D+UIWPj5uC8MPslMK62HmAXW+ZomZWJifOFTuJgado86UUiMeBrk03z2uvdS6cIGi0OTRcg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"find-up": "^5.0.0",
"tslib": "^2.4.1"
@@ -8936,7 +8929,8 @@
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
},
"node_modules/js-yaml": {
"version": "3.14.1",
@@ -9065,17 +9059,6 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"dev": true
},
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -9709,12 +9692,10 @@
"link": true
},
"node_modules/react": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
- "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
+ "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -9817,15 +9798,15 @@
}
},
"node_modules/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "version": "19.0.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
+ "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
+ "license": "MIT",
"dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.2"
+ "scheduler": "^0.25.0"
},
"peerDependencies": {
- "react": "^18.3.1"
+ "react": "^19.0.0"
}
},
"node_modules/react-is": {
@@ -10291,12 +10272,10 @@
}
},
"node_modules/scheduler": {
- "version": "0.23.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
- "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
+ "version": "0.25.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
+ "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
+ "license": "MIT"
},
"node_modules/semver": {
"version": "6.3.1",
@@ -11373,7 +11352,7 @@
}
},
"packages/dnd-multi-backend": {
- "version": "8.1.0",
+ "version": "8.1.2",
"license": "MIT",
"funding": {
"type": "individual",
@@ -11384,10 +11363,10 @@
}
},
"packages/rdndmb-html5-to-touch": {
- "version": "8.1.0",
+ "version": "8.1.2",
"license": "MIT",
"dependencies": {
- "dnd-multi-backend": "^8.1.0",
+ "dnd-multi-backend": "^8.1.2",
"react-dnd-html5-backend": "^16.0.1",
"react-dnd-touch-backend": "^16.0.1"
},
@@ -11397,11 +11376,11 @@
}
},
"packages/react-dnd-multi-backend": {
- "version": "8.1.0",
+ "version": "8.1.2",
"license": "MIT",
"dependencies": {
- "dnd-multi-backend": "^8.1.0",
- "react-dnd-preview": "^8.1.0"
+ "dnd-multi-backend": "^8.1.2",
+ "react-dnd-preview": "^8.1.2"
},
"funding": {
"type": "individual",
@@ -11409,20 +11388,20 @@
},
"peerDependencies": {
"dnd-core": "^16.0.1",
- "react": "^16.14.0 || ^17.0.2 || ^18.0.0",
+ "react": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0",
"react-dnd": "^16.0.1",
- "react-dom": "^16.14.0 || ^17.0.2 || ^18.0.0"
+ "react-dom": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0"
}
},
"packages/react-dnd-preview": {
- "version": "8.1.0",
+ "version": "8.1.2",
"license": "MIT",
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/LouisBrunner"
},
"peerDependencies": {
- "react": "^16.14.0 || ^17.0.2 || ^18.0.0",
+ "react": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0",
"react-dnd": "^16.0.1"
}
}
diff --git a/package.json b/package.json
index d3541fe4..e39d0906 100644
--- a/package.json
+++ b/package.json
@@ -39,20 +39,21 @@
"@testing-library/react": "^16.1.0",
"@types/jest": "^29.5.14",
"@types/jsdom": "^21.1.7",
- "@types/react-dom": "^18.3.5",
+ "@types/react-dom": "^19.0.2",
+ "@types/react": "^19.0.2",
"esbuild": "^0.24",
"esbuild-jest": "^0.5.0",
- "esbuild-node-externals": "^1.15.0",
+ "esbuild-node-externals": "^1.16.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"node-notifier": "^10.0.1",
- "react": "^18.3.1",
+ "react": "^19.0.0",
"react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16.0.1",
"react-dnd-test-backend": "^16.0.1",
"react-dnd-test-utils": "^16.0.1",
"react-dnd-touch-backend": "^16.0.1",
- "react-dom": "^18.3.1",
+ "react-dom": "^19.0.0",
"typescript": "^5.7.2"
},
"workspaces": ["./packages/*"]
diff --git a/packages/dnd-multi-backend/examples/Backends.ts b/packages/dnd-multi-backend/examples/Backends.ts
index ad24529c..dbf75008 100644
--- a/packages/dnd-multi-backend/examples/Backends.ts
+++ b/packages/dnd-multi-backend/examples/Backends.ts
@@ -1,7 +1,7 @@
-import {DragDropManager, DragDropActions, BackendFactory, Backend, Unsubscribe, Identifier} from 'dnd-core'
+import type {Backend, BackendFactory, DragDropActions, DragDropManager, Identifier, Unsubscribe} from 'dnd-core'
type Options = {
- draggable?: boolean,
+ draggable?: boolean
}
class DnDBackend implements Backend {
@@ -37,6 +37,7 @@ class DnDBackend implements Backend {
}
}
+ // biome-ignore lint/suspicious/noExplicitAny: interface is like that
connectDragSource(sourceId: Identifier, nodeRaw?: any, _options?: any): Unsubscribe {
const node = nodeRaw as Element
@@ -49,7 +50,7 @@ class DnDBackend implements Backend {
console.log(`${this.#label}: drag`)
this.#actions.beginDrag([sourceId], {
clientOffset: this.#getXY(node),
- getSourceClientOffset: (_id: unknown): {x: number, y: number} => {
+ getSourceClientOffset: (_id: unknown): {x: number; y: number} => {
return this.#getXY(node)
},
})
@@ -74,13 +75,15 @@ class DnDBackend implements Backend {
}
}
+ // biome-ignore lint/suspicious/noExplicitAny: interface is like that
connectDragPreview(_sourceId: any, _node?: any, _options?: any): Unsubscribe {
- return () => { }
+ return () => {}
}
+ // biome-ignore lint/suspicious/noExplicitAny: interface is like that
connectDropTarget(targetId: Identifier, node?: Element, _options?: any): Unsubscribe {
if (node === undefined) {
- return () => { }
+ return () => {}
}
const hover = (e: Event) => {
@@ -120,7 +123,7 @@ class DnDBackend implements Backend {
this.#actions.endDrag()
}
- #getXY = (node: Element): {x: number, y: number} => {
+ #getXY = (node: Element): {x: number; y: number} => {
const {top: x, left: y} = node.getBoundingClientRect()
return {x, y}
}
diff --git a/packages/dnd-multi-backend/examples/DnD.ts b/packages/dnd-multi-backend/examples/DnD.ts
index 0e35460d..3bf01e5d 100644
--- a/packages/dnd-multi-backend/examples/DnD.ts
+++ b/packages/dnd-multi-backend/examples/DnD.ts
@@ -1,8 +1,8 @@
-import {DragSource as IDragSource, DropTarget as IDropTarget, DragDropMonitor, Identifier} from 'dnd-core'
+import type {DragDropMonitor, DragSource as IDragSource, DropTarget as IDropTarget, Identifier} from 'dnd-core'
type createElementProps = {
- text: string,
- color: string,
+ text: string
+ color: string
}
const createElement = ({text, color}: createElementProps): Element => {
@@ -28,7 +28,8 @@ export class DragSource implements IDragSource {
beginDrag(_monitor: DragDropMonitor, _targetId: Identifier): void {
// FIXME: the interface is actually wrong
- return {color: this.#color} as unknown as void
+ // biome-ignore lint/correctness/noVoidTypeReturn: interface is wrong
+ return {color: this.#color} as unknown as undefined
}
endDrag(_monitor: DragDropMonitor, _targetId: Identifier): void {}
@@ -42,11 +43,11 @@ export class DragSource implements IDragSource {
}
}
-export class DropTarget implements IDropTarget {
+export class DropTarget implements IDropTarget {
#node: Element
- #onDrop?: (r: any) => void
+ #onDrop?: (r: T) => void
- constructor({text, color, onDrop}: createElementProps & {onDrop?: (r: any) => void}) {
+ constructor({text, color, onDrop}: createElementProps & {onDrop?: (r: T) => void}) {
this.#node = createElement({text, color})
this.#onDrop = onDrop
}
@@ -61,7 +62,7 @@ export class DropTarget implements IDropTarget {
hover(_monitor: DragDropMonitor, _targetId: Identifier): void {}
- drop(monitor: DragDropMonitor, _targetId: Identifier): any {
+ drop(monitor: DragDropMonitor, _targetId: Identifier): void {
this.#onDrop?.(monitor.getItem())
}
}
diff --git a/packages/dnd-multi-backend/examples/index.ts b/packages/dnd-multi-backend/examples/index.ts
index 87db9575..ce740c69 100644
--- a/packages/dnd-multi-backend/examples/index.ts
+++ b/packages/dnd-multi-backend/examples/index.ts
@@ -1,7 +1,7 @@
-import { createDragDropManager } from 'dnd-core'
-import { MultiBackend, MouseTransition, TouchTransition } from '../src'
-import { HTML5Backend, TouchBackend } from './Backends'
-import { DragSource, DropTarget } from './DnD'
+import {createDragDropManager} from 'dnd-core'
+import {MouseTransition, MultiBackend, TouchTransition} from '../src'
+import {HTML5Backend, TouchBackend} from './Backends'
+import {DragSource, DropTarget} from './DnD'
// Setup pipeline
const pipeline = {
@@ -26,10 +26,13 @@ const registry = manager.getRegistry()
// Create logic
const src = new DragSource({text: 'Source', color: 'red'})
-const dst = new DropTarget({text: 'Target', color: 'orange', onDrop: (itemRaw: any) => {
- const item = itemRaw as {color: string}
- console.log(`Dropped: ${item.color}`)
-}})
+const dst = new DropTarget<{color: string}>({
+ text: 'Target',
+ color: 'orange',
+ onDrop: (item) => {
+ console.log(`Dropped: ${item.color}`)
+ },
+})
const Item = 'item'
diff --git a/packages/react-dnd-multi-backend/examples/App.tsx b/packages/react-dnd-multi-backend/examples/App.tsx
index e4d20513..03d729e7 100644
--- a/packages/react-dnd-multi-backend/examples/App.tsx
+++ b/packages/react-dnd-multi-backend/examples/App.tsx
@@ -1,24 +1,30 @@
-import { CSSProperties, RefObject, StrictMode, useContext, useRef, useState } from 'react'
-import { DndProvider as ReactDndProvider } from 'react-dnd'
+import {type CSSProperties, type JSX, type RefObject, StrictMode, useContext, useRef, useState} from 'react'
+import {DndProvider as ReactDndProvider} from 'react-dnd'
-import { MultiBackend, DndProvider, PreviewContext, usePreview, Preview, PreviewState } from '../src'
-import { HTML5toTouch } from 'rdndmb-html5-to-touch'
+import {HTML5toTouch} from 'rdndmb-html5-to-touch'
+import {DndProvider, MultiBackend, Preview, PreviewContext, type PreviewState, usePreview} from '../src'
-import {Card} from './Card'
import {Basket} from './Basket'
-import {MultiCard} from './MultiCard'
+import {Card} from './Card'
import {MultiBasket} from './MultiBasket'
-import {DragContent} from './common'
-
-const Block = ({row, text, item, style}: {row: number, text: string, item: DragContent, style: CSSProperties}): JSX.Element => {
- return Generated {text}
+import {MultiCard} from './MultiCard'
+import type {DragContent} from './common'
+
+const Block = ({row, text, item, style}: {row: number; text: string; item: DragContent; style: CSSProperties}): JSX.Element => {
+ return (
+
+ Generated {text}
+
+ )
}
const ContextPreview = ({text}: {text: string}): JSX.Element => {
@@ -41,13 +47,15 @@ const HookPreview = ({text}: {text: string}): JSX.Element | null => {
const ComponentPreview = ({text}: {text: string}): JSX.Element => {
return (
- ): JSX.Element => {
- return
- }} />
+ ): JSX.Element => {
+ return
+ }}
+ />
)
}
-const Content = ({title, fref}: {title: string, fref: RefObject}) => {
+const Content = ({title, fref}: {title: string; fref: RefObject}) => {
return (
<>
{title} API
@@ -95,7 +103,14 @@ export const App = (): JSX.Element => {
return (
- {setAPI(e.target.checked)}} />
+ {
+ setAPI(e.target.checked)
+ }}
+ />
{useNew ? newAPI : oldAPI}
diff --git a/packages/react-dnd-multi-backend/examples/Basket.tsx b/packages/react-dnd-multi-backend/examples/Basket.tsx
index 1ef5f367..0c46bf46 100644
--- a/packages/react-dnd-multi-backend/examples/Basket.tsx
+++ b/packages/react-dnd-multi-backend/examples/Basket.tsx
@@ -1,9 +1,9 @@
-import {CSSProperties, RefObject} from 'react'
-import { useDrop } from 'react-dnd'
-import {DragContent} from './common'
+import type {CSSProperties, JSX, RefObject} from 'react'
+import {useDrop} from 'react-dnd'
+import {type DragContent, useFixRDnDRef} from './common'
-export const Basket = ({logs}: {logs: RefObject}): JSX.Element => {
- const [collectedProps, drop] = useDrop({
+export const Basket = ({logs}: {logs: RefObject}): JSX.Element => {
+ const [collectedProps, drop] = useDrop({
accept: 'card',
drop: (item) => {
const message = `Dropped: ${item.color}`
@@ -22,7 +22,7 @@ export const Basket = ({logs}: {logs: RefObject}): JSX.Element => {
const isOver = collectedProps.isOver
const canDrop = collectedProps.canDrop
const style: CSSProperties = {
- backgroundColor: (isOver && canDrop) ? '#f3f3f3' : '#cccccc',
+ backgroundColor: isOver && canDrop ? '#f3f3f3' : '#cccccc',
border: '1px dashed black',
display: 'inline-block',
width: '100px',
@@ -30,5 +30,6 @@ export const Basket = ({logs}: {logs: RefObject}): JSX.Element => {
margin: '10px',
}
- return
+ const dropRef = useFixRDnDRef(drop)
+ return
}
diff --git a/packages/react-dnd-multi-backend/examples/Card.tsx b/packages/react-dnd-multi-backend/examples/Card.tsx
index bde47953..0e53820e 100644
--- a/packages/react-dnd-multi-backend/examples/Card.tsx
+++ b/packages/react-dnd-multi-backend/examples/Card.tsx
@@ -1,5 +1,6 @@
-import {CSSProperties} from 'react'
+import type {CSSProperties, JSX} from 'react'
import {useDrag} from 'react-dnd'
+import {useFixRDnDRef} from './common'
export const Card = (props: {color: string}): JSX.Element => {
const [collectedProps, drag] = useDrag({
@@ -21,5 +22,6 @@ export const Card = (props: {color: string}): JSX.Element => {
margin: '10px',
}
- return
+ const dragRef = useFixRDnDRef(drag)
+ return
}
diff --git a/packages/react-dnd-multi-backend/examples/MultiBasket.tsx b/packages/react-dnd-multi-backend/examples/MultiBasket.tsx
index 969b29bb..bfc2485b 100644
--- a/packages/react-dnd-multi-backend/examples/MultiBasket.tsx
+++ b/packages/react-dnd-multi-backend/examples/MultiBasket.tsx
@@ -1,9 +1,15 @@
-import {CSSProperties, RefObject} from 'react'
+import type {CSSProperties, JSX, RefObject} from 'react'
import {useMultiDrop} from '../src'
-import {DragContent} from './common'
+import {type DragContent, useFixRDnDRef} from './common'
-export const MultiBasket = ({logs}: {logs: RefObject}): JSX.Element => {
- const [_, {html5: [html5Props, html5Drop], touch: [touchProps, touchDrop]}] = useMultiDrop({
+export const MultiBasket = ({logs}: {logs: RefObject}): JSX.Element => {
+ const [
+ _,
+ {
+ html5: [html5Props, html5Drop],
+ touch: [touchProps, touchDrop],
+ },
+ ] = useMultiDrop({
accept: 'card',
drop: (item) => {
const message = `Dropped: ${item.color}`
@@ -26,7 +32,7 @@ export const MultiBasket = ({logs}: {logs: RefObject}): JSX.Element =>
margin: '10px',
}
const html5DropStyle: CSSProperties = {
- backgroundColor: (html5Props.isOver && html5Props.canDrop) ? '#f3f3f3' : '#bbbbbb',
+ backgroundColor: html5Props.isOver && html5Props.canDrop ? '#f3f3f3' : '#bbbbbb',
display: 'inline-block',
margin: '5px',
width: '90px',
@@ -35,7 +41,7 @@ export const MultiBasket = ({logs}: {logs: RefObject}): JSX.Element =>
userSelect: 'none',
}
const touchDropStyle: CSSProperties = {
- backgroundColor: (touchProps.isOver && touchProps.canDrop) ? '#f3f3f3' : '#bbbbbb',
+ backgroundColor: touchProps.isOver && touchProps.canDrop ? '#f3f3f3' : '#bbbbbb',
display: 'inline-block',
margin: '5px',
width: '90px',
@@ -43,10 +49,16 @@ export const MultiBasket = ({logs}: {logs: RefObject}): JSX.Element =>
textAlign: 'center',
userSelect: 'none',
}
+ const html5DropRef = useFixRDnDRef(html5Drop)
+ const touchDropRef = useFixRDnDRef(touchDrop)
return (
-
HTML5
-
Touch
+
+ HTML5
+
+
+ Touch
+
)
}
diff --git a/packages/react-dnd-multi-backend/examples/MultiCard.tsx b/packages/react-dnd-multi-backend/examples/MultiCard.tsx
index ad84a850..7d4f8f7c 100644
--- a/packages/react-dnd-multi-backend/examples/MultiCard.tsx
+++ b/packages/react-dnd-multi-backend/examples/MultiCard.tsx
@@ -1,9 +1,15 @@
-import {CSSProperties} from 'react'
+import type {CSSProperties, JSX} from 'react'
import {useMultiDrag} from '../src'
-import {DragContent} from './common'
+import {type DragContent, useFixRDnDRef} from './common'
export const MultiCard = (props: {color: string}): JSX.Element => {
- const [_, {html5: [html5Props, html5Drag], touch: [touchProps, touchDrag]}] = useMultiDrag({
+ const [
+ _,
+ {
+ html5: [html5Props, html5Drag],
+ touch: [touchProps, touchDrag],
+ },
+ ] = useMultiDrag({
type: 'card',
item: {color: props.color},
collect: (monitor) => {
@@ -37,10 +43,16 @@ export const MultiCard = (props: {color: string}): JSX.Element => {
textAlign: 'center',
userSelect: 'none',
}
+ const html5DragRef = useFixRDnDRef(html5Drag)
+ const touchDragRef = useFixRDnDRef(touchDrag)
return (
-
HTML5
-
Touch
+
+ HTML5
+
+
+ Touch
+
)
}
diff --git a/packages/react-dnd-multi-backend/examples/common.ts b/packages/react-dnd-multi-backend/examples/common.ts
index e79c0812..890028d5 100644
--- a/packages/react-dnd-multi-backend/examples/common.ts
+++ b/packages/react-dnd-multi-backend/examples/common.ts
@@ -1,3 +1,16 @@
+import {useCallback} from 'react'
+import type {ConnectDragSource, ConnectDropTarget} from 'react-dnd'
+
export type DragContent = {
color: string
}
+
+// FIXME: issue with react-dnd when using React v19
+export const useFixRDnDRef = (ref: ConnectDropTarget | ConnectDragSource) => {
+ return useCallback(
+ (node: T | null) => {
+ ref(node)
+ },
+ [ref],
+ )
+}
diff --git a/packages/react-dnd-multi-backend/examples/index.tsx b/packages/react-dnd-multi-backend/examples/index.tsx
index b3941873..e0d50c60 100644
--- a/packages/react-dnd-multi-backend/examples/index.tsx
+++ b/packages/react-dnd-multi-backend/examples/index.tsx
@@ -1,5 +1,9 @@
import {createRoot} from 'react-dom/client'
import {App} from './App'
-const root = createRoot(document.getElementById('root')!)
-root.render(,)
+const rootElement = document.getElementById('root')
+if (!rootElement) {
+ throw new Error('could not find root element')
+}
+const root = createRoot(rootElement)
+root.render()
diff --git a/packages/react-dnd-multi-backend/package.json b/packages/react-dnd-multi-backend/package.json
index f0d389de..1c5fa3e6 100644
--- a/packages/react-dnd-multi-backend/package.json
+++ b/packages/react-dnd-multi-backend/package.json
@@ -26,8 +26,8 @@
},
"peerDependencies": {
"dnd-core": "^16.0.1",
- "react": "^16.14.0 || ^17.0.2 || ^18.0.0",
+ "react": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0",
"react-dnd": "^16.0.1",
- "react-dom": "^16.14.0 || ^17.0.2 || ^18.0.0"
+ "react-dom": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0"
}
}
diff --git a/packages/react-dnd-multi-backend/src/components/DndProvider.tsx b/packages/react-dnd-multi-backend/src/components/DndProvider.tsx
index 78be4aa9..003c6e44 100644
--- a/packages/react-dnd-multi-backend/src/components/DndProvider.tsx
+++ b/packages/react-dnd-multi-backend/src/components/DndProvider.tsx
@@ -1,5 +1,5 @@
import {MultiBackend, type MultiBackendOptions} from 'dnd-multi-backend'
-import {type ReactNode, createContext, useState} from 'react'
+import {type JSX, type ReactNode, createContext, useState} from 'react'
import {DndProvider as ReactDndProvider} from 'react-dnd'
export const PreviewPortalContext = createContext(null)
diff --git a/packages/react-dnd-multi-backend/src/components/Preview.tsx b/packages/react-dnd-multi-backend/src/components/Preview.tsx
index 5199c9d6..e609783f 100644
--- a/packages/react-dnd-multi-backend/src/components/Preview.tsx
+++ b/packages/react-dnd-multi-backend/src/components/Preview.tsx
@@ -1,4 +1,4 @@
-import {useContext} from 'react'
+import {type JSX, useContext} from 'react'
import {Preview as DnDPreview, Context as PreviewContext, type PreviewProps, type PreviewState} from 'react-dnd-preview'
import {createPortal} from 'react-dom'
diff --git a/packages/react-dnd-multi-backend/src/components/__tests__/Preview.test.tsx b/packages/react-dnd-multi-backend/src/components/__tests__/Preview.test.tsx
index 807439e6..ce346973 100644
--- a/packages/react-dnd-multi-backend/src/components/__tests__/Preview.test.tsx
+++ b/packages/react-dnd-multi-backend/src/components/__tests__/Preview.test.tsx
@@ -1,6 +1,6 @@
import {MockMultiBackend, MockPreviewList, type MockedMultiBackend, type MockedPreviewList} from '@mocks/mocks'
import {act, render, screen} from '@testing-library/react'
-import {useState} from 'react'
+import {type JSX, useState} from 'react'
import {DndContext, type DndContextType} from 'react-dnd'
import type {PreviewGenerator} from 'react-dnd-preview'
import {PreviewPortalContext} from '../DndProvider'
diff --git a/packages/react-dnd-preview/examples/main/App.tsx b/packages/react-dnd-preview/examples/main/App.tsx
index 491b89ed..e013893e 100644
--- a/packages/react-dnd-preview/examples/main/App.tsx
+++ b/packages/react-dnd-preview/examples/main/App.tsx
@@ -1,9 +1,9 @@
-import { DndProvider } from 'react-dnd'
-import { Components } from './methods/Components'
-import { Hooks } from './methods/Hooks'
-import { TouchBackend } from 'react-dnd-touch-backend'
-import { Draggable } from '../shared'
-import { StrictMode } from 'react'
+import {type JSX, StrictMode} from 'react'
+import {DndProvider} from 'react-dnd'
+import {TouchBackend} from 'react-dnd-touch-backend'
+import {Draggable} from '../shared'
+import {Components} from './methods/Components'
+import {Hooks} from './methods/Hooks'
export const App = (): JSX.Element => {
return (
diff --git a/packages/react-dnd-preview/examples/main/index.tsx b/packages/react-dnd-preview/examples/main/index.tsx
index b3941873..e0d50c60 100644
--- a/packages/react-dnd-preview/examples/main/index.tsx
+++ b/packages/react-dnd-preview/examples/main/index.tsx
@@ -1,5 +1,9 @@
import {createRoot} from 'react-dom/client'
import {App} from './App'
-const root = createRoot(document.getElementById('root')!)
-root.render(,)
+const rootElement = document.getElementById('root')
+if (!rootElement) {
+ throw new Error('could not find root element')
+}
+const root = createRoot(rootElement)
+root.render()
diff --git a/packages/react-dnd-preview/examples/main/methods/Components.tsx b/packages/react-dnd-preview/examples/main/methods/Components.tsx
index 31531a6f..fa241407 100644
--- a/packages/react-dnd-preview/examples/main/methods/Components.tsx
+++ b/packages/react-dnd-preview/examples/main/methods/Components.tsx
@@ -1,15 +1,15 @@
-import { Preview, Context, PreviewState } from '../../../src'
-import {DragContent} from '../../shared'
-import { WithPropFunction, WithChildFunction, WithChildComponent, WithChildFunctionContext, GenPreviewLiteProps } from './common'
+import {Context, Preview, type PreviewState} from '../../../src'
+import type {DragContent} from '../../shared'
+import {type GenPreviewLiteProps, WithChildComponent, WithChildFunction, WithChildFunctionContext, WithPropFunction} from './common'
+
+import type {JSX} from 'react'
export const Components = ({title, col}: GenPreviewLiteProps): JSX.Element => {
return (
<>
-
- {WithChildFunction({title, col})}
-
+ {WithChildFunction({title, col})}
diff --git a/packages/react-dnd-preview/examples/main/methods/Hooks.tsx b/packages/react-dnd-preview/examples/main/methods/Hooks.tsx
index 6602d232..5457881e 100644
--- a/packages/react-dnd-preview/examples/main/methods/Hooks.tsx
+++ b/packages/react-dnd-preview/examples/main/methods/Hooks.tsx
@@ -1,6 +1,8 @@
-import { usePreview } from '../../../src'
-import {DragContent} from '../../shared'
-import { generatePreview, GenPreviewLiteProps, GenPreviewProps } from './common'
+import {usePreview} from '../../../src'
+import type {DragContent} from '../../shared'
+import {type GenPreviewLiteProps, type GenPreviewProps, generatePreview} from './common'
+
+import type {JSX} from 'react'
const WithHook = (props: GenPreviewProps): JSX.Element | null => {
const preview = usePreview()
diff --git a/packages/react-dnd-preview/examples/main/methods/common.tsx b/packages/react-dnd-preview/examples/main/methods/common.tsx
index 0b2fe579..ad8d07df 100644
--- a/packages/react-dnd-preview/examples/main/methods/common.tsx
+++ b/packages/react-dnd-preview/examples/main/methods/common.tsx
@@ -1,24 +1,29 @@
-import { useContext } from 'react'
-import { Context, PreviewState, usePreviewStateContent } from '../../../src'
-import { Shape, DragContent } from '../../shared'
+import {type JSX, useContext} from 'react'
+import {Context, type PreviewState, type usePreviewStateContent} from '../../../src'
+import {type DragContent, Shape} from '../../shared'
export type PreviewProps = usePreviewStateContent
export type GenPreviewProps = {
- row: number,
- col: number,
- title: string,
- method: string,
+ row: number
+ col: number
+ title: string
+ method: string
}
export const generatePreview = ({itemType, item, style, ref}: PreviewProps, {row, col, title, method}: GenPreviewProps): JSX.Element => {
return (
-
+
{title}
Generated {itemType?.toString()}
diff --git a/packages/react-dnd-preview/examples/offset/App.tsx b/packages/react-dnd-preview/examples/offset/App.tsx
index ad87cbd9..f569fecb 100644
--- a/packages/react-dnd-preview/examples/offset/App.tsx
+++ b/packages/react-dnd-preview/examples/offset/App.tsx
@@ -1,16 +1,16 @@
-import {CSSProperties, StrictMode, useState} from 'react'
+import {type CSSProperties, type JSX, type Ref, StrictMode, useState} from 'react'
import {DndProvider} from 'react-dnd'
import {TouchBackend} from 'react-dnd-touch-backend'
-import {usePreview, Point} from '../../src'
+import {type Point, usePreview} from '../../src'
import type {PreviewPlacement} from '../../src/'
-import {Draggable, Shape, DragContent} from '../shared'
+import {type DragContent, Draggable, Shape} from '../shared'
type Kinds = 'default' | 'ref' | 'custom_client' | 'custom_source_client'
type PreviewProps = {
- kind: Kinds,
- text: string,
- placement?: PreviewPlacement,
+ kind: Kinds
+ text: string
+ placement?: PreviewPlacement
padding?: Point
}
@@ -21,13 +21,15 @@ export const Preview = ({kind, text, placement, padding}: PreviewProps): JSX.Ele
}
const {style, ref, monitor} = preview
- let finalRef, finalStyle: CSSProperties = {...style, opacity: 0.5, whiteSpace: 'nowrap'}
+ let finalRef: Ref | undefined
+ let finalStyle: CSSProperties = {...style, opacity: 0.5, whiteSpace: 'nowrap'}
if (kind === 'default') {
// Keep as-is
} else if (kind === 'ref') {
finalRef = ref
} else {
- let x, y
+ let x: number
+ let y: number
if (kind === 'custom_client') {
x = monitor.getClientOffset()?.x ?? 0
y = monitor.getClientOffset()?.y ?? 0
@@ -45,7 +47,11 @@ export const Preview = ({kind, text, placement, padding}: PreviewProps): JSX.Ele
}
}
- return {text}
+ return (
+
+ {text}
+
+ )
}
export const App = (): JSX.Element => {
@@ -85,27 +91,31 @@ export const App = (): JSX.Element => {
-
+
-
+
- {
- setDebug(e.target.checked)
- }} id="debug_mode"/>
+ {
+ setDebug(e.target.checked)
+ }}
+ id="debug_mode"
+ />
-
-
-
-
+
+
+
{debug ? (
<>
-
-
+
+
>
) : null}
diff --git a/packages/react-dnd-preview/examples/offset/index.tsx b/packages/react-dnd-preview/examples/offset/index.tsx
index b3941873..e0d50c60 100644
--- a/packages/react-dnd-preview/examples/offset/index.tsx
+++ b/packages/react-dnd-preview/examples/offset/index.tsx
@@ -1,5 +1,9 @@
import {createRoot} from 'react-dom/client'
import {App} from './App'
-const root = createRoot(document.getElementById('root')!)
-root.render(,)
+const rootElement = document.getElementById('root')
+if (!rootElement) {
+ throw new Error('could not find root element')
+}
+const root = createRoot(rootElement)
+root.render()
diff --git a/packages/react-dnd-preview/examples/shared.tsx b/packages/react-dnd-preview/examples/shared.tsx
index 0b286394..82fcd461 100644
--- a/packages/react-dnd-preview/examples/shared.tsx
+++ b/packages/react-dnd-preview/examples/shared.tsx
@@ -1,32 +1,34 @@
-import {CSSProperties, forwardRef, ReactNode} from 'react'
+import {type CSSProperties, type JSX, type ReactNode, type Ref, useCallback} from 'react'
import {useDrag} from 'react-dnd'
export type DragContent = {
- type: string,
- color: string,
+ type: string
+ color: string
}
export type ShapeProps = {
- style: CSSProperties,
- size: number,
- color: string,
+ style: CSSProperties
+ size: number
+ color: string
children?: ReactNode
+ ref?: Ref
}
-export const Shape = forwardRef(({style, size, color, children}, ref) => {
+export const Shape = ({style, size, color, children, ref}: ShapeProps) => {
return (
-
+
{children}
)
-})
-
-Shape.displayName = 'Shape'
+}
export const Draggable = (): JSX.Element => {
const [_, drag] = useDrag({
@@ -35,5 +37,12 @@ export const Draggable = (): JSX.Element => {
color: '#eedd00',
},
})
- return
+ // FIXME: issue with react-dnd when using React v19
+ const refTrampoline = useCallback(
+ (node: HTMLDivElement | null) => {
+ drag(node)
+ },
+ [drag],
+ )
+ return
}
diff --git a/packages/react-dnd-preview/package.json b/packages/react-dnd-preview/package.json
index 5ed052a4..1252862e 100644
--- a/packages/react-dnd-preview/package.json
+++ b/packages/react-dnd-preview/package.json
@@ -21,7 +21,7 @@
"types": "dist/index.d.ts",
"module": "dist/index.js",
"peerDependencies": {
- "react": "^16.14.0 || ^17.0.2 || ^18.0.0",
+ "react": "^16.14.0 || ^17.0.2 || ^18.0.0 || ^19.0.0",
"react-dnd": "^16.0.1"
}
}
diff --git a/packages/react-dnd-preview/src/Preview.tsx b/packages/react-dnd-preview/src/Preview.tsx
index 891c60bb..fd34c800 100644
--- a/packages/react-dnd-preview/src/Preview.tsx
+++ b/packages/react-dnd-preview/src/Preview.tsx
@@ -1,4 +1,4 @@
-import type {ReactNode} from 'react'
+import type {JSX, ReactNode} from 'react'
import {Context, type PreviewState} from './Context'
import type {Point, PreviewPlacement} from './offsets'
import {usePreview} from './usePreview'
diff --git a/packages/react-dnd-preview/src/offsets.ts b/packages/react-dnd-preview/src/offsets.ts
index 9ed73a7d..0a4b4f95 100644
--- a/packages/react-dnd-preview/src/offsets.ts
+++ b/packages/react-dnd-preview/src/offsets.ts
@@ -69,7 +69,7 @@ const calculateYOffset = (placement: PreviewPlacement, bb: DOMRect): number => {
}
}
-export const calculatePointerPosition = (monitor: DragLayerMonitor, childRef: RefObject
, placement: PreviewPlacement = 'center', padding: Point = {x: 0, y: 0}): Point | null => {
+export const calculatePointerPosition = (monitor: DragLayerMonitor, childRef: RefObject, placement: PreviewPlacement = 'center', padding: Point = {x: 0, y: 0}): Point | null => {
const offset = monitor.getClientOffset()
if (offset === null) {
return null