Skip to content

Commit

Permalink
fix(actions/drop): fix regression with drop event targets
Browse files Browse the repository at this point in the history
Close #1016
  • Loading branch information
taye authored and interactjs-ci committed Nov 15, 2023
1 parent 88b393b commit 52ec341
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 8 deletions.
73 changes: 69 additions & 4 deletions packages/@interactjs/actions/drop/drop.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import * as helpers from '@interactjs/core/tests/_helpers'
import drop from '../drop/plugin'

describe('actions/drop', () => {
afterEach(() => {
document.body.innerHTML = ''
})

test('options', () => {
const { interactable } = helpers.testEnv({ plugins: [drop] })

Expand Down Expand Up @@ -91,13 +95,74 @@ describe('actions/drop', () => {

expect(onActionsDropStart).toHaveBeenCalledTimes(1)

// rejected dropzones are removed from activeDrops,
// rejected dropzones are removed from activeDrops
expect(interaction.dropState!.activeDrops.map((d) => d.element)).toEqual([dropEl3])

// rejected dropzones are deactivated,
expect(onDeactivate).toHaveBeenNthCalledWith(1, expect.objectContaining({ target: dropEl1 }))
expect(onDeactivate).toHaveBeenNthCalledWith(2, expect.objectContaining({ target: dropEl2 }))
// rejected dropzones are deactivated
expect(onDeactivate.mock.calls.map((arg) => arg[0].target)).toEqual([dropEl1, dropEl2])

interaction.end()
})

test('targeting', () => {
const interactionTarget = document.body.appendChild(document.createElement('div'))
interactionTarget.id = 'target'
const { scope, interactable, down, start, move, up, coords } = helpers.testEnv({
plugins: [drop],
target: interactionTarget,
})

interactable.draggable({})

const [dropElA, dropElB, dropElC] = ['a', 'b', 'c'].map((id) => {
const dropEl = scope.document.createElement('div')

dropEl.dataset.drop = id
scope.document.body.appendChild(dropEl)

return dropEl
})

const onActivate = jest.fn((event) => event.target)
const onDeactivate = jest.fn((event) => event.target)
const onDragenter = jest.fn()
const dropzone = scope.interactables
.new('[data-drop]')
.dropzone({
checker: () => true,
})
.on({ dropactivate: onActivate, dropdeactivate: onDeactivate, dragenter: onDragenter })

down()
start({ name: 'drag' })
expect(onActivate.mock.results.map(({ value }) => value)).toEqual([dropElA, dropElB, dropElC])
expect(onDeactivate.mock.calls).toEqual([])
expect(onDragenter.mock.calls).toEqual([])

coords.page.x++
move()

expect(onDragenter.mock.calls.map(([{ target, relatedTarget }]) => [target, relatedTarget])).toEqual([
[dropElC, interactionTarget],
])

onDragenter.mockClear()

// only b drop
dropzone.dropzone({
checker: (_dragEvent, _event, _dropped, _dropzone, dropElement) => dropElement.dataset.drop === 'b',
})

coords.page.x++
move()

expect(onDragenter.mock.calls.map((args) => [args[0].target, args[0].relatedTarget])).toEqual([
[dropElB, interactionTarget],
])

up()

// all dropzones are deactivated
expect(onDeactivate.mock.results.map(({ value }) => value)).toEqual([dropElA, dropElB, dropElC])
})
})
14 changes: 10 additions & 4 deletions packages/@interactjs/actions/drop/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,16 @@ function getDrop (
const validDrops: Element[] = []

// collect all dropzones and their elements which qualify for a drop
for (const { dropzone, element: dropzoneElement, rect } of dropState!.activeDrops) {
if (dropzone.dropCheck(dragEvent, pointerEvent, draggable!, dragElement!, dropzoneElement, rect)) {
validDrops.push(dropzoneElement)
}
for (const { dropzone, element: dropzoneElement, rect } of dropState.activeDrops) {
const isValid = dropzone.dropCheck(
dragEvent,
pointerEvent,
draggable!,
dragElement!,
dropzoneElement,
rect,
)
validDrops.push(isValid ? dropzoneElement : null)
}

// get the most appropriate dropzone based on DOM depth and order
Expand Down

0 comments on commit 52ec341

Please sign in to comment.