-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[fields] Fix input focus when input is not on main document #10847
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
[fields] Fix input focus when input is not on main document #10847
Conversation
Deploy preview: https://deploy-preview-10847--material-ui-x.netlify.app/ |
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.
Thank you for your contribution! 🙏
The solution makes sense, but what do you think about also adding the following diff to fix picker focused button management as well as range picker behavior inside of a portal? 🤔
diff --git a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx
index 030cbc422..6c97db447 100644
--- a/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx
+++ b/packages/x-date-pickers-pro/src/internals/hooks/useDesktopRangePicker/useDesktopRangePicker.tsx
@@ -90,9 +90,11 @@ export const useDesktopRangePicker = <
const handleBlur = () => {
executeInTheNextEventLoopTick(() => {
+ const fieldCurrent = fieldContainerRef.current;
+ const popperCurrent = popperRef.current;
if (
- fieldContainerRef.current?.contains(getActiveElement(document)) ||
- popperRef.current?.contains(getActiveElement(document))
+ fieldCurrent?.contains(getActiveElement(fieldCurrent.ownerDocument)) ||
+ popperCurrent?.contains(getActiveElement(popperCurrent.ownerDocument))
) {
return;
}
diff --git a/packages/x-date-pickers/src/internals/components/PickersPopper.tsx b/packages/x-date-pickers/src/internals/components/PickersPopper.tsx
index 6152aa89c..6390657d0 100644
--- a/packages/x-date-pickers/src/internals/components/PickersPopper.tsx
+++ b/packages/x-date-pickers/src/internals/components/PickersPopper.tsx
@@ -359,7 +359,10 @@ export function PickersPopper(inProps: PickerPopperProps) {
}
if (open) {
- lastFocusedElementRef.current = getActiveElement(document);
+ lastFocusedElementRef.current = getActiveElement(
+ lastFocusedElementRef.current?.ownerDocument ??
+ (anchorEl instanceof HTMLElement ? anchorEl?.ownerDocument : undefined),
+ );
} else if (
lastFocusedElementRef.current &&
lastFocusedElementRef.current instanceof HTMLElement
@@ -372,7 +375,7 @@ export function PickersPopper(inProps: PickerPopperProps) {
}
});
}
- }, [open, role, shouldRestoreFocus]);
+ }, [anchorEl, open, role, shouldRestoreFocus]);
const [clickAwayRef, onPaperClick, onPaperTouchStart] = useClickAwayListener(
open,
Here is an adjusted codesandbox with showcased range picker.
If you modify the code in the pro codebase, technically, you should sign a CLA agreeing that the code you contributed will be used for commercial purposes, but if you agree that the change on pro codebase is trivial, this requirement can be omitted. 👌
In general, this change makes sense to me, but what do you think @flaviendelangle?
@LukasTy I can see that yes in your new sandbox there are also issues with the RangePicker and that your diff looks sensible to me and as you said it's a rather small change |
The fix looks great |
Yes, there is that problem. 🤔
In which case? |
I just want to replace if (inputRef.current && inputRef.current === inputRef.current.ownerDocument.activeElement) { With something higher level like: if (isActiveElement(inputRef) {} To reduce the risk of mistake
|
Makes sense. Will look into a possible alternative. 👌 Unless you have a diff to suggest. 🙈 This instance is changed in this PR, isn't it? 🤔 |
Yes, my point was that hardcoding those smarter solutions can often lead to someone forgetting to use the smart way when creating new code later on |
@@ -426,7 +426,7 @@ export const useField = < | |||
// On multi input range pickers we want to update selection range only for the active input | |||
// This helps to avoid the focus jumping on Safari https://github.com/mui/mui-x/issues/9003 | |||
// because WebKit implements the `setSelectionRange` based on the spec: https://bugs.webkit.org/show_bug.cgi?id=224425 | |||
if (inputRef.current === getActiveElement(document)) { | |||
if (inputRef.current === getActiveElement(inputRef.current.ownerDocument)) { |
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.
Could you use ownerDocument
util instead?
const doc = ownerDocument(nodeRef.current); |
UPD: didn't see the comments above, feel free to disregard if a different approach was suggested
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
This PR has been inactive for a while, so we’re going to close it for now. |
Fixes a bug where MUI datepickers would not accept keyboard interaction when loaded in a popup via React Portal. See bug reproduction code here: https://codesandbox.io/s/mui-datepickers-in-popup-window-via-react-portal-dx83lg?file=/src/App.js:0-3486
Instead of using the global
document
, instead use theinputRef.current
'sownerDocument
which accurately reflects the document the input is mounted on. This should have no effect to the "normal" usecase, as theninputRef.current.ownerDocument === document