use-gesture
use-gesture copied to clipboard
Exclude children from the gesture
cc @odusseys
Discussed in https://github.com/pmndrs/use-gesture/discussions/428
Originally posted by odusseys January 19, 2022 Hi, Is there a way to exclude specific children of an element from triggering the gesture / getting events as they should ? For example, is there a way to correctly select text within a draggable elements ?
Responding to your last comment: it doesn't feel very idiomatic (in a react sense, but I understand the lib is meant to work for all JS frameworks including vanilla) to
- be passing around / working with dom objects unless it's a last resort / building a library, so as a consumer of a react lib it is always much more appreciable to work with components, hooks and refs
- send objects bottom-up in the props hierarchy. This to me is the biggest issue ; if the component you wish to exclude is nested deep, you will need to forward a ref multiple times down to that component in order for it to be used (or put it in a context ; but putting refs in a context is clunky). In particular refactoring becomes much more complex, and the props are muddled by an unneccessary ref which has little to do with the intrinsic purpose of the components.
For react, this use case seems to be most compatible with the Context API ; ie a provider at the useGesture level (useGesture and the child component would both subscribe to this context to communicate)
For the general vanilla JS purpose, I would rely on an element property (ex. use-gesture-ignore="true"), or something along those lines. This is less ideal for React as custom properties are not idiomatic, and don't work in a straightforward way if you want to wrap a fragment / list.
I find the react-dnd lib extremely well designed in this aspect, it allows to very easily and modularly communicate between drag / drop components without any prop sharing whatsoever.
Can you point at where react-dnd is using the context api? Honestly it feels a bit convoluted to be using a <Provider /> for a lib such as use-gesture, but I'm happy to reconsider.
the provider could be used optionally (only if you need a child to get access to the gesture / the gesture state) react-dnd has the provider here https://react-dnd.github.io/react-dnd/docs/api/dnd-provider but it's a bit different since all hooks / HOC subscribe to this provider, as a means to declare useDrag anywhere inside and useDrop anywhere else, and have both communicate without passing any props across.
Would you be up for a PR? Note that the core package is platform agnostic (ie not React specific).
I am under water with work but I'm putting a task in my todos to do this as soon as things clear out, would love to help
I personnally use @vueuse/gesture based on this library...
I have the same problem : my users want to still select texts or have a "normal" behavior of the website.
As i didn't found anything in gesture options and as the "target" option juste do nothing (= event still triggered on children)
what i did is basically check if the dom element of the state.event is the one i want based on classList..contains(example) and element.id = the one i want..
Example :
const handler = (state: any): void => {
// boolean : check if target element is a div.pannel or a div.page => other elements should not trigger swipe.
let isCorrectDomTriggered =
state.event.target.classList.contains('page') ||
state.event.target.classList.contains('pannel') ||
state.event.target.id == 'app_body';
if(!isCorrectDomTriggered)
return
// other stuff = when correct dom triggered
}
// Composable usage // https://gesture.vueuse.org/use-drag.html#options useDrag(handler, { domTarget: draggy, filterTaps: true, axis: 'x' });
Maybe someone will have a more elegant way to achieve this... Have a good day :)
cardRef.current.style.top = `${element.pageY + state.offset[1]}px`;
cardRef.current.style.left = `${element.pageX + state.offset[0]}px`;
I tried the same logic but the state offset still seems to be getting updated even though the draggable element didn't get dragged. So when I actually drag the element there is a sudden jerk.
I personnally use @vueuse/gesture based on this library...
I have the same problem : my users want to still select texts or have a "normal" behavior of the website.
As i didn't found anything in gesture options and as the "target" option juste do nothing (= event still triggered on children)
what i did is basically check if the dom element of the state.event is the one i want based on classList..contains(example) and element.id = the one i want..
Example :
const handler = (state: any): void => {
// boolean : check if target element is a div.pannel or a div.page => other elements should not trigger swipe. let isCorrectDomTriggered = state.event.target.classList.contains('page') || state.event.target.classList.contains('pannel') || state.event.target.id == 'app_body'; if(!isCorrectDomTriggered) return // other stuff = when correct dom triggered}
// Composable usage // https://gesture.vueuse.org/use-drag.html#options useDrag(handler, { domTarget: draggy, filterTaps: true, axis: 'x' });
Maybe someone will have a more elegant way to achieve this... Have a good day :)
this worked for me but idk if its ideal