microsoft / react-native-macos

A framework for building native macOS apps with React.
https://microsoft.github.io/react-native-windows/
MIT License
3.37k stars 130 forks source link

Cursor ignoring zindex #914

Open jbcullis opened 2 years ago

jbcullis commented 2 years ago

Environment

react-native 0.64.0:
npm ls react-native-macos: 0.64.13
node: 17.0.1
npm: 8.1.0
yarn: N/A
xcodebuild: 13A1030d

Steps to reproduce the bug

If you have a popup covering a TextInput, if you hover over the overlayed TextInput it will show the text cursor.

Expected Behavior

Cursor should be based on top layer.

Actual Behavior

Text cursor shows for when hovering over a TextInput underneath the popup.

Reproducible Demo

https://github.com/jbcullis/test

Additional context

Doesn't matter about opacity, this also occurs when full opacity: 1 views are covering the TextInput.

Further, clicking a button that sits over the top of a TextInput will focus the TextInput. Temporary workaround is to set editable to false on the TextInput when the UI container the TextInput is in the background.

IMG_5598

HeyImChris commented 2 years ago

Could you please attach some sample code we can repro this with?

jbcullis commented 2 years ago

@HeyImChris I've created a demo with an absolute opaque view overlaying a TextInput and you'll see the cursor will change when you hover over the TextInput, and you can select and type into it.

It seems like that the TextInput control is always on top in terms of zIndex.

HeyImChris commented 2 years ago

@jbcullis How are you displaying the popover in your test app? I cloned it and right clicked to get a contextual menu to show over the TextInput control and the cursor is the correct type in that scenario even when the menu is over a TextInput. Contextual Menu != Popover though so want to make sure I'm testing this with the same controls as you.

jbcullis commented 2 years ago

@HeyImChris the issue I’m having is that I can still select a text input even when there is a view overlayed over the top of it. Same issue with a scroll view, if you create a full screen view over the top of a scroll view, you can still scroll.

HeyImChris commented 2 years ago

@jbcullis Thanks, I'm able to repro your issue. Could you try testing it on an iOS app just with a simple text input and View over top of it? I'm curious if this is a macOS bug or just a generic RCTView issue.

jbcullis commented 2 years ago

@HeyImChris issue seems limited to macOS. It's fine on iOS, Android, and Windows.

jbcullis commented 2 years ago

@HeyImChris I don't have any experience with core RN but I'm hoping to learn so I started poking around over the weekend to try an identify the cause. Could it be an issue with catalyst cause I've seen some weird cursor behavior in the iOS simulator before.

This issue is the most pressing for us as it's causing users to think they can't press buttons if there is a textinput below the overlayed view.

gurupatel107 commented 2 years ago

Any update on the issue? Tested on latest react-native-macos version it is still coming. Any workaround can be done for short period ?

jbcullis commented 2 years ago

Workaround is to set an active window flag and on textbox set editable to the active window status.

It's a pretty dirty hack and adds cruft to the codebase but it works.

jbcullis commented 1 year ago

@HeyImChris We updated to .68 and the issue remains.

Saadnajmi commented 1 year ago

@jbcullis where did you set the active window flag? And to confirm, you tested on 0.68, not main correct?

jbcullis commented 1 year ago

@Saadnajmi it's a global variable we set for active window, then any screen that doesn't match active window disables all input text elements. It's not part of the element, it's something we came up with as a work around for macos. You still get the wrong cursor if you're hovering over a text input at a lower z index but it at least prevents those elements grabbing focus.

Yes, we upgraded to .68 and this issue persists.

Saadnajmi commented 1 year ago

@jbcullis thanks for the info. We have some fairly substantial changes to both Text and Textinput on our main branch, but they haven't made it to our next stable release yet (planned to be 0.71, no eta just yet when we can get it out yet though). We can revisit this at our next release and see if the bug still persists. I'm glad you found a workaround =) albeit a hacky one.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

bear-ei commented 6 months ago

@Saadnajmi It seems that zIndex is not valid for all mouseover events. Any mouseover event on a lower level window element can be triggered on a higher level window. This causes a lot of problems in most single-window applications. This problem still exists in version 0.73.0.

jbcullis commented 6 months ago

@Saadnajmi Yep, still a problem. Mac is only 1.9% of our install base on the main app so not the biggest issue but if we went web with our latest app because of this issue.

The biggest issue is when there is a pressable element directly below it in a lower window, it breaks long press.

bear-ei commented 4 months ago

https://github.com/microsoft/react-native-macos/assets/61616262/ef701f5e-c8a7-4927-bfb3-700643fcbe7b

I was wondering if there has been any progress on this issue. Or does anyone know what the cause of this problem is? What should be done to fix it. I am currently using version 0.72.* and still have this problem. If there are no plans to fix it in the near future, I may have to make some compromises to my project interactions.

Saadnajmi commented 4 months ago

@bear-ei looking at your video, is there a view extending across the full width of your window, or just where the drawer comes out?

bear-ei commented 4 months ago

截屏2024-03-04 23 23 58

@bear-ei 看看你的视频,是否有一个视图延伸到整个窗口的宽度,或者只是抽屉出来的地方?

I can confirm that there is a top-level View covering the entire width and height of the window, and the drawer pops up within this View. I have set the zIndex to the maximum, and only when encountering onHoverIn and onHoverOut events do they penetrate to the underlying elements. This is one of the reasons causing the incorrect cursor display. However, events like onPress and onPressOut do not penetrate to the underlying elements, indicating that the zIndex is taking effect. I lack knowledge of MacOS native UI components, so I cannot further investigate the issue.

Saadnajmi commented 4 months ago

@bear-ei Yes, onHoverIn and onHoverOut (implemented separately from everything else since they are desktop specific) are implemented differently. I don't think we have any plans to fix this bug, at least in paper. In the case of your example, I think even in a native macOS app the highlights would happen. To block highlights, you would probably want to present a modal like an NSSheet. But you would also need a native module for that, so I am not sure I've got a good workaround for you 🙁. Knowing that this issue keeps coming up is good though, thank you for reporting it. I'll update if anything changes.

fo-fo commented 4 months ago

@bear-ei Yes, onHoverIn and onHoverOut (implemented separately from everything else since they are desktop specific) are implemented differently. I don't think we have any plans to fix this bug, at least in paper. In the case of your example, I think even in a native macOS app the highlights would happen. To block highlights, you would probably want to present a modal like an NSSheet. But you would also need a native module for that, so I am not sure I've got a good workaround for you 🙁. Knowing that this issue keeps coming up is good though, thank you for reporting it. I'll update if anything changes.

Would it be possible to create a native component, something like OverlayView, that would block all interaction with views beneath it, but would otherwise work like a normal View? By the way, react-native-web behaves differently than react-native-macos here. I understand that it might not be easy to fix, but still it's a bit unfortunate for modal (or modal-like) views.

Saadnajmi commented 4 months ago

For completeness sake, here is the code on Paper (not Fabric) that send the onMouseEnter / onMouseExit events. which turn into onHoverIn / onHoverOut. As you can see, it's a very simple implementation of NSView's mouseEntered method.

https://github.com/microsoft/react-native-macos/blob/70e4f2fe703d28c6d47f739e83914309fad0d492/packages/react-native/React/Views/RCTView.m#L1548-L1564

Mouse enters tracking rect -> sends event. To account for zIndex, maybe we just need to make sure the view isn't obscured somehow? I'll look around to see if there's a simple way to do this in Appkit

Saadnajmi commented 4 months ago

Possibly a simple solution? https://stackoverflow.com/a/35344315

fo-fo commented 4 months ago

Mouse enters tracking rect -> sends event. To account for zIndex, maybe we just need to make sure the view isn't obscured somehow? I'll look around to see if there's a simple way to do this in Appkit

At least in my case I don't think the issue itself was related to z-index in any way. It also happened with other obscuring views (based on element order).

So yeah that kind of a hit test might work.

jbcullis commented 4 months ago

There's definitely a bigger issue where it gets in the way of long press on higher level buttons.