-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[pickers] Avoid stealing focus on click away #13434
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
base: master
Are you sure you want to change the base?
Conversation
Deploy preview: https://deploy-preview-13434--material-ui-x.netlify.app/ Bundle size report
|
packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts
Outdated
Show resolved
Hide resolved
@@ -219,7 +220,8 @@ export const DigitalClock = React.forwardRef(function DigitalClock<TDate extends | |||
return; | |||
} | |||
const offsetTop = activeItem.offsetTop; | |||
if (autoFocus || !!focusedView) { | |||
if ((autoFocus || !!focusedView) && activeItem !== lastActiveRef.current) { |
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.
Fix the issue of stealing the focus when closing a picker with DigitalClock:
Screen.Recording.2024-06-10.at.15.37.51.mov
@@ -172,7 +173,7 @@ export const MultiSectionDigitalClockSection = React.forwardRef( | |||
const activeItem = containerRef.current.querySelector<HTMLElement>( | |||
'[role="option"][tabindex="0"], [role="option"][aria-selected="true"]', | |||
); | |||
if (active && autoFocus && activeItem) { | |||
if (activeItem && active && autoFocus && activeItem !== previousActive.current) { |
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.
Fix the issue of stealing the focus when closing a picker with MultiSectionDigitalClock:
Screen.Recording.2024-06-10.at.15.38.47.mov
packages/x-date-pickers/src/internals/components/PickersPopper.tsx
Outdated
Show resolved
Hide resolved
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.
LGTM! 🚢
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 solid!
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.
In HEAD, we restore the focus back to the trigger. e.g. https://mui.com/material-ui/react-menu/
Screen.Recording.2024-06-10.at.18.37.04.mov
It doesn't do it anymore:
Screen.Recording.2024-06-10.at.18.34.53.mov
A bug?
packages/x-date-pickers-pro/src/internals/hooks/useEnrichedRangePickerFieldProps.ts
Outdated
Show resolved
Hide resolved
Thank you for flagging this @oliviertassinari! 🙏 |
@oliviertassinari I've explored other solutions and here is the rundown:
Given these arguments, I think that the behavioral solution in this PR is valid and more correct than the current one. WDYT @flaviendelangle @arthurbalduini @joserodolfofreitas?
|
@LukasTy Thanks for the dive. In my view, the behavior before feels better (Angular Material and React Spectrum ). At least, the things that are important properties we want seem to be:
On the solution, I don't think that 1. (using a backdrop) is that much correlated to the root of the problem, this feels like taking a different path (which works, true). Now, it's not the end of the world, maybe it can work ok like this. At the root, there might be nothing to change in MUI X (I assume what we do here is to trigger ). The problem might really be with the FocusTrap logic. Maybe the logic that restores the focus should give up if that focus is already set outside of its boundary. I mean, this would make a lot of sense to me. It makes me think of mui/material-ui#35307. For this, we should involve the FocusTrap's ower? https://www.notion.so/mui-org/0c8156b0b1634ea5bfd903dd005ec1cf?v=89ea8d7b7e104bf8b3bb68a9edca5e16&p=fbe1aed295f748c19576d024e9a48c62&pm=s |
Hi! Is this fix still being considered? I just spent the better part of last week migrating from react-dates to this date picker, but that bug is a deal breaker for us. I haven't see any comments since June on this issue, I was wondering if maybe it had been forgotten? Thanks |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
Hi, thank you for reminding us about this problem. 🙏 |
Hello! Was there any progress on this issue in the meanwhile? If not, can the community help in anyway? |
This pull request has been inactive for 30 days. Please remove the stale label or leave a comment to keep it open. Otherwise, it will be closed in 15 days. |
This pull request has been closed due to 15 days of inactivity after being marked stale. |
I have given this a second shot. Exploring the existing approaches in different libraries, I have noticed two main behavior options (as noted in #13434 (comment)):
I have gone for the 2nd approach as it's the least UX change and could be treated as a bugfix, without a BC. I haven't looked into this improvement, since it is not strictly necessary and is a more obvious "breaking change", but I think it is necessary for the complete solution and could/should be done on the next major. As for when to close the Picker on scroll - it's debatable. We could do it only when the Picker leaves visible viewport. IMHO, it's a bit more friendly UX than closing immediately after a tiniest amount of scroll, especially given our more complex Picker views (i.e. DateTimeRangePicker). I'm open to suggestions and ideas on whether we should backport the fix to v7. 👍 |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
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.
Congrats (again) for the work on this one!
It's not an easy one to review, I tried in a few scenario and could not find issue 😬
@@ -785,4 +785,25 @@ describe('<DesktopDateRangePicker />', () => { | |||
expect(getPickerDay('17')).to.have.attribute('disabled'); | |||
}); | |||
}); | |||
it('should close the Picker and move focus to the text field when clicking it', async () => { |
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('should close the Picker and move focus to the text field when clicking it', async () => { | |
it('should close the Picker and move focus to the text field when clicking it', async () => { |
*/ | ||
const isInputHidden = (input: HTMLInputElement) => input.type === 'hidden'; | ||
|
||
export function isElementInteractive(element: HTMLElement) { |
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.
If it's only used in one package, not sure if it make sense to extract it.
Is it likely that we end up using it elsewhere?
Fixes #13332
Fixes #14801
Fixes #18356
stopPropagation
calls were preventing click away listener from working properly.focus()
calls in effects were stealing the focus before closing the popperPreview: https://deploy-preview-13434--material-ui-x.netlify.app/x/react-date-pickers/