From 6fd15e9a794b6a78293a146f2a623e8bb4a9b25e Mon Sep 17 00:00:00 2001 From: Daniel Valdivia <18384552+dvaldivia@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:53:32 -0700 Subject: [PATCH] Break Away Overlay from ModalBox (#1073) Signed-off-by: Daniel Valdivia --- src/components/ModalBox/ModalBox.styles.ts | 20 ------ src/components/ModalBox/index.tsx | 63 ++++++------------ src/components/Overlay/Overlay.styles.ts | 37 +++++++++++ src/components/Overlay/Overlay.types.ts | 25 ++++++++ src/components/Overlay/index.tsx | 74 ++++++++++++++++++++++ src/index.ts | 2 + 6 files changed, 158 insertions(+), 63 deletions(-) create mode 100644 src/components/Overlay/Overlay.styles.ts create mode 100644 src/components/Overlay/Overlay.types.ts create mode 100644 src/components/Overlay/index.tsx diff --git a/src/components/ModalBox/ModalBox.styles.ts b/src/components/ModalBox/ModalBox.styles.ts index d1649f8d6..c4b496036 100644 --- a/src/components/ModalBox/ModalBox.styles.ts +++ b/src/components/ModalBox/ModalBox.styles.ts @@ -18,26 +18,6 @@ import { css, Theme } from "@emotion/react"; import { CssProperties } from "../../../styled-system/types"; -export const modalOverlay = (theme: Theme) => - css({ - position: "fixed" as const, - zIndex: 1200, - width: "100vw", - height: "100vh", - top: 0, - left: 0, - backgroundColor: theme.colors["Color/Neutral/Bg/colorBgOverlay"], - display: "flex", - alignItems: "center", - justifyContent: "center", - opacity: 0, - backdropFilter: "blur(4px)", - "&.active": { - opacity: 1, - transition: "opacity 0.3s", - }, - }); - export const modalContainer = (theme: Theme, width: CssProperties["width"]) => css({ fontFamily: "'Geist', sans-serif", diff --git a/src/components/ModalBox/index.tsx b/src/components/ModalBox/index.tsx index 0d67ad1d3..d3e480082 100644 --- a/src/components/ModalBox/index.tsx +++ b/src/components/ModalBox/index.tsx @@ -14,15 +14,15 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { FC, useEffect, useMemo, useState } from "react"; +import { FC, useEffect, useState } from "react"; import { createPortal } from "react-dom"; -import { css, useTheme } from "@emotion/react"; +import { useTheme } from "@emotion/react"; import { useEscapeKey } from "../../global/hooks"; -import { overridePropsParse } from "../../global/utils"; import XIcon from "../../icons/XIcon"; -import { modalContainer, modalOverlay, modalTitleBar } from "./ModalBox.styles"; +import { modalContainer, modalTitleBar } from "./ModalBox.styles"; import { ModalBoxProps } from "./ModalBox.types"; +import Overlay from "../Overlay"; const ModalBox: FC = ({ onClose, @@ -38,59 +38,36 @@ const ModalBox: FC = ({ const theme = useTheme(); useEscapeKey(onClose); - const [displayOverlay, setDisplayOverlay] = useState(false); - - const overrideThemes = useMemo(() => { - if (sx) { - return css({ ...overridePropsParse(sx, theme) }); - } - - return {}; - }, [sx, theme]); - - const overlayStyles = modalOverlay(theme); const containerStyles = modalContainer( theme, widthLimit ? customMaxWidth : "100%", ); const titleStyles = modalTitleBar(theme); - useEffect(() => { - if (open) { - setTimeout(() => setDisplayOverlay(true), 100); - return; - } - setDisplayOverlay(false); - }, [open]); - if (!open) { return null; } const modalBox = ( -
-
-
-
-
- {titleIcon} - {title} -
- + +
+
+
+ {titleIcon} + {title}
-
{children}
+
+
{children}
-
+ ); return createPortal(modalBox, document.body); diff --git a/src/components/Overlay/Overlay.styles.ts b/src/components/Overlay/Overlay.styles.ts new file mode 100644 index 000000000..0dae90631 --- /dev/null +++ b/src/components/Overlay/Overlay.styles.ts @@ -0,0 +1,37 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { css, Theme } from "@emotion/react"; + +export const modalOverlay = (theme: Theme) => + css({ + position: "fixed" as const, + zIndex: 1200, + width: "100vw", + height: "100vh", + top: 0, + left: 0, + backgroundColor: theme.colors["Color/Neutral/Bg/colorBgOverlay"], + display: "flex", + alignItems: "center", + justifyContent: "center", + opacity: 0, + backdropFilter: "blur(4px)", + "&.active": { + opacity: 1, + transition: "opacity 0.3s", + }, + }); diff --git a/src/components/Overlay/Overlay.types.ts b/src/components/Overlay/Overlay.types.ts new file mode 100644 index 000000000..dbcf7b5f7 --- /dev/null +++ b/src/components/Overlay/Overlay.types.ts @@ -0,0 +1,25 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react"; +import { OverrideTheme } from "../../global/global.types"; + +export interface OverlayProps { + onClose: () => void; + open: boolean; + children: React.ReactNode; + backgroundOverlay?: boolean; + sx?: OverrideTheme; +} diff --git a/src/components/Overlay/index.tsx b/src/components/Overlay/index.tsx new file mode 100644 index 000000000..e11bbf640 --- /dev/null +++ b/src/components/Overlay/index.tsx @@ -0,0 +1,74 @@ +// This file is part of MinIO Design System +// Copyright (c) 2024 MinIO, Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import { FC, useEffect, useMemo, useState } from "react"; +import { createPortal } from "react-dom"; +import { css, useTheme } from "@emotion/react"; + +import { useEscapeKey } from "../../global/hooks"; +import { overridePropsParse } from "../../global/utils"; +import { modalOverlay } from "./Overlay.styles"; +import { OverlayProps } from "./Overlay.types"; + +const Overlay: FC = ({ + onClose, + open, + children, + backgroundOverlay = true, + sx, +}) => { + const theme = useTheme(); + useEscapeKey(onClose); + + const [displayOverlay, setDisplayOverlay] = useState(false); + + const overrideThemes = useMemo(() => { + if (sx) { + return css({ ...overridePropsParse(sx, theme) }); + } + + return {}; + }, [sx, theme]); + + const overlayStyles = modalOverlay(theme); + + useEffect(() => { + if (open) { + setTimeout(() => setDisplayOverlay(true), 100); + return; + } + setDisplayOverlay(false); + }, [open]); + + if (!open) { + return null; + } + + const Overlay = ( +
+
+ {children} +
+
+ ); + + return createPortal(Overlay, document.body); +}; + +export default Overlay; diff --git a/src/index.ts b/src/index.ts index 1c67ab019..8ddb1f9eb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -74,6 +74,7 @@ export { default as Loader } from "./components/Loader"; export { default as LoginWrapper } from "./components/LoginWrapper"; export { default as MDSCacheProvider } from "./components/MDSCacheProvider"; export { default as ModalBox } from "./components/ModalBox"; +export { default as Overlay } from "./components/Overlay"; export { default as NotificationAlert } from "./components/NotificationAlert"; export { default as NotificationCount } from "./components/NotificationCount"; export { default as Notifications } from "./components/Notifications"; @@ -132,6 +133,7 @@ export * from "./components/InputLabel/InputLabel.types"; export * from "./components/Link/Link.types"; export * from "./components/LinkButton/LinkButton.types"; export * from "./components/ModalBox/ModalBox.types"; +export * from "./components/Overlay/Overlay.types"; export * from "./components/NotificationAlert/NotificationAlert.types"; export * from "./components/Notifications/Notifications.types"; export * from "./components/PageHeader/PageHeader.types";