Skip to content

Commit f42b7c7

Browse files
committed
feat: track canvas dragEnter & dragLeave (WIP)
1 parent ab76b39 commit f42b7c7

File tree

4 files changed

+97
-12
lines changed

4 files changed

+97
-12
lines changed

example/src/demos/FileDragDrop.tsx

+10-3
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,21 @@ export default function Box() {
2424
return (
2525
<Canvas
2626
{...preventDragDropDefaults}
27-
onDropMissed={(e) => console.log('drop missed!')}
28-
onDragOverMissed={(e) => setActiveBg(1)}>
27+
onDropMissed={(e) => {
28+
console.log('drop missed!')
29+
setActiveBg(0)
30+
}}
31+
onDragOverMissed={(e) => setActiveBg(1)}
32+
onDragLeave={() => setActiveBg(0)}>
2933
<color attach="background" args={[bgColor]} />
3034
<a.mesh
3135
rotation-y={rotation}
3236
scale-x={scale}
3337
scale-z={scale}
34-
onDrop={(e) => console.log('dropped!', e)}
38+
onDrop={(e) => {
39+
console.log('dropped!')
40+
setActive(0)
41+
}}
3542
onDragOverEnter={() => {
3643
setActive(1)
3744
setActiveBg(0)

packages/fiber/src/core/events.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,12 @@ export type Events = {
4141
onClick: EventListener
4242
onContextMenu: EventListener
4343
onDoubleClick: EventListener
44+
onDragEnter: EventListener
45+
onDragLeave: EventListener
4446
onDragOverEnter: EventListener
4547
onDragOverLeave: EventListener
4648
onDrop: EventListener
49+
onDropMissed: EventListener
4750
onWheel: EventListener
4851
onPointerDown: EventListener
4952
onPointerUp: EventListener
@@ -57,6 +60,8 @@ export type EventHandlers = {
5760
onClick?: (event: ThreeEvent<MouseEvent>) => void
5861
onContextMenu?: (event: ThreeEvent<MouseEvent>) => void
5962
onDoubleClick?: (event: ThreeEvent<MouseEvent>) => void
63+
onDragEnter?: (event: ThreeEvent<DragEvent>) => void
64+
onDragLeave?: (event: ThreeEvent<DragEvent>) => void
6065
onDragOverEnter?: (event: ThreeEvent<DragEvent>) => void
6166
onDragOverLeave?: (event: ThreeEvent<DragEvent>) => void
6267
onDragOverMissed?: (event: DragEvent) => void
@@ -113,6 +118,8 @@ export function getEventPriority() {
113118
case 'click':
114119
case 'contextmenu':
115120
case 'dblclick':
121+
case 'dragenter':
122+
case 'dragleave':
116123
case 'drop':
117124
case 'pointercancel':
118125
case 'pointerdown':
@@ -186,7 +193,9 @@ export function createEvents(store: UseBoundStore<RootState>) {
186193
['Move', 'Over', 'Enter', 'Out', 'Leave'].some(
187194
(name) => (obj as unknown as Instance).__r3f?.handlers[('onPointer' + name) as keyof EventHandlers],
188195
) ||
189-
['Over'].some((name) => (obj as unknown as Instance).__r3f?.handlers[('onDrag' + name) as keyof EventHandlers]),
196+
['Over', 'Enter', 'Leave'].some(
197+
(name) => (obj as unknown as Instance).__r3f?.handlers[('onDrag' + name) as keyof EventHandlers],
198+
),
190199
)
191200
}
192201

@@ -401,6 +410,7 @@ export function createEvents(store: UseBoundStore<RootState>) {
401410
switch (name) {
402411
case 'onPointerLeave':
403412
case 'onPointerCancel':
413+
case 'onDragLeave':
404414
return () => cancelPointer([])
405415
case 'onLostPointerCapture':
406416
return (event: DomEvent) => {
@@ -423,7 +433,7 @@ export function createEvents(store: UseBoundStore<RootState>) {
423433

424434
// Get fresh intersects
425435
const isPointerMove = name === 'onPointerMove'
426-
const isDragOver = name === 'onDragOverEnter' || name === 'onDragOverLeave'
436+
const isDragOver = name === 'onDragOver'
427437
const isDrop = name === 'onDrop'
428438
const isClickEvent = name === 'onClick' || name === 'onContextMenu' || name === 'onDoubleClick'
429439
const filter = isPointerMove ? filterPointerEvents : undefined

packages/fiber/src/web/events.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ const DOM_EVENTS = {
66
onClick: ['click', false],
77
onContextMenu: ['contextmenu', false],
88
onDoubleClick: ['dblclick', false],
9-
onDragOverEnter: ['dragover', false],
10-
onDragOverLeave: ['dragover', false],
9+
onDragEnter: ['dragenter', false],
10+
onDragLeave: ['dragleave', false],
11+
onDragOver: ['dragover', false],
1112
onDrop: ['drop', false],
1213
onWheel: ['wheel', true],
1314
onPointerDown: ['pointerdown', true],

packages/fiber/tests/core/events.test.tsx

+72-5
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ describe('events', () => {
210210
expect(handlePointerOut).toHaveBeenCalled()
211211
})
212212

213-
it('can handle onDragOverEnter & onDragOverLeave', async () => {
213+
it('can handle dragover events via onDragOverEnter & onDragOverLeave', async () => {
214214
const handleDragOverEnter = jest.fn()
215215
const handleDragOverLeave = jest.fn()
216216

@@ -226,7 +226,6 @@ describe('events', () => {
226226
})
227227

228228
// Note: DragEvent is not implemented in jsdom yet: https://github.com/jsdom/jsdom/issues/2913
229-
// https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
230229
// however, @react-testing/library does simulate it
231230
let evt = createEvent.dragOver(getContainer())
232231
//@ts-ignore
@@ -248,12 +247,80 @@ describe('events', () => {
248247
expect(handleDragOverLeave).toHaveBeenCalled()
249248
})
250249

251-
it('can handle onDrop', async () => {
250+
it('can handle onDragOverMissed', async () => {
251+
const handleDragOverMissed = jest.fn()
252+
253+
await act(async () => {
254+
render(
255+
<Canvas onDragOverMissed={handleDragOverMissed}>
256+
<mesh>
257+
<boxGeometry args={[2, 2]} />
258+
<meshBasicMaterial />
259+
</mesh>
260+
</Canvas>,
261+
)
262+
})
263+
264+
// Note: DragEvent is not implemented in jsdom yet: https://github.com/jsdom/jsdom/issues/2913
265+
// https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
266+
// however, @react-testing/library does simulate it
267+
let evt = createEvent.dragOver(getContainer())
268+
//@ts-ignore
269+
evt.offsetX = 1
270+
//@ts-ignore
271+
evt.offsetY = 1
272+
273+
fireEvent(getContainer(), evt)
274+
275+
expect(handleDragOverMissed).toHaveBeenCalled()
276+
})
277+
278+
it('can handle onDragEnter & onDragLeave', async () => {
279+
const handleDragEnter = jest.fn()
280+
const handleDragLeave = jest.fn()
281+
282+
await act(async () => {
283+
render(
284+
<Canvas onDragEnter={handleDragEnter} onDragLeave={handleDragLeave}>
285+
<mesh>
286+
<boxGeometry args={[2, 2]} />
287+
<meshBasicMaterial />
288+
</mesh>
289+
</Canvas>,
290+
)
291+
})
292+
293+
// Note: DragEvent is not implemented in jsdom yet: https://github.com/jsdom/jsdom/issues/2913
294+
// https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
295+
// however, @react-testing/library does simulate it
296+
let evt = createEvent.dragEnter(getContainer())
297+
//@ts-ignore
298+
evt.offsetX = 10
299+
//@ts-ignore
300+
evt.offsetY = 10
301+
302+
fireEvent(getContainer(), evt)
303+
304+
expect(handleDragEnter).toHaveBeenCalled()
305+
306+
evt = createEvent.dragLeave(getContainer())
307+
//@ts-ignore
308+
evt.offsetX = 0
309+
//@ts-ignore
310+
evt.offsetY = 0
311+
312+
fireEvent(getContainer(), evt)
313+
314+
expect(handleDragLeave).toHaveBeenCalled()
315+
})
316+
317+
it('can handle onDrop & onDropMissed', async () => {
252318
const handleOnDrop = jest.fn()
319+
const handleOnDropMissed = jest.fn()
253320

254321
await act(async () => {
255322
render(
256-
<Canvas>
323+
<Canvas onDropMissed={handleOnDropMissed}>
257324
<mesh onDrop={handleOnDrop}>
258325
<boxGeometry args={[2, 2]} />
259326
<meshBasicMaterial />
@@ -263,7 +330,6 @@ describe('events', () => {
263330
})
264331

265332
// Note: DragEvent is not implemented in jsdom yet: https://github.com/jsdom/jsdom/issues/2913
266-
// https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
267333
// however, @react-testing/library does simulate it
268334
let evt = createEvent.drop(getContainer())
269335
//@ts-ignore
@@ -284,6 +350,7 @@ describe('events', () => {
284350

285351
// second event shouldn't register
286352
expect(handleOnDrop).toHaveBeenCalledTimes(1)
353+
expect(handleOnDropMissed).toHaveBeenCalled()
287354
})
288355

289356
it('should handle stopPropagation', async () => {

0 commit comments

Comments
 (0)