I am trying to create a draggable Material UI dialog which includes in its contents an Autocomplete component. The result should look something like the following:
The desktop experience here is that when one drags the dialog (by grabbing the title area), the text field loses focus, and so the options Popper immediately disappears. However, the touch experience (tested iPhone 6 and iPad 7) is broken in that the text field remains focused while dragging, and so the popper doesn't disappear but also doesn't drag with the dialog:
Notice as a further weirdness that the text cursor (circled) lines up with the text field every time the dialog is grabbed but then does not move while the dragging is happening (this bug exhibits even without Autocomplete, so maybe beyond the scope of this question, but thought I'd mention for completeness).
I think I understand why this is happening: The popper is a child of body
in the DOM and not the draggable Paper
element, so it isn't being targeted the way one would naively hope. However, the fact remains that it is happening, and I would like a way to fix it, if possible.
Note that a bug has been filed here.
Code below:
import React from "react";
import {
Dialog,
DialogContent,
DialogContentText,
DialogTitle,
DialogActions,
Button,
Paper,
TextField,
} from "@material-ui/core";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Draggable from "react-draggable";
function ComboBox() {
return (
<Autocomplete
id="combo-box-demo"
options={top3Films}
getOptionLabel={(option) => option.title}
style={{ width: 300 }}
renderInput={(params) => (
<TextField {...params} label="Combo box" variant="outlined" />
)}
/>
);
}
const top3Films = [
{ title: "The Shawshank Redemption", year: 1994 },
{ title: "The Godfather", year: 1972 },
{ title: "The Godfather: Part II", year: 1974 },
];
const titleId = "draggable-title";
function DraggablePaper(props) {
// This is to quiet strict mode warnings about findDOMNode usage. See
// https://stackoverflow.com/a/63603903/12162258 for details
const nodeRef = React.useRef(null);
return (
<Draggable
handle={`#${titleId}`}
cancel={'[class*="MuiDialogContent-root"]'}
nodeRef={nodeRef}
>
<Paper ref={nodeRef} {...props} />
</Draggable>
);
}
function App() {
return (
<div>
<Dialog open={true} PaperComponent={DraggablePaper}>
<DialogTitle style={{ cursor: "move" }} id={titleId}>
Title
</DialogTitle>
<DialogContent>
<DialogContentText>Content text</DialogContentText>
<ComboBox />
</DialogContent>
<DialogActions>
<Button>Submit</Button>
<Button>Cancel</Button>
</DialogActions>
</Dialog>
</div>
);
}
export default App;