-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
fix: [web] Don't apply SvgTouchableMixin on every component #1294
base: main
Are you sure you want to change the base?
Conversation
Oh interesting, I suspect this won't handle cases where at first there's no touchable property, but in a later re-render there is. Wonder what makes it accessible to begin with, have you dug deeper into this? |
@msand I didn't check about this! I will make the changes to handle this case! |
Hmm, I can't seem to figure out why that return value would depend on using TouchableMixin, can't find anything inside it that should effect it. Guess I'd have to run the actual code to figure it out. |
@msand Instead of using a |
I think that probably wont work well together with gesture responders. Not sure though. |
This seems to work: const isWeb = Platform.OS === 'web';
const keys = Object.keys(SvgTouchableMixin);
const touchKeys = isWeb ? keys.filter(key => key !== 'componentDidMount') : keys; |
Seems related to this._isTouchableKeyboardActive in Touchable Mixin |
Actually, deciding factor seems to be: |
Not sure how the presence / absence of a blur handler decides if a svg element can become the active element or not. |
I see https://svgwg.org/svg2-draft/interact.html#Focus
|
@necolas Is this behaviour intentional? Is the blur event handler partially there to make some svg elements focusable? What are the cases in which they should be focusable and not? I'd assume if there's no focus/press/gesture related handlers, they shouldn't be focusable, while if that changes, it should adapt correctly. Seems like disabling the blur event listener / skipping componentDidMount is not a good solution. Could perhaps attach/detach as a side-effect based on the presence of event handlers. Wdyt? |
@necolas Sorry to ping you twice like this. Feel free to instruct me not to ping you and I won't cause any further interruptions. Was suspecting it went past your radar / forgot about this. Would you mind having a quick look and giving a bit of guidance with regards to the touchable api in react-native-web? I'm considering I should write a react-native-svg specific handler, that de/attaches the blur event listener on demand. Do you see any problems with this approach? |
@zoontek What do you think of this implementation? |
@msand This should work, I can try it tomorrow to be sure if you want. But this (kind of) seems fragile. Maybe |
Yeah, this certainly isn't very clean, but the closest api to the react-native implementation and most react-native-web compatible I can think of at the moment. I'd love to see a cleaner implementation of this and certainly willing to merge it. |
I think the mixin should be run on the prototype once rather than on each instance object as well. Only the event listeners need to be attached, and the state initialized, per instance. |
I don't have enough context to understand what's going on here. You're trying to mixin Touchable on an SVG element? Why is that part of an svg library? |
It's used in the react-native implementation to get support for touch/gesture events, so quite a few components are implemented based on that api of react-native-svg, and thus a compatibility layer for the web components has been requested. |
@necolas Perhaps I should elaborate, the Touchable mixin has been part of the (Shape) api since v4.1.0 or 9 Jun 2016 Many of the use cases of this library aren't static content, but interactive visualisations and complex ui elements with various touchable filled and/or stroked areas. Many of them are simple press handlers, others have turing complete dependence on the history of gesture events / other inputs. In the case of this pr, as we've made the api work the same way on the web as it already does in native (i.e. support touch and gesture handler directly on the components), causes the dom elements to be focusable, as the componentDidMount handler from Touchable in react-native-web attaches a blur event handler to the dom elements, causing them to be considered accessible elements, and thus when you tab thru the page, the elements receive focus, even if they don't have any press / gesture event handlers actively attached to the react-native-svg elements. This pr currently detaches the blur event handler after componentDidMount, in case there are no touchable props given, and reattaches if at a later point there is. Ideally we would have had two sets of elements, one with touchable support, and one without, but this api was grandfathered in before I made my first contributions. @zoontek Did you have time to test this? |
@msand Yes, I use the last version on two projects and it works correctly now. Otherwise if I understand the necessity of interactive SVG, why can't we just wrap elements in TouchableWithoutFeedback? (Ex: to make a Path pressable). It's added complexity and possible side effects for not so much. |
@zoontek You mean the last released version? last commit from develop branch? or from this branch/pr? That would be ideal, but I'm not sure I could sustain the amount of opened issues that kind of breaking change to the api would cause. I would likely stop supporting this library, given the history of types of issues opened over the past few years. So, perhaps in case you would commit to handling all issues of that type I could consider it. |
I added a working web example with RNW + kept my implementation (using There's still a small issue with ref forwarding, but it could be fixed in another PR. |
My recommandation: Cleanup this repository to the max, update dependencies, and schedule some breaking changes. It just add a lot of complexity for nothing. Developers can wrap |
I think it is not a good idea to mix many different changes in one PR since it makes it a lot harder to spot bugs and revert them later. As for the |
@WoLewicki I had several errors in the console. I can create a new PR to fix the example app + add react-native-web for it (and maybe delete |
|
@WoLewicki The PR is here: #1717 Like I said here, the But IMHO it's a good start to implement breaking changes. I can help creating a roadmap for v13. |
@WoLewicki Indeed, it might was super broken with focus on all elements and pressability broken too, I didn't checked 😄 |
Could you merge the current |
# Conflicts: # Example/.prettierrc.js # Example/src/App.tsx # Example/src/examples/Image.tsx # Example/src/examples/PanResponder.tsx # Example/src/examples/Svg.tsx # Example/webpack.config.js # Example/yarn.lock # src/ReactNativeSVG.web.ts
@WoLewicki Done. However, I recommend using that as a temporary solution and remove press handling in the next major version 🙏 It sures fixes the onPress related events, but:
|
Sorry for the late response. So do you think this PR provides better solution than the current implementation? About wrapping the whole Svg with a Pressable, do you think it won't add new problems, as the clickable area? |
It's better than the current implementation for sure. But not perfect. Advices to wrap SVG with Pressable / Animated.View / View with PanResponder will allow deletion of a lot of code / the suppression of a lot of issues 🙂 |
I think quite a few people depend on the press related functionality to only respond when interacting with filled / stroked parts of them canvas. I'm quite sure that wrapping with Pressable / PanResponder won't respect that part of the api. Or? |
@msand IMHO, if a part of the SVG should be animated / move using PanResponder but not the rest, that's not an SVG, but two. And even with that, components are implemented using basic UIView / View, it shouldn't be an issue. |
Well, in practise, if the pressability would change to be based on bounding boxes rather than fill / stroke, a bunch of use cases would no longer be possible or would be buggy. The ability to have events based on this comes from the svg spec, so I'd say it is in scope of what should be supported by react-native-svg for single svg components. |
This is a blocker for our A11y audits. I've moved our implementation to module alias |
Hi 👋
Do you remember this bug? Well, it happens again, for a different reason. 😄
By default, every component of this lib implements the
SvgTouchableMixin
, even if no Touchable properties are used, making every component accessible by default again.Summary
hasTouchableProperty
is now a function,SvgTouchableMixin
is applied only if it returnstrue
.Test Plan
What's required for testing (prerequisites)?
create-react-app
andreact-native-web
react-native-svg
dependency and render a random SVG using itWhat are the steps to reproduce (after prerequisites)?
Checklist
README.md
__tests__
folder