diff --git a/.changeset/delay-or-distance.md b/.changeset/delay-or-distance.md new file mode 100644 index 00000000..a6ecb110 --- /dev/null +++ b/.changeset/delay-or-distance.md @@ -0,0 +1,5 @@ +--- +'@dnd-kit/core': minor +--- + +Allow `delay` and `distance` activation constraints to be used concurrently for `MouseSensor`, `TouchSensor` and `PointerSensor`. diff --git a/packages/core/src/sensors/pointer/AbstractPointerSensor.ts b/packages/core/src/sensors/pointer/AbstractPointerSensor.ts index f566f96e..3f87cd55 100644 --- a/packages/core/src/sensors/pointer/AbstractPointerSensor.ts +++ b/packages/core/src/sensors/pointer/AbstractPointerSensor.ts @@ -36,11 +36,14 @@ export interface PointerEventHandlers { end: EventDescriptor; } -export type PointerActivationConstraint = DistanceConstraint | DelayConstraint; +export type PointerActivationConstraint = + | DelayConstraint + | DistanceConstraint + | (DelayConstraint & DistanceConstraint); function isDistanceConstraint( constraint: PointerActivationConstraint -): constraint is DistanceConstraint { +): constraint is PointerActivationConstraint & DistanceConstraint { return Boolean(constraint && 'distance' in constraint); } @@ -55,7 +58,8 @@ export interface AbstractPointerSensorOptions extends SensorOptions { onActivation?({event}: {event: Event}): void; } -export type AbstractPointerSensorProps = SensorProps; +export type AbstractPointerSensorProps = + SensorProps; export class AbstractPointerSensor implements SensorInstance { public autoScrollEnabled = true; @@ -109,10 +113,6 @@ export class AbstractPointerSensor implements SensorInstance { this.documentListeners.add(EventName.Keydown, this.handleKeydown); if (activationConstraint) { - if (isDistanceConstraint(activationConstraint)) { - return; - } - if (isDelayConstraint(activationConstraint)) { this.timeoutId = setTimeout( this.handleStart, @@ -120,6 +120,10 @@ export class AbstractPointerSensor implements SensorInstance { ); return; } + + if (isDistanceConstraint(activationConstraint)) { + return; + } } this.handleStart(); @@ -178,16 +182,8 @@ export class AbstractPointerSensor implements SensorInstance { const coordinates = getEventCoordinates(event) ?? defaultCoordinates; const delta = getCoordinatesDelta(initialCoordinates, coordinates); + // Constraint validation if (!activated && activationConstraint) { - // Constraint validation - if (isDelayConstraint(activationConstraint)) { - if (hasExceededDistance(delta, activationConstraint.tolerance)) { - return this.handleCancel(); - } - - return; - } - if (isDistanceConstraint(activationConstraint)) { if ( activationConstraint.tolerance != null && @@ -195,12 +191,19 @@ export class AbstractPointerSensor implements SensorInstance { ) { return this.handleCancel(); } + if (hasExceededDistance(delta, activationConstraint.distance)) { return this.handleStart(); } + } - return; + if (isDelayConstraint(activationConstraint)) { + if (hasExceededDistance(delta, activationConstraint.tolerance)) { + return this.handleCancel(); + } } + + return; } if (event.cancelable) { diff --git a/stories/1 - Core/Draggable/1-Draggable.story.tsx b/stories/1 - Core/Draggable/1-Draggable.story.tsx index c62dc8ca..fc002194 100644 --- a/stories/1 - Core/Draggable/1-Draggable.story.tsx +++ b/stories/1 - Core/Draggable/1-Draggable.story.tsx @@ -112,15 +112,10 @@ function DraggableItem({ handle, buttonStyle, }: DraggableItemProps) { - const { - attributes, - isDragging, - listeners, - setNodeRef, - transform, - } = useDraggable({ - id: 'draggable', - }); + const {attributes, isDragging, listeners, setNodeRef, transform} = + useDraggable({ + id: 'draggable', + }); return ( ( /> ); +PressDelay.storyName = 'Press delay'; + +export const PressDelayOrDistance = () => ( + +); + +PressDelayOrDistance.storyName = 'Press delay or minimum distance'; + export const MinimumDistance = () => (