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

[Core] Injects react-tap-event-plugin when calling getMuiTheme() #3079

Closed
wants to merge 4 commits into from

Conversation

newoga
Copy link
Contributor

@newoga newoga commented Jan 28, 2016

Resolves #3068

Signed-off-by: Neil Gabbadon neil.gabbadon@emikra.com

Resolves mui#3068

Signed-off-by: Neil Gabbadon <neil.gabbadon@emikra.com>
@newoga newoga force-pushed the inject-tap-event-plugin branch from e920add to 89d11e6 Compare January 28, 2016 10:45
@oliviertassinari
Copy link
Member

We should remove it from the examples too.

Signed-off-by: Neil Gabbadon <neil.gabbadon@emikra.com>
@newoga
Copy link
Contributor Author

newoga commented Jan 28, 2016

We should remove it from the examples too.

Done.

Do you think we should remove the section in the documentation about this? Or should we leave the section in and just change the content to say that material-ui now injects it for you.

@newoga newoga changed the title Injects react-tap-event-plugin when calling getMuiTheme() [Core] Injects react-tap-event-plugin when calling getMuiTheme() Jan 28, 2016
@oliviertassinari
Copy link
Member

Do you think we should remove the section in the documentation about this?

Looks like it's going to be an implementation detail of Material UI. I would say we can remote it from the surface of the earth documentation.

@mbrookes
Copy link
Member

I think we should reword the documentation to reflect the change, for the benefit of anyone who implemented the previous instructions. We can remove it completely in a future release.

Edit: Obviously it's harmless if someone's already importing and injecting it in their app, but it might be a good idea to mention that we now do this in Material UI, and it no longer has to be added, and can optionally be removed if not used elsewhere in their app.

@newoga
Copy link
Contributor Author

newoga commented Jan 28, 2016

I suppose the other option is to include the change log on the site and put a note on there.

@mbrookes mbrookes added the PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI label Jan 30, 2016
…efined in theme

Signed-off-by: Neil Gabbadon <neil.gabbadon@emikra.com>
Signed-off-by: Neil Gabbadon <neil.gabbadon@emikra.com>
@newoga
Copy link
Contributor Author

newoga commented Feb 1, 2016

@oliviertassinari I'm not sure if you've been following the discussion in #3068, but there react-tap-event-plugin recently added a feature where you can configure thresholds as an argument of the injectTapEventPlugin() method.

I figured if we wanted to pursue this PR, we probably should support overriding or disabling our call of injectTapEventPlugin(). The way this is currently implemented in this PR is I put the function in the muiTheme (by default it's the injectTapEventPlugin function with no configuration). If you wanted to turn it off all together, you could provide injectTapEventPlugin: false in your theme. You could also write your own function wrapper that passes the configuration you want. Something like this...

/* custom muiTheme */
import injectTapEventPlugin from 'react-tap-event-plugin'
import Colors from 'material-ui/lib/styles/colors';

/* https://github.com/zilverline/react-tap-event-plugin#ignoring-ghost-clicks */
const customConfig = {
  shouldRejectClick: function (lastTouchEventTimestamp, clickEventTimestamp) {
    return true;
  },
};

export default {
  injectTapEventPlugin: () => injectTapEventPlugin(customConfig),
//injectTapEventPlugin: false,  // This would turn off our call `injectTapEventPlugin` entirely
  palette: {
    primary1Color: Colors.cyan500,
    primary2Color: Colors.cyan700,
  },
};

This is the best idea I can think of at the moment that simplifies material-ui for the 80% of developers that aren't configuring react-tap-event-plugin and are new to material-ui but won't break for developers that want to do things their own way.

@mbrookes @alitaheri Your feedback here would be useful too. 😄

@newoga newoga added PR: Needs Review and removed PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI labels Feb 1, 2016
@newoga
Copy link
Contributor Author

newoga commented Feb 1, 2016

The way this is currently implemented in this PR is I put the function in the muiTheme (by default it's the injectTapEventPlugin function with no configuration).

I thought about this some more and I'm not a huge fan of this implementation. I don't have a better idea at the moment but I'll think about it.

@alitaheri
Copy link
Member

I myself would still go with the warning. This coupling can be harmful in ways we might not pick up so fast. after all, we are adding a plugin to react during a render, which scares me.

@mbrookes
Copy link
Member

mbrookes commented Feb 1, 2016

It's not ideal, but I think it's worth the tradeoff. I propose we put it in a release candidate, and see if anyone screams.

Would love to get @s0meone's thoughts on this.

@newoga
Copy link
Contributor Author

newoga commented Feb 1, 2016

This coupling can be harmful in ways we might not pick up so fast.

Yeah I'm not really completely comfortable with this either for that same exact reason. For the possible issues we're not aware of yet.

I propose we put it in a release candidate, and see if anyone screams.

I'd be surprised if anyone screams during RC phase. But like @alitaheri said I'm afraid that down the line this could end up being a problem area. I think a fair compromise would be to merge the warning PR and see if we still are getting a lot issues opened up related to this issue. If after cleaning the code more we feel like we can reasonability fit this level of automation in and it's still an issue for users, I'd be open to reinvestigating it.

@s0meone
Copy link

s0meone commented Feb 1, 2016

Hi all, like I discussed with @oliviertassinari in zilverline/react-tap-event-plugin#57, I'm willing to add a mechanism to the plugin to detect whether the plugin is loaded or not. If people want to use the custom options provided with zilverline/react-tap-event-plugin#25 they could do so by injecting the plugin themselves, if not the proposed solution in this PR will inject the plugin automatically.

Hopefully this tap plugin will be fixed by React and not needed anymore, but it doesn't seem they're actively working on this yet.

So let know what an ideal solution would be and I'm happy to help out 👍

@newoga
Copy link
Contributor Author

newoga commented Feb 2, 2016

@s0meone Thanks for dropping a comment here! Yeah it seems like this event will be in user space indefinitely. I'm still thinking this through a bit and I'll let you know what I think the best direction is.

Also FYI, I wrote a function that detects whether the plugin was loaded and warns if not here. Do you think that implementation is adequate?

If detecting whether the plugin was loaded is something you think would have broader appeal to users of react-tap-event-plugin, then it'd be great to see it there. But I wouldn't ask you to do it if it's something only this project needs 😄

@s0meone
Copy link

s0meone commented Feb 3, 2016

Your solution looks solid. I think this check is definitely useful for the plugin itself, we're getting several issue reports about this as well. Maybe we can get @madjam002 in here, would like to know what he thinks.

@madjam002
Copy link

Now that 0.14 has removed initializeTouchEvents, maybe requiring the application to call injectTapEventPlugin themselves isn't such a good idea, the components should be able to call it themselves.

The only problem I see is if you want to use config like shouldRejectClick (mentioned above).
I imagine the application could then call injectTapEventPlugin with custom config if it wants it, then all the components calling it would no-op because it's already been injected. But what if a component needed shouldRejectClick? Maybe this isn't something to worry about.

For now I can make it so calls to tap event plugin get ignored if it has already been injected?

@newoga
Copy link
Contributor Author

newoga commented Feb 4, 2016

@madjam002 Thanks for the message and I apologize for the late response. 😄

First of all, I'm not too familiar with the internals of react-tap-event-plugin. I reviewed its source while implement the warning but I haven't looked too much beyond that. So please correct me if I'm wrong somewhere!

The only problem I see is if you want to use config like shouldRejectClick (mentioned above).
I imagine the application could then call injectTapEventPlugin with custom config if it wants it, then all the components calling it would no-op because it's already been injected.

I agree that, ideally, multiple calls of injectTapEventPlugin would result in a noop.

Based on what I currently understand, the issue in zilverline/react-tap-event-plugin#59 is that since every call of injectTapEventPlugin() returns a new function, every time it is called and registered, React thinks it's a different plugin instance being registered under the same name and produces the invariant violation.

Let me know if I'm reading that wrong.

Honestly, I'm really conflicted about what the right solution is to this. Implementing a check that ignores successive calls to injectTapEventPlugin sounds ideal, but I can seem some problems surfacing when developers are importing multiple libraries/components that call injectTapEventPlugin automatically.

@newoga
Copy link
Contributor Author

newoga commented Feb 4, 2016

I suppose this is a potential scenario I'm afraid of:

  1. Developer calls injectTapEventPlugin() in his own project
  2. Developer imports a component from an external library that is calling injectTapEventPlugin() automatically with a configuration that rejects all click events
  3. Developer imports or uses another component that has a onClick() handler and is confused why the events aren't being fired (and looks and his or her own code to trying to figure out what they did wrong in their own injectTapEventPlugin call)

Is this a reasonable concern or would this not happen?

My gut feeling at the moment is that due to the global nature of the plugin, frameworks and libraries should avoid calling injectTapEventPlugin automatically and let it be handled by implementing developers. That way they have full control of the configuration.

Side note:
@s0meone @madjam002 Out of respect to you guys, if you want to open an issue in the react-tap-event-plugin repo to discuss this more, that's no a problem at all. I'm more willing to continue there if that's what you prefer :)

@madjam002
Copy link

@newoga It's fine we can discuss it here if it's more convenient for you guys, material-ui is probably the biggest library which uses tap event plugin so it's important that we get this right.

Developer imports a component from an external library that is calling injectTapEventPlugin() automatically with a configuration that rejects all click events

Yeah that's what I'm worried about. To be honest, I don't mind calling injectTapEventPlugin at the top level of the application, I think it's the best approach.

Maybe we just need to improve error reporting so that if someone calls it twice, they no longer get a cryptic error message from React, but an error explaining that injectTapEventPlugin must be called once, possibly just before ReactDOM.render in their application.

How does that sound?

@newoga
Copy link
Contributor Author

newoga commented Feb 4, 2016

Maybe we just need to improve error reporting so that if someone calls it twice, they no longer get a cryptic error message from React, but an error explaining that injectTapEventPlugin must be called once, possibly just before ReactDOM.render in their application.

Yeah I was wondering the same. I think that's a real good start. I really think good error and/or warning messages will do a lot of good for the community that uses the plugin 👍

//cc @oliviertassinari @alitaheri @mbrookes Feel free to weigh in any additional thoughts here.

@madjam002
Copy link

Alright I will see to it later today 😄
We can then take things from there.

@newoga
Copy link
Contributor Author

newoga commented Feb 4, 2016

Alright I will see to it later today 😄
We can then take things from there.

Perfect, thanks much @madjam002!

@s0meone
Copy link

s0meone commented Feb 4, 2016

Sounds good guys. I think keeping things the way they are with better and clear warnings from both ends is a great solution for now.

@alitaheri
Copy link
Member

@madjam002 @s0meone Thanks for taking the time to discuss it with us 😄

Maybe we just need to improve error reporting so that if someone calls it twice, they no longer get a cryptic error message from React, but an error explaining that injectTapEventPlugin must be called once, possibly just before ReactDOM.render in their application.

I believe this is the best approach myself. I was thinking, maybe it won't be a bad idea if the same people who maintain inject-tap-event-plugin also maintain a very tiny library ( possibly 5 lines of code ) with the name check-tap-event-plugin (or something else 😁 ) to allow other library maintainers to check if the plugin is called successfully. The reason for it is that

  1. All other libraries that need this plugin to be injected will have a common way of checking whether it was injected or not.
  2. It can support some login to make sure no other library has warned the user already, avoids flooding the console.
  3. Since the same people maintain both libraries they can keep the logic up to date. Avoids regressions.
  4. It can also check for whether some specific configurations where provided to the plugin or not.
  5. It's small and stateless, so many versions can be loaded with no problem. no need to add it as peer dependency.

That's my opinion. I would love to hear yours on this too 😁

@madjam002
Copy link

@alitaheri I like that idea. Maybe one call to checkTapEventPlugin() at the index file of a library before any components get exported? That way the consumer would have to inject tap event plugin before requiring in any libraries.

@alitaheri
Copy link
Member

Yeah, that's also a great idea 👍 An optional warning would also be good, so authors can point users to their section of documentation on how to set it up. some libraries rely on some of the configuration provided by inject-tap-event-plugin so it's good way to point the users to those pages instead of generally asking them to call injectTapEventPlugin()

@newoga
Copy link
Contributor Author

newoga commented Feb 4, 2016

@alitaheri That sounds reasonable 👍

@alitaheri I like that idea. Maybe one call to checkTapEventPlugin() at the index file of a library before any components get exported? That way the consumer would have to inject tap event plugin before requiring in any libraries.

That workflow should work too.

@madjam002 Maybe you could get away with a monorepo approach like React and just stick both packages in the same repo and version them the same.

@alitaheri
Copy link
Member

@madjam002 Maybe you could get away with a monorepo approach like React and just stick both packages in the same repo and version them the same.

👍 👍

@s0meone
Copy link

s0meone commented Feb 4, 2016

@madjam002 Maybe you could get away with a monorepo approach like React and just stick both packages in the same repo and version them the same.

👍

@madjam002
Copy link

I like the sound of that, I'll see to it later this evening when I have some time.

@newoga newoga added PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI and removed PR: Needs Review labels Feb 5, 2016
@newoga
Copy link
Contributor Author

newoga commented Feb 27, 2016

I'm going to close this PR because we're not going to support injecting tapEventPlugin automatically for developers.

Thanks for everyone involved!

@newoga newoga closed this Feb 27, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR: needs revision The pull request can't be merged. More details is available on the code review or fails in the CI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants