Draggable диалоги позволяют пользователю перемещать
модальные окна по экрану, обеспечивая более гибкий интерфейс. В MUI
(Material-UI) это достигается комбинацией компонентов
Dialog и Paper, а также использованием внешней
библиотеки react-draggable или встроенных возможностей MUI
через PaperComponent.
Компонент Dialog принимает свойство
PaperComponent, которое позволяет указать, какой компонент
будет использоваться в качестве “коробки” диалога. Для реализации
перетаскивания можно создать обёртку на базе Draggable:
import React from 'react';
import Dialog from '@mui/material/Dialog';
import DialogTitle from '@mui/material/DialogTitle';
import DialogContent from '@mui/material/DialogContent';
import Paper from '@mui/material/Paper';
import Draggable from 'react-draggable';
function PaperComponent(props) {
return (
<Draggable handle="#draggable-dialog-title" cancel={'[class*="MuiDialogContent-root"]'}>
<Paper {...props} />
</Draggable>
);
}
export default function DraggableDialog() {
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
return (
<div>
<button onCl ick={handleClickOpen}>Открыть диалог</button>
<Dialog
open={open}
onCl ose={handleClose}
PaperComponent={PaperComponent}
aria-labelledby="draggable-dialog-title"
>
<DialogTitle style={{ cursor: 'move' }} id="draggable-dialog-title">
Заголовок диалога
</DialogTitle>
<DialogContent>
Содержимое диалога можно перетаскивать по экрану.
</DialogContent>
</Dialog>
</div>
);
}
Разбор ключевых моментов:
handle="#draggable-dialog-title" в
Draggable указывает, что только заголовок диалога можно
использовать для перетаскивания. Это предотвращает случайное перемещение
при взаимодействии с контентом.cancel={'[class*="MuiDialogContent-root"]'} блокирует
перетаскивание при клике на контент.PaperComponent={PaperComponent} подключает кастомный
компонент для диалога, который поддерживает перетаскивание.Можно ограничить перемещение диалога, чтобы он не уходил за границы окна:
<Draggable
handle="#draggable-dialog-title"
bounds="parent"
cancel={'[class*="MuiDialogContent-root"]'}
>
<Paper {...props} />
</Draggable>
bounds="parent" заставляет диалог оставаться внутри
родительского контейнера.{ left, top, right, bottom }
для точного задания границ.Для улучшения UX можно настроить плавное движение с помощью
CSS-переходов или использовать проп position и события
onDrag:
<Draggable
handle="#draggable-dialog-title"
onD rag={(e, data) => console.log(data.x, data.y)}
cancel={'[class*="MuiDialogContent-root"]'}
>
<Paper style={{ transition: 'transform 0.2s ease-out' }} {...props} />
</Draggable>
transition добавляет анимацию при
перемещении.onDrag позволяет отслеживать текущее положение
диалога и при необходимости синхронизировать с другими
компонентами.Draggable диалоги полностью совместимы с DialogActions,
TextField, Select и другими элементами:
<Dialog
open={open}
onCl ose={handleClose}
PaperComponent={PaperComponent}
aria-labelledby="draggable-dialog-title"
>
<DialogTitle style={{ cursor: 'move' }} id="draggable-dialog-title">
Форма ввода
</DialogTitle>
<DialogContent>
<TextField label="Имя" fullWidth margin="dense" />
<TextField label="Email" fullWidth margin="dense" />
</DialogContent>
<DialogActions>
<button onCl ick={handleClose}>Отмена</button>
<button onCl ick={() => console.log('Сохранено')}>Сохранить</button>
</DialogActions>
</Dialog>
На мобильных устройствах перетаскивание может конфликтовать с жестами прокрутки. Рекомендуется отключать Draggable на небольших экранах:
const isMobile = window.innerWidth < 600;
<Dialog
open={open}
onCl ose={handleClose}
PaperComponent={isMobile ? Paper : PaperComponent}
>
Draggable диалоги в MUI обеспечивают гибкость интерфейса и повышают
интерактивность приложений. С помощью PaperComponent,
ограничений перемещения и адаптивной логики можно создать диалоги,
которые выглядят современно и ведут себя предсказуемо.