Skip to content

Commit b417f0f

Browse files
authored
Allow delay and distance constraints to be combined (#1269)
1 parent 62b3446 commit b417f0f

File tree

3 files changed

+44
-26
lines changed

3 files changed

+44
-26
lines changed

.changeset/delay-or-distance.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@dnd-kit/core': minor
3+
---
4+
5+
Allow `delay` and `distance` activation constraints to be used concurrently for `MouseSensor`, `TouchSensor` and `PointerSensor`.

packages/core/src/sensors/pointer/AbstractPointerSensor.ts

+20-17
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,14 @@ export interface PointerEventHandlers {
3636
end: EventDescriptor;
3737
}
3838

39-
export type PointerActivationConstraint = DistanceConstraint | DelayConstraint;
39+
export type PointerActivationConstraint =
40+
| DelayConstraint
41+
| DistanceConstraint
42+
| (DelayConstraint & DistanceConstraint);
4043

4144
function isDistanceConstraint(
4245
constraint: PointerActivationConstraint
43-
): constraint is DistanceConstraint {
46+
): constraint is PointerActivationConstraint & DistanceConstraint {
4447
return Boolean(constraint && 'distance' in constraint);
4548
}
4649

@@ -55,7 +58,8 @@ export interface AbstractPointerSensorOptions extends SensorOptions {
5558
onActivation?({event}: {event: Event}): void;
5659
}
5760

58-
export type AbstractPointerSensorProps = SensorProps<AbstractPointerSensorOptions>;
61+
export type AbstractPointerSensorProps =
62+
SensorProps<AbstractPointerSensorOptions>;
5963

6064
export class AbstractPointerSensor implements SensorInstance {
6165
public autoScrollEnabled = true;
@@ -109,17 +113,17 @@ export class AbstractPointerSensor implements SensorInstance {
109113
this.documentListeners.add(EventName.Keydown, this.handleKeydown);
110114

111115
if (activationConstraint) {
112-
if (isDistanceConstraint(activationConstraint)) {
113-
return;
114-
}
115-
116116
if (isDelayConstraint(activationConstraint)) {
117117
this.timeoutId = setTimeout(
118118
this.handleStart,
119119
activationConstraint.delay
120120
);
121121
return;
122122
}
123+
124+
if (isDistanceConstraint(activationConstraint)) {
125+
return;
126+
}
123127
}
124128

125129
this.handleStart();
@@ -178,29 +182,28 @@ export class AbstractPointerSensor implements SensorInstance {
178182
const coordinates = getEventCoordinates(event) ?? defaultCoordinates;
179183
const delta = getCoordinatesDelta(initialCoordinates, coordinates);
180184

185+
// Constraint validation
181186
if (!activated && activationConstraint) {
182-
// Constraint validation
183-
if (isDelayConstraint(activationConstraint)) {
184-
if (hasExceededDistance(delta, activationConstraint.tolerance)) {
185-
return this.handleCancel();
186-
}
187-
188-
return;
189-
}
190-
191187
if (isDistanceConstraint(activationConstraint)) {
192188
if (
193189
activationConstraint.tolerance != null &&
194190
hasExceededDistance(delta, activationConstraint.tolerance)
195191
) {
196192
return this.handleCancel();
197193
}
194+
198195
if (hasExceededDistance(delta, activationConstraint.distance)) {
199196
return this.handleStart();
200197
}
198+
}
201199

202-
return;
200+
if (isDelayConstraint(activationConstraint)) {
201+
if (hasExceededDistance(delta, activationConstraint.tolerance)) {
202+
return this.handleCancel();
203+
}
203204
}
205+
206+
return;
204207
}
205208

206209
if (event.cancelable) {

stories/1 - Core/Draggable/1-Draggable.story.tsx

+19-9
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,10 @@ function DraggableItem({
112112
handle,
113113
buttonStyle,
114114
}: DraggableItemProps) {
115-
const {
116-
attributes,
117-
isDragging,
118-
listeners,
119-
setNodeRef,
120-
transform,
121-
} = useDraggable({
122-
id: 'draggable',
123-
});
115+
const {attributes, isDragging, listeners, setNodeRef, transform} =
116+
useDraggable({
117+
id: 'draggable',
118+
});
124119

125120
return (
126121
<Draggable
@@ -154,6 +149,21 @@ export const PressDelay = () => (
154149
/>
155150
);
156151

152+
PressDelay.storyName = 'Press delay';
153+
154+
export const PressDelayOrDistance = () => (
155+
<DraggableStory
156+
label="Activated dragging 3px or holding 250ms"
157+
activationConstraint={{
158+
delay: 250,
159+
distance: 3,
160+
tolerance: 10,
161+
}}
162+
/>
163+
);
164+
165+
PressDelayOrDistance.storyName = 'Press delay or minimum distance';
166+
157167
export const MinimumDistance = () => (
158168
<DraggableStory
159169
label="I'm activated after dragging 15px"

0 commit comments

Comments
 (0)