-
Notifications
You must be signed in to change notification settings - Fork 982
[DropdownMenu][Menu] Allow dialog composition #818
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
Conversation
I need to figure out keyboard support 🙈 |
5cca3e5
to
f5e3289
Compare
80e6385
to
e5e47cf
Compare
event.currentTarget.click(); | ||
// prevent default browser behaviour for selection keys, they should trigger a | ||
// selection only. for example, stops page from scrolling when hitting space key. | ||
event.preventDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is needed for Enter
keypress also otherwise the Dialog
will not open. I am really stumped why this is needed though. There isn't a keydown
event in the Dialog.Trigger
so we're not preventing any of our implementation, just browser stuff but I dno what that "stuff" is 🙈
Any ideas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not knowing the "stuff" is bugging me too. I realised that the Dialog
does open, it's just that the close button is triggered as well, causing it to close immediately.
Could this be related to any of the implicit form submission behaviour associated with Enter
? I can't see why it would given we're not in a form context, I'm just struggling to see what else the browser could be doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's just that the close button is triggered as well, causing it to close immediately.
This should only be happening if you hold the Enter
key down which is how the browser works unfortunately https://codepen.io/jjenzz/pen/rNmPwqj
Is it happening when you just press enter and don't hold it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it happening when you just press enter and don't hold it?
Seems so, without preventing default the dialogs close button onClick
handler will fire when you quick tap Enter
on the menu item.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's have a quick call because I'm not seeing that here 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh gosh, I see what you mean now hahaha... when I don't put the event.preventDefault()
in.
without preventing default
Missed that part. Interesting... yeah okay, let me try something quick.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, we've updated the comment to explain why the Enter
key needs to be prevented. Here's an isolated/simplified demonstration of the issue:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the same thing I was running into here. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like the same thing I was running into here.
Yep! we were actually using one of those examples to help debug. I was quite surprised to see the events working this way after calling focus
but it explains what we were seeing in that thread.
e5e47cf
to
cc79b5c
Compare
@andy-hook I think this is ready now 😬 |
09248c4
to
868bc57
Compare
868bc57
to
e36f953
Compare
onCloseAutoFocus={(event) => { | ||
// prevent focusing dropdown trigger when it closes from a dialog trigger | ||
if (isDialogOpenRef.current) event.preventDefault(); | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@benoitgrelard We shouldn't really have to do this because the DropdownMenu
already has logic to prevent its trigger from focusing if there was a focus outside of it. However, the setTimeout
in FocusScope
for onCloseAutoFocus
is re-ordering events and breaking the expected behaviour here.
We have discussed removing the setTimeout
from FocusScope
given that v17 has been out for a while and we are a new modern library (still in alpha) but we're reluctant to make that change as part of this PR (not sure of the knock on effects in other primz).
We're going to leave this in the story for now to demonstrate the workaround but it would be good to discuss this in more detail with you when you return.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm more curious why we have to do it only in the non-modal scenario?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the modal
scenario traps focus in the dialog so when it tries to focus the dropdown trigger when the dropdopwn closes (onCloseAutoFocus
) it can't.
onCloseAutoFocus={(event) => { | ||
// prevent focusing dropdown trigger when it closes from a dialog trigger | ||
if (isDialogOpenRef.current) event.preventDefault(); | ||
}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm more curious why we have to do it only in the non-modal scenario?
if (itemSelectEvent.defaultPrevented) return; | ||
context.onRootClose(); | ||
if (itemSelectEvent.defaultPrevented) { | ||
isPointerDownRef.current = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure I understand fully, we're resetting here because the menu won't close, the item won't unmount and so the ref won't be reset automatically on remount?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the ref will always be reset automatically on remount, this is specifically for a case where someone prevents it from closing. Without this, this would break:
- on the same item
pointer down -> pointer up
event.preventDefault()
inonSelect
- on a different item
pointer down -> pointer move -> pointer up on the item from step 1
That pointer up on the item from step one would think they pointered down on it too because it wouldn't have been reset when it was kept open.
onPointerUp={composeEventHandlers(props.onPointerUp, (event) => { | ||
// Pointer down can move to a different menu item which should activate it on pointer up. | ||
// We dispatch a click for selection to allow composition with click based triggers. | ||
if (!isPointerDownRef.current) event.currentTarget?.click(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find it a bit odd that if users add an onClick
listener to the item, it will trigger even when it's not a click (down and up), I'm guessing that was the only way we managed to get it to work with Dialog
trigger?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing that was the only way we managed to get it to work with Dialog trigger?
Yes and I've also just realised this conveniently fixes #745 too.
I'm okay with it firing a click tbh because that's what we're logically determining to be a click on the item - the circumstances in which it would activate. I guess we can see what complaints we get here from consumers, if any.
Fixes #634
Fixes #745
While doing this, I noticed that the DX for composing multiple dialogs from menu items is not ideal. You cannot colocate the
Dialog
with the dropdown item that opens it otherwise the dialog will unmount when theDropdown
closes, which we knew but it makes these sorts ofDialog
wrappers impossible:However, this fix will at least make single/multiple possible and we can decide if the above can be achieved somehow later, if we think it's important.
Notes for release