Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set cursor to the grabbing hand when gesture is active #700

Closed
EvanBacon opened this issue Jul 24, 2019 · 4 comments
Closed

Set cursor to the grabbing hand when gesture is active #700

EvanBacon opened this issue Jul 24, 2019 · 4 comments
Labels
BugBash 31.03 Close when stale The issue will be closed automatically if it remains inactive Feature request Platform: Web

Comments

@EvanBacon
Copy link
Collaborator

😎

cursor: grab;
@jakub-gonet jakub-gonet changed the title [web] Set cursor to the grabbing hand when gesture is active Set cursor to the grabbing hand when gesture is active Sep 3, 2020
@m-bert
Copy link
Contributor

m-bert commented Sep 21, 2022

Added in 2.6.1 😎

Note that this change is available in new web implementation. To enable it, call enableExperimentalWebImplementation() in the root of your project.

@TomSwift
Copy link

Why is this desirable? I just encountered the behavior and I don't want it, and not seeing a way to turn it off.

@chriscoomber
Copy link
Contributor

chriscoomber commented Feb 14, 2023

@TomSwift I agree, and I've come up with a workaround to turn it off:

  • Find the view that your GestureDetector wraps and get a ref to it.
  • In every gesture's onBegin, set viewRef.current.style.cursor = 'auto';

For example:

const viewRef = useRef<Animated.View>(null);

/* ... */

const panGesture = Gesture.Pan()
  .onBegin(() => {
    // Web fix: don't use the grabby hand when drawing.
    if (Platform.OS === 'web' && viewRef.current !== null) {
      (viewRef.current as unknown as HTMLElement).style.cursor = 'auto';
    }
  })
  /* ...more config */;

/* ... */

<GestureDetector gesture={panGesture}>
  <Animated.View ref={viewRef} /* ...more props */>

This works because they set the cursor to 'grab' right after calling activate(), and I think that's always followed by the state being transitioned to BEGIN.

Edit: hrm, actually I'm not sure if that's enough. I actually was doing something a bit more complicated:

const panGesture = Gesture.Exclusive(
  Gesture.Pan()
    .onBegin(() => {
      // Web fix: don't use the grabby hand when drawing.
      if (Platform.OS === 'web' && viewRef.current !== null) {
        (viewRef.current as unknown as HTMLElement).style.cursor = 'auto';
      }
    })
    .minDistance(0)
    /* ...more config */,
  Gesture.Tap()
    .onBegin(() => {
      // Web fix: don't use the grabby hand when drawing.
      if (Platform.OS === 'web' && viewRef.current !== null) {
        (viewRef.current as unknown as HTMLElement).style.cursor = 'auto';
      }
    })
);

This works. I seem to need the Tap - even if it does nothing at all. I also seem to need the minDistance(0), which you might not want. I'm afraid I haven't been able to distill it down to exactly the right fix to undo their change - maybe you'll have more luck.

Edit 2:

It appears that adding in the extra (unused) Gesture.Tap, at lower priority to your main gesture (via Gesture.Exclusive) seems to be the magic fix. I also needed the fix in the onUpdate part of my Gesture.Pan, but if your gesture wasn't a Gesture.Pan I'm sure you can do something similar. To be clear, I don't understand why this works.

let panGesture: GestureType | ComposedGesture = Gesture.Pan()
  .onUpdate(event => {
    // Web fix: don't use grabby hand (part 1)
    if (Platform.OS === 'web' && viewRef.current !== null) {
      (viewRef.current as unknown as HTMLElement).style.cursor = 'auto';
    }
    /* ...more code */
  })
  /* ...more config */;

// Web fix: don't use grabby hand (part 2)
if (Platform.OS === 'web') {
  panGesture = Gesture.Exclusive(
    panGesture,
    Gesture.Tap().onBegin(() => {
      if (viewRef.current !== null) (viewRef.current as unknown as HTMLElement).style.cursor = 'auto';
    })
  );
}

Edit 3:

If you are using manual activation, it's super simple: just put this code immediately after calling activate(). E.g.

const gesture = Gesture.Manual()
  .onTouchesDown((event, manager) => {
    /* ... logic */
    manager.activate();
    if (viewRef.current !== null) (viewRef.current as unknown as HTMLElement).style.cursor = 'auto';
  };

All the hacks in the rest of my comment are to do with trying to find where each gesture calls activate() under the covers.

@m-bert
Copy link
Contributor

m-bert commented Jul 19, 2023

Hi @TomSwift and @chriscoomber! We understand that this change may not be desirable and not everyone likes the idea. With that in mind I've prepared this PR, which adds activeCursor prop. This way cursor keeps default appearance and if you would like to change it, you can use new prop to give it any css cursor value you'd like. I hope this will help!

m-bert added a commit that referenced this issue Jul 20, 2023
## Description

This PR adds `activeCursor` prop which allows users to change cursor
appearance upon handler activation. Initially it was added in
[2.6.1](https://github.com/software-mansion/react-native-gesture-handler/releases/tag/2.6.1)
as a response to [this
issue](#700).
However, not everyone liked the idea (which is understandable), so we
decided to turn this change into property. This way anyone who was using
it still will be able to do so, and those who didn't like the change
don't have to remove it on their own.

Co-authored-by: Michał Bert <michal.bert@swmansion.com>
@j-piasecki j-piasecki added the Close when stale The issue will be closed automatically if it remains inactive label Jul 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugBash 31.03 Close when stale The issue will be closed automatically if it remains inactive Feature request Platform: Web
Projects
None yet
Development

No branches or pull requests

6 participants