Skip to content

Commit

Permalink
feat: track canvas dragEnter & dragLeave (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
haywirez committed Jul 20, 2022
1 parent ab76b39 commit f42b7c7
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 12 deletions.
13 changes: 10 additions & 3 deletions example/src/demos/FileDragDrop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,21 @@ export default function Box() {
return (
<Canvas
{...preventDragDropDefaults}
onDropMissed={(e) => console.log('drop missed!')}
onDragOverMissed={(e) => setActiveBg(1)}>
onDropMissed={(e) => {
console.log('drop missed!')
setActiveBg(0)
}}
onDragOverMissed={(e) => setActiveBg(1)}
onDragLeave={() => setActiveBg(0)}>
<color attach="background" args={[bgColor]} />
<a.mesh
rotation-y={rotation}
scale-x={scale}
scale-z={scale}
onDrop={(e) => console.log('dropped!', e)}
onDrop={(e) => {
console.log('dropped!')
setActive(0)
}}
onDragOverEnter={() => {
setActive(1)
setActiveBg(0)
Expand Down
14 changes: 12 additions & 2 deletions packages/fiber/src/core/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ export type Events = {
onClick: EventListener
onContextMenu: EventListener
onDoubleClick: EventListener
onDragEnter: EventListener
onDragLeave: EventListener
onDragOverEnter: EventListener
onDragOverLeave: EventListener
onDrop: EventListener
onDropMissed: EventListener
onWheel: EventListener
onPointerDown: EventListener
onPointerUp: EventListener
Expand All @@ -57,6 +60,8 @@ export type EventHandlers = {
onClick?: (event: ThreeEvent<MouseEvent>) => void
onContextMenu?: (event: ThreeEvent<MouseEvent>) => void
onDoubleClick?: (event: ThreeEvent<MouseEvent>) => void
onDragEnter?: (event: ThreeEvent<DragEvent>) => void
onDragLeave?: (event: ThreeEvent<DragEvent>) => void
onDragOverEnter?: (event: ThreeEvent<DragEvent>) => void
onDragOverLeave?: (event: ThreeEvent<DragEvent>) => void
onDragOverMissed?: (event: DragEvent) => void
Expand Down Expand Up @@ -113,6 +118,8 @@ export function getEventPriority() {
case 'click':
case 'contextmenu':
case 'dblclick':
case 'dragenter':
case 'dragleave':
case 'drop':
case 'pointercancel':
case 'pointerdown':
Expand Down Expand Up @@ -186,7 +193,9 @@ export function createEvents(store: UseBoundStore<RootState>) {
['Move', 'Over', 'Enter', 'Out', 'Leave'].some(
(name) => (obj as unknown as Instance).__r3f?.handlers[('onPointer' + name) as keyof EventHandlers],
) ||
['Over'].some((name) => (obj as unknown as Instance).__r3f?.handlers[('onDrag' + name) as keyof EventHandlers]),
['Over', 'Enter', 'Leave'].some(
(name) => (obj as unknown as Instance).__r3f?.handlers[('onDrag' + name) as keyof EventHandlers],
),
)
}

Expand Down Expand Up @@ -401,6 +410,7 @@ export function createEvents(store: UseBoundStore<RootState>) {
switch (name) {
case 'onPointerLeave':
case 'onPointerCancel':
case 'onDragLeave':
return () => cancelPointer([])
case 'onLostPointerCapture':
return (event: DomEvent) => {
Expand All @@ -423,7 +433,7 @@ export function createEvents(store: UseBoundStore<RootState>) {

// Get fresh intersects
const isPointerMove = name === 'onPointerMove'
const isDragOver = name === 'onDragOverEnter' || name === 'onDragOverLeave'
const isDragOver = name === 'onDragOver'
const isDrop = name === 'onDrop'
const isClickEvent = name === 'onClick' || name === 'onContextMenu' || name === 'onDoubleClick'
const filter = isPointerMove ? filterPointerEvents : undefined
Expand Down
5 changes: 3 additions & 2 deletions packages/fiber/src/web/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ const DOM_EVENTS = {
onClick: ['click', false],
onContextMenu: ['contextmenu', false],
onDoubleClick: ['dblclick', false],
onDragOverEnter: ['dragover', false],
onDragOverLeave: ['dragover', false],
onDragEnter: ['dragenter', false],
onDragLeave: ['dragleave', false],
onDragOver: ['dragover', false],
onDrop: ['drop', false],
onWheel: ['wheel', true],
onPointerDown: ['pointerdown', true],
Expand Down
77 changes: 72 additions & 5 deletions packages/fiber/tests/core/events.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ describe('events', () => {
expect(handlePointerOut).toHaveBeenCalled()
})

it('can handle onDragOverEnter & onDragOverLeave', async () => {
it('can handle dragover events via onDragOverEnter & onDragOverLeave', async () => {
const handleDragOverEnter = jest.fn()
const handleDragOverLeave = jest.fn()

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

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

it('can handle onDrop', async () => {
it('can handle onDragOverMissed', async () => {
const handleDragOverMissed = jest.fn()

await act(async () => {
render(
<Canvas onDragOverMissed={handleDragOverMissed}>
<mesh>
<boxGeometry args={[2, 2]} />
<meshBasicMaterial />
</mesh>
</Canvas>,
)
})

// Note: DragEvent is not implemented in jsdom yet: https://github.com/jsdom/jsdom/issues/2913
// https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
// however, @react-testing/library does simulate it
let evt = createEvent.dragOver(getContainer())
//@ts-ignore
evt.offsetX = 1
//@ts-ignore
evt.offsetY = 1

fireEvent(getContainer(), evt)

expect(handleDragOverMissed).toHaveBeenCalled()
})

it('can handle onDragEnter & onDragLeave', async () => {
const handleDragEnter = jest.fn()
const handleDragLeave = jest.fn()

await act(async () => {
render(
<Canvas onDragEnter={handleDragEnter} onDragLeave={handleDragLeave}>
<mesh>
<boxGeometry args={[2, 2]} />
<meshBasicMaterial />
</mesh>
</Canvas>,
)
})

// Note: DragEvent is not implemented in jsdom yet: https://github.com/jsdom/jsdom/issues/2913
// https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
// however, @react-testing/library does simulate it
let evt = createEvent.dragEnter(getContainer())
//@ts-ignore
evt.offsetX = 10
//@ts-ignore
evt.offsetY = 10

fireEvent(getContainer(), evt)

expect(handleDragEnter).toHaveBeenCalled()

evt = createEvent.dragLeave(getContainer())
//@ts-ignore
evt.offsetX = 0
//@ts-ignore
evt.offsetY = 0

fireEvent(getContainer(), evt)

expect(handleDragLeave).toHaveBeenCalled()
})

it('can handle onDrop & onDropMissed', async () => {
const handleOnDrop = jest.fn()
const handleOnDropMissed = jest.fn()

await act(async () => {
render(
<Canvas>
<Canvas onDropMissed={handleOnDropMissed}>
<mesh onDrop={handleOnDrop}>
<boxGeometry args={[2, 2]} />
<meshBasicMaterial />
Expand All @@ -263,7 +330,6 @@ describe('events', () => {
})

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

// second event shouldn't register
expect(handleOnDrop).toHaveBeenCalledTimes(1)
expect(handleOnDropMissed).toHaveBeenCalled()
})

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

0 comments on commit f42b7c7

Please sign in to comment.