Модальное/диалоговое окно всплывающее из кнопки/элемента

Есть задача, где необходимо показать модальное окно, будто всплывающее из кнопки (в конечном результате отображается, по центру экрана), есть ли какие-то готовые реализации данного функционала в MUI или сторонние решение и если нет, то как подобное можно реализовать?

Подойдет анимация появления/закрытия как в MacOS: введите сюда описание изображения


Ответы (2 шт):

Автор решения: Franz

В MUI есть компонент Modal, который может использоваться для создания модальных окон. Однако, он не имеет встроенной анимации появления/закрытия.

Вы можете использовать сторонние библиотеки анимаций, такие как react-spring или framer-motion, чтобы добавить анимацию к вашему модальному окну.

Если вы хотите реализовать анимацию появления/закрытия как в MacOS, вы можете использовать анимацию "scale" и "opacity". Например, для появления модального окна вы можете использовать следующую анимацию:

  1. Установите начальное значение для модального окна:
transform: "scale(0.8)",
opacity: 0
  1. Создайте анимацию для появления модального окна:
transform: "scale(1)",
opacity: 1,
config: { tension: 300, friction: 20 }
  1. Примените анимацию к модальному окну при его открытии.

Для закрытия модального окна вы можете использовать обратную анимацию:

  1. Создайте анимацию для закрытия модального окна:
transform: "scale(0.8)",
opacity: 0,
config: { tension: 300, friction: 20 }
  1. Примените анимацию к модальному окну при его закрытии.

Обратите внимание, что вы можете настроить параметры анимации (например, "tension" и "friction") в зависимости от ваших потребностей.

→ Ссылка
Автор решения: Oliver Patterson

Ну вот наконец-то и ответ... Мы будем использовать Zoom transition и для его props мы можем передать style и изменить для него transfromOrigin в котором будут содержаться координаты, откуда должна начинаться анимация.

Координаты мы можем получить при клике на кнопку с помощью:

const rect = event.currentTarget.getBoundingClientRect();

В rect.left, rect.top находятся координаты левого верхнего угла элемента. Чтобы получить центр элемента нужно прибавить rect.width / 2 и rect.height / 2.


Edit dialog-show-animation

import { Dialog, Zoom, DialogTitle, DialogContent } from "@mui/material";
import { useState } from "react";

function DialogTest()
{
    const [ isDialogOpen, setIsDialogOpen ] = useState<boolean>(false);
    const [ clickPosition, setClickPosition ] = useState<{ x: number, y: number; }>({ x: 0, y: 0 });

    return (
        <>
            <button
                onClick={(event) =>
                {
                    const rect = event.currentTarget.getBoundingClientRect();

                    setClickPosition({
                        x: rect.left + rect.width / 2,
                        y: rect.top + rect.height / 2
                    });

                    setIsDialogOpen(true);
                }}
            >
                Test button
            </button>

            <Dialog
                open={isDialogOpen}
                onClose={() => setIsDialogOpen(false)}
                slots={{ transition: Zoom }}
                slotProps={{
                    transition:
                    {
                        style: { transformOrigin: `${ clickPosition.x }px ${ clickPosition.y }px` }
                    }
                }}
            >
                <DialogTitle>
                    Modal title
                </DialogTitle>

                <DialogContent>
                    Lorem ipsum dolor sit amet consectetur.
                </DialogContent>
            </Dialog>
        </>
    );
}

export default DialogTest;

(если кто-то может сделать так, чтобы прямо на SO можно было запустить - отредактируйте и спасибо вам)

→ Ссылка