dnd-kit icon indicating copy to clipboard operation
dnd-kit copied to clipboard

Proposal: add a SensorOptions property to facilitate disabling drag on interactive elements

Open ChristopherChudzicki opened this issue 2 years ago • 2 comments

Problem

Sometimes it is useful to make an entire element draggable, except interactive child elements.

Current Solution: As discussed in https://github.com/clauderic/dnd-kit/issues/477, a current solution to this issue is a custom sensor extending PointerSensor and overriding its activators. This has some downsides: (1) it's a little hard to discover as a library user, (2) if the PointerSensor's activators are updated in future releases, custom classes that override its activators won't benefit from those updates; (3) while not too hard, creating a custom sensor for this seems like a lot of code.

Other Libraries: For comparison, some other drag libraries include this behavior by default. For example, react-beautiful-dnd automatically prevents drag on interactive child elements: Interactive child elements within a <Draggable />

Proposal:

Add some sort of sensor option to determine whether an element is draggable or not, something like

interface PointerSensorOptions {
  /**
   * Invoked with the target of `pointerdown` event. If returns `false`, drag
   * events will not be emitted.
   */
  isDraggableElement?: (element: HTMLElement) => boolean;
  /** ...existing options */
}

Omitted isDraggableElement in the sensor options would be equivalent to passing () => true (all elements draggable).

Additionally, dnd-kit could then export a helper like isNotInteractiveElement, or leave that to userland. (Writing a isNotInteractiveElement predicate is much simpler than writing your own sensor, so leaving that for userland seems OK.)

Questions

  1. @clauderic Would you be open to this additional option, or something similar? I'd be happy to make a PR for it.
  2. If yes, would PointerSensor actually be the right place, or would this be suitable for all sensors?
  3. This seems like an activationConstraint... Is it? On the other hand, those seem to be mutually exclusive, and providing isDraggableElement should not preclude using other constraints.

ChristopherChudzicki avatar Aug 10 '22 20:08 ChristopherChudzicki

For anyone interested, here is a CustomPointSensor that provides this option: https://github.com/ChristopherChudzicki/math3d-next/blob/a224ca3865aa079aef34d349edfcf23d0fdf1cb9/client/src/util/components/dnd/PointerSensor.ts#L11

(I'm not sure if the activators array is actually the best place to put this kind of logic, but it works for a proof of concept.)

ChristopherChudzicki avatar Aug 10 '22 20:08 ChristopherChudzicki

And a CustomKeyboardSensor dealing with a similar issue, namely that pressing the spacebar or enter keys on an input inside a draggable initiates drags:

https://github.com/ChristopherChudzicki/math3d-next/blob/f59bea5d1605a8276ac6a67c0e31c626fb7dda9c/client/src/util/components/dnd/KeyboardSensor.ts#L16

ChristopherChudzicki avatar Sep 18 '22 20:09 ChristopherChudzicki

I tried that approach but didn't work for me. Then I opened an issue here: https://stackoverflow.com/questions/74963931. Anyways, if you have any idea on make that work, just let me know. Thanks!

zeuscronos avatar Dec 30 '22 16:12 zeuscronos