Skip to content

Commit

Permalink
Support for tolerance in DistanceConstraint (#399)
Browse files Browse the repository at this point in the history
Co-authored-by: Claudéric Demers <clauderic.d@gmail.com>
  • Loading branch information
supersebh and clauderic authored Aug 23, 2021
1 parent 2ba6dfe commit a32a4c5
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .changeset/distance-constraint-tolerance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
"@dnd-kit/core": minor
---

Added support for `tolerance` in DistanceConstrain. As soon as the `tolerance` is exceeded, the drag operation will be aborted, unless it has already started (because distance criteria was met).

Example usage:

```
// Require the pointer be moved by 10 pixels vertically to initiate drag operation
// Abort if the pointer is moved by more than 5 pixels horizontally.
{
distance: {y: 10},
tolerance: {x: 5},
}
```

Be careful not to pick conflicting settings for distance and tolerance if used together. For example, picking a tolerance that is lower than the distance in the same axis would result in the activation constraint never being met.


60 changes: 60 additions & 0 deletions cypress/integration/draggable_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,5 +347,65 @@ describe('Draggable', () => {
return subject;
});
});

it('Activates if the mouse is moved more than the minimum distance x and less than tolerance y', () => {
const deltaX = 100;
const deltaY = 5;

cy.visitStory('core-draggable-hooks-usedraggable--minimum-distance-x-tolerance-y')
.findFirstDraggableItem()
.mouseMoveBy(deltaX, deltaY)
.then(([subject, {delta}]) => {
expect(delta.x).eq(deltaX);
expect(delta.y).eq(deltaY);

return subject;
});
});

it('Does not activate if the mouse is moved more than the minimum distance x and more than tolerance y', () => {
const deltaX = 100;
const deltaY = 150;

cy.visitStory('core-draggable-hooks-usedraggable--minimum-distance-x-tolerance-y')
.findFirstDraggableItem()
.mouseMoveBy(deltaX, deltaY)
.then(([subject, {delta}]) => {
expect(delta.x).eq(0);
expect(delta.y).eq(0);

return subject;
});
});

it('Activates if the mouse is moved more than the minimum distance y and less than tolerance x', () => {
const deltaX = 5;
const deltaY = 100;

cy.visitStory('core-draggable-hooks-usedraggable--minimum-distance-y-tolerance-x')
.findFirstDraggableItem()
.mouseMoveBy(deltaX, deltaY)
.then(([subject, {delta}]) => {
expect(delta.x).eq(deltaX);
expect(delta.y).eq(deltaY);

return subject;
});
});

it('Does not activate if the mouse is moved more than the minimum distance y and more than tolerance x', () => {
const deltaX = 150;
const deltaY = 100;

cy.visitStory('core-draggable-hooks-usedraggable--minimum-distance-y-tolerance-x')
.findFirstDraggableItem()
.mouseMoveBy(deltaX, deltaY)
.then(([subject, {delta}]) => {
expect(delta.x).eq(0);
expect(delta.y).eq(0);

return subject;
});
});
});
});
7 changes: 7 additions & 0 deletions packages/core/src/sensors/pointer/AbstractPointerSensor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {Coordinates, DistanceMeasurement} from '../../types';

interface DistanceConstraint {
distance: DistanceMeasurement;
tolerance?: DistanceMeasurement;
}

interface DelayConstraint {
Expand Down Expand Up @@ -172,6 +173,12 @@ export class AbstractPointerSensor implements SensorInstance {
}

if (isDistanceConstraint(activationConstraint)) {
if (
activationConstraint.tolerance != null &&
hasExceededDistance(delta, activationConstraint.tolerance)
) {
return this.handleCancel();
}
if (hasExceededDistance(delta, activationConstraint.distance)) {
return this.handleStart();
}
Expand Down
24 changes: 24 additions & 0 deletions stories/1 - Core/Draggable/1-Draggable.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,30 @@ export const MinimumDistanceXY = () => (

MinimumDistanceXY.storyName = 'Minimum Distance – X&Y Axis';

export const MinimumDistanceXToleranceY = () => (
<DraggableStory
label="I'm activated after dragging 15px on the x axis and aborted after dragging 30px on the y axis"
activationConstraint={{
distance: {x: 15},
tolerance: {y: 30},
}}
/>
);

MinimumDistanceXToleranceY.storyName = 'Minimum Distance X Axis and Tolerance Y Axis';

export const MinimumDistanceYToleranceX = () => (
<DraggableStory
label="I'm activated after dragging 15px on the y axis and aborted after dragging 30px on the x axis"
activationConstraint={{
distance: {y: 15},
tolerance: {x: 30},
}}
/>
);

MinimumDistanceYToleranceX.storyName = 'Minimum Distance Y Axis and Tolerance X Axis';

export const HorizontalAxis = () => (
<DraggableStory
label="Draggable horizontally"
Expand Down

0 comments on commit a32a4c5

Please sign in to comment.