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

[Select] Dispatch click event with same target of the mousedown event #25630

Closed
wants to merge 8 commits into from

Conversation

m4theushw
Copy link
Member

@m4theushw m4theushw commented Apr 5, 2021

Closes #25578

Trade-offs:

A codesandbox with the upstream issue and the fix in this PR: https://codesandbox.io/s/datagrid-bug-demo-forked-ntsb3?file=/package.json

@mui-pr-bot
Copy link

mui-pr-bot commented Apr 5, 2021

Details of bundle changes

@material-ui/core: parsed: +0.11% , gzip: +0.09%

Generated by 🚫 dangerJS against d3b4a0f

@@ -116,6 +116,7 @@ describe('<Select />', () => {
const trigger = getByRole('button');

fireEvent.mouseDown(trigger);
fireEvent.click(trigger);
Copy link
Member Author

@m4theushw m4theushw Apr 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to add this click to every fireEvent.mouseDown so that the previous added event listener is removed.

@m4theushw m4theushw added the on hold There is a blocker, we need to wait label Apr 6, 2021
@m4theushw
Copy link
Member Author

Added the "on hold" label as I want to use the e2e job to test this use case.

@m4theushw m4theushw removed the on hold There is a blocker, we need to wait label Apr 6, 2021
@oliviertassinari oliviertassinari changed the title [SelectInput] Dispatch click event with same target of the mousedown event [Select] Dispatch click event with same target of the mousedown event Apr 6, 2021
@oliviertassinari oliviertassinari added the component: select This is the name of the generic UI component, not the React module! label Apr 6, 2021
Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have updated the issue description to link #18655 that will likely come up again with the changes here. No objections to giving this approach a try. I would personally favor the change in the ClickAwayListener logic I had initially proposed. It would be more resilient, It's not too hard to trigger the same issue: https://codesandbox.io/s/simplepopper-material-demo-forked-1xw2n?file=/demo.tsx.

@oliviertassinari oliviertassinari added the bug 🐛 Something doesn't work label Apr 6, 2021
Copy link
Member

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing the behavior for the clickAwayListener is important. We can't also dispatch synthetic events. We would now compete with the browser and React. Adding new, unspecified behavior. But not only is the behavior unspecified, it actually violates existing specification (click events should be dispatched on the common ancestor of mousedown/mouseup).

I talked with the React folks who faced this very issue recently and will share their recommendations this week. Dispatching synthetic events was not among the considered approaches.

@@ -116,6 +116,7 @@ describe('<Select />', () => {
const trigger = getByRole('button');

fireEvent.mouseDown(trigger);
fireEvent.click(trigger);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one indicator that this change is problematic. What happens if there is no click registered on the trigger due to interactions with other elements?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no problem if the click occurs in other element, here it could even be in the document.body. I just need to issue it to clear the previous added listener or it will cause unexpected behavior in the next fireEvent.mouseDown below.

packages/material-ui/src/Select/SelectInput.js Outdated Show resolved Hide resolved
packages/material-ui/src/Select/SelectInput.js Outdated Show resolved Hide resolved
doc.removeEventListener('click', handleClick.current, true);
}

// Since the targets of the `mousedown` and `mouseup` events are different,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not clear at this point in the code that this is the case. Wouldn't you want to check that during mouseup?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To check during mouseup I would have to add another listener to the document and from this listener add another one to cancel and re-dispatch the click.


// Since the targets of the `mousedown` and `mouseup` events are different,
// the browser will dispatch the `click` to a common ancestor.
// This stops the next `click` and re-dispatch it with the right target.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you think the specified behavior is not the "right" target?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it's not clear that, because a transparent div is placed in the mousedown, the target of mouseup changes.

@m4theushw
Copy link
Member Author

Fixing the behavior for the clickAwayListener is important. We can't also dispatch synthetic events. We would now compete with the browser and React. Adding new, unspecified behavior. But not only is the behavior unspecified, it actually violates existing specification (click events should be dispatched on the common ancestor of mousedown/mouseup).

I talked with the React folks who faced this very issue recently and will share their recommendations this week. Dispatching synthetic events was not among the considered approaches.

@eps1lon Even if we discard this PR to avoid dispatching new events, there's still the problem that the click doesn't propagate. It's not intuitive for users writing unit-tests to have to use the mousedown to click the select. #18655 #19250
I'll wait for your recommendations.

@aditya2337
Copy link

Hello 👋 , I happened to stumble upon this PR after debugging what I think is a similar issue, in my case, I am trying to track the user's click event on the Select field, and I am doing this through heap analytics, although once a user clicks on select, heap recognizes the event on body.

Is this related to the current issue? If not could you point me how to fix this?

Thank you in advance 🤗

@m4theushw
Copy link
Member Author

Hello 👋 , I happened to stumble upon this PR after debugging what I think is a similar issue, in my case, I am trying to track the user's click event on the Select field, and I am doing this through heap analytics, although once a user clicks on select, heap recognizes the event on body.

Is this related to the current issue? If not could you point me how to fix this?

Thank you in advance 🤗

@aditya2337 Yes, this PR is related to your issue. The click event is not dispatched in the Select field but in the body or other common ancestor. The mousedown event can be used to track user's click.

@aditya2337
Copy link

Ah, awesome 👏 thank you!!

@m4theushw
Copy link
Member Author

I changed the approach here. Instead of dispatching new events, I'm setting pointer-events to none between mousedown and click. This prevents the backdrop from being used as target for the mouseup, which also avoids the common ancestor logic in the click event.

Copy link
Member

@oliviertassinari oliviertassinari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new approach makes me think of #23466. Looks better

Copy link
Member

@eps1lon eps1lon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's discuss this on the next planning meeting. There are some misunderstandings that we should sync on. Mostly onboarding issues.

@oliviertassinari
Copy link
Member

I'm closing as the effort has been stale for a while.

@m4theushw m4theushw deleted the selectInput-onClick branch November 1, 2021 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: select This is the name of the generic UI component, not the React module! PR: out-of-date The pull request has merge conflicts and can't be merged
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ClickAwayListener] Calling onClickAway straightaway when used with Select
5 participants