You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Pressable Text substrings do not work properly when they're selectable #1679
You can create a pressable Text substring by nesting a Text component with an onPress handler inside of another Text component. If the outer Text component marks the text as selectable, then the press functionality of the inner Text component is broken. Here's an example:
<Text selectable={true}>
Outer text
<Text onPress={this._handlePress} style={{color: 'red'}}>
Inner text
</Text>
More outer text
</Text>
There are a couple of issues with this:
When you click on "Inner text" _handlePress is not called.
When you hover over "Inner text" the cursor is the I-beam selection cursor. Instead, the cursor should be a hand indicating that you are hovering over a clickable element.
Potential Solutions
I have a few ideas for how to solve this but none are ideal so far:
Manually do hit testing on Text to see if a pressable region was hit. To do this, we'd have to sign up for the RichTextBlock's pointer events using AddHandler so we can pass true for the handledEventsToo parameter. A major limitation is apparently we are stuck with the I-beam selection cursor when hovering over text. When trying to set it to something else like an arrow in the PointerMoved handler, the cursor rapidly flickers between I-beam and arrow. To fix this, we'd likely need a feature from the XAML team. Another concern is around the performance of the code that would do the hit testing.
Every nested Text component with an onPress handler is rendered as a Hyperlink. This solution has some issues due to limitations with Hyperlink:
You can only nest Runs and non-HyperlinkSpans inside of the Hyperlink (e.g. can't nest inline views). I suspect this won't be problematic in practice.
Every nested Text component with an onPress handler is rendered as an inline view. The issue with this approach is that when your selection includes the inline view, the copy command doesn't work.
The best option might be (2). We translate a <Text> with an onPress handler to a XAML Hyperlink. There will be a lot of limitations in styling but a hyperlink scenario is probably the most common use of onPress on Text nodes anyway. Also, I can't think of a more general way to solve this nicely given the APIs XAML exposes.
For now, we're using option 2 from the description above, but it's limiting that the ABIViewManager derives from FrameworkElementViewManager (so we need to keep the HyperlinkViewManager implementation in a fork of react-native-windows). Honestly option 2 wouldn't need to be a core feature if we fixed #5539. Ideally we would be able to create ViewManagers that returned DependencyObjects as opposed to only FrameworkElements.
I experimented with option 1 (using AddHandler with handledEventsToo=true) in TouchEventHandler.cpp rather than the routed event handlers, but that doesn't seem to work entirely because of pointer capture inside TextBlock (so PointerCaptureLost is invoked before PointerReleased, canceling the pointer).
A while back, we used the UIElement.AddHandler approach with handledEventsToo set to true: #1646
However, this has it's own limitations, as PointerCaptureLost fires whenever the TextBlock handles an event, which effectively cancels the React Native touch sequence. It might also interfere with other workarounds that were added for pointer capture behavior on ScrollViewer like this one: react/react-native#30374
Activity
rozele commentedon Mar 31, 2021
Reviving an oldie-but-goodie. This remains to be true in vnext.
rozele commentedon Mar 31, 2021
For now, we're using option 2 from the description above, but it's limiting that the ABIViewManager derives from FrameworkElementViewManager (so we need to keep the HyperlinkViewManager implementation in a fork of react-native-windows). Honestly option 2 wouldn't need to be a core feature if we fixed #5539. Ideally we would be able to create ViewManagers that returned DependencyObjects as opposed to only FrameworkElements.
I experimented with option 1 (using AddHandler with
handledEventsToo=true) in TouchEventHandler.cpp rather than the routed event handlers, but that doesn't seem to work entirely because of pointer capture inside TextBlock (so PointerCaptureLost is invoked before PointerReleased, canceling the pointer).chrisglein commentedon Apr 5, 2021
Igor Klemenski (@rectified95) You've got a change to restore the pressable events on nested text. See if
selectableis still affected.rozele commentedon Apr 7, 2021
Chris Glein (@chrisglein) Igor Klemenski (@rectified95) -
selectableis still affected, it's an issue with TextBlock capturing the pointer and handling events before they can reach TouchEventHandler.A while back, we used the
UIElement.AddHandlerapproach withhandledEventsTooset totrue: #1646However, this has it's own limitations, as
PointerCaptureLostfires whenever the TextBlock handles an event, which effectively cancels the React Native touch sequence. It might also interfere with other workarounds that were added for pointer capture behavior on ScrollViewer like this one: react/react-native#30374I have a WIP approach that takes a more targeted approach, subscribing TouchEventHandler directly on TextBlocks when
selectableis set:https://github.com/rozele/react-native-windows/tree/handledEventsToo
[rn][win] Adds HyperlinkViewManager for `selectable`-safe `onPress`
rozele commentedon Nov 4, 2021
Fixed by #7813
[rn][win] Adds HyperlinkViewManager for `selectable`-safe `onPress`