diff --git a/packages/actions/drop/index.ts b/packages/actions/drop/index.ts index 6bf1dcad1..7a782138a 100644 --- a/packages/actions/drop/index.ts +++ b/packages/actions/drop/index.ts @@ -133,13 +133,15 @@ function install (scope: Scope) { const { dropState } = interaction - dropState.activeDrops = null - dropState.events = null - dropState.cur.dropzone = null - dropState.cur.element = null - dropState.prev.dropzone = null - dropState.prev.element = null - dropState.rejected = false + if (dropState) { + dropState.activeDrops = null + dropState.events = null + dropState.cur.dropzone = null + dropState.cur.element = null + dropState.prev.dropzone = null + dropState.prev.element = null + dropState.rejected = false + } }) /** diff --git a/packages/auto-scroll/index.ts b/packages/auto-scroll/index.ts index ae3cd790e..3b6cb7d2b 100644 --- a/packages/auto-scroll/index.ts +++ b/packages/auto-scroll/index.ts @@ -38,6 +38,14 @@ function install (scope: Scope) { interaction.autoScroll = null }) + interactions.signals.on('destroy', ({ interaction }) => { + interaction.autoScroll = null + autoScroll.stop() + if (autoScroll.interaction) { + autoScroll.interaction = null + } + }) + interactions.signals.on('stop', autoScroll.stop) interactions.signals.on('action-move', (arg: any) => autoScroll.onInteractionMove(arg)) diff --git a/packages/core/Interactable.spec.ts b/packages/core/Interactable.spec.ts index 99d845539..0c4cff35f 100644 --- a/packages/core/Interactable.spec.ts +++ b/packages/core/Interactable.spec.ts @@ -36,6 +36,28 @@ test('Interactable copies and extends defaults', (t) => { t.end() }) +test('Interactable unset correctly', (t) => { + const scope = helpers.mockScope() as any + + const div = d('div') + const interactable = scope.interactables.new(div) + + const mappingInfo = div[scope.id][0] + + scope.interactables.signals.fire('unset', { interactable }) + + t.strictEqual(mappingInfo.context, null, + 'unset mappingInfo context') + + t.strictEqual(mappingInfo.interactable, null, + 'unset mappingInfo interactable') + + t.strictEqual(div[scope.id].length, 0, + 'unset target are removed') + + t.end() +}) + test('Interactable copies and extends per action defaults', (t) => { const scope = helpers.mockScope() const { defaults } = scope diff --git a/packages/core/InteractableSet.ts b/packages/core/InteractableSet.ts index 1f3e8f0f9..a610271b4 100644 --- a/packages/core/InteractableSet.ts +++ b/packages/core/InteractableSet.ts @@ -21,7 +21,13 @@ export default class InteractableSet { ? this.selectorMap[target] : target[this.scope.id] - targetMappings.splice(targetMappings.findIndex((m) => m.context === context), 1) + const targetIndex = targetMappings.findIndex((m) => m.context === context) + if (targetMappings[targetIndex]) { + // Destroying mappingInfo's context and interactable + targetMappings[targetIndex].context = null + targetMappings[targetIndex].interactable = null + } + targetMappings.splice(targetIndex, 1) }) } diff --git a/packages/core/Interaction.spec.ts b/packages/core/Interaction.spec.ts index d3aa87a2b..2551ebb76 100644 --- a/packages/core/Interaction.spec.ts +++ b/packages/core/Interaction.spec.ts @@ -30,7 +30,7 @@ test('Interaction constructor', (t) => { for (const coordField in interaction.coords) { t.deepEqual(interaction.coords[coordField], zeroCoords, - `nteraction.coords.${coordField} set to zero`) + `interaction.coords.${coordField} set to zero`) } t.equal(interaction.pointerType, testType, @@ -50,6 +50,27 @@ test('Interaction constructor', (t) => { t.end() }) +test('Interaction destroy', (t) => { + const interaction = makeInteractionAndSignals() + const pointer = { pointerId: 10 } as any + const event = {} as any + + interaction.updatePointer(pointer, event, null) + + interaction.destroy() + + t.strictEqual(interaction._latestPointer.pointer, null, + 'interaction._latestPointer.pointer is null') + + t.strictEqual(interaction._latestPointer.event, null, + 'interaction._latestPointer.event is null') + + t.strictEqual(interaction._latestPointer.eventTarget, null, + 'interaction._latestPointer.eventTarget is null') + + t.end() +}) + test('Interaction.getPointerIndex', (t) => { const interaction = makeInteractionAndSignals() diff --git a/packages/core/Interaction.ts b/packages/core/Interaction.ts index df0adda5a..7ac473f13 100644 --- a/packages/core/Interaction.ts +++ b/packages/core/Interaction.ts @@ -468,6 +468,12 @@ export class Interaction { this._latestPointer.eventTarget = eventTarget } + destroy () { + this._latestPointer.pointer = null + this._latestPointer.event = null + this._latestPointer.eventTarget = null + } + _createPreparedEvent (event: Interact.PointerEventType, phase: EventPhase, preEnd: boolean, type: string) { const actionName = this.prepared.name diff --git a/packages/core/scope.ts b/packages/core/scope.ts index bb052aca2..58bb4cdf5 100644 --- a/packages/core/scope.ts +++ b/packages/core/scope.ts @@ -92,8 +92,12 @@ export class Scope { if (interaction.interactable === this) { interaction.stop() } + scope.interactions.signals.fire('destroy', { interaction }) + interaction.destroy() } + scope.interactions.list = [] + scope.interactables.signals.fire('unset', { interactable: this }) } } diff --git a/packages/interact/interact.spec.ts b/packages/interact/interact.spec.ts index 318ba125c..64cc2d437 100644 --- a/packages/interact/interact.spec.ts +++ b/packages/interact/interact.spec.ts @@ -16,6 +16,8 @@ test('interact export', (t) => { interactable1.unset() t.equal(scope.interactables.list.length, 0, 'unset interactables are removed') + t.strictEqual(scope.interactions.list.length, 0, + 'unset interactions are removed') const constructsUniqueMessage = 'unique contexts make unique interactables with identical targets' diff --git a/scripts/test.sh b/scripts/test.sh index e8b0d3435..3ffa03f90 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,5 +1,9 @@ #!/bin/bash PKG_DIR=$(dirname $(dirname $(readlink -f $0))) +if [ -z "$PKG_DIR" ] +then + PKG_DIR=$(dirname $(dirname $0)) +fi export PATH=$PKG_DIR/node_modules/.bin:$PWD/node_modules/.bin:$PATH export NODE_ENV=test