Skip to content

Commit

Permalink
Break Away Overlay from ModalBox (#1073)
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Valdivia <[email protected]>
  • Loading branch information
dvaldivia authored Oct 30, 2024
1 parent 101b804 commit 6fd15e9
Show file tree
Hide file tree
Showing 6 changed files with 158 additions and 63 deletions.
20 changes: 0 additions & 20 deletions src/components/ModalBox/ModalBox.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
63 changes: 20 additions & 43 deletions src/components/ModalBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

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<ModalBoxProps> = ({
onClose,
Expand All @@ -38,59 +38,36 @@ const ModalBox: FC<ModalBoxProps> = ({
const theme = useTheme();
useEscapeKey(onClose);

const [displayOverlay, setDisplayOverlay] = useState<boolean>(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 = (
<div css={[overrideThemes]} className={"modalBoxMain"}>
<div
css={backgroundOverlay ? overlayStyles : {}}
className={`overlay ${displayOverlay ? "active" : ""}`}
>
<div css={containerStyles} className={"modalContainer"}>
<div css={titleStyles} className={"modalTitleBar"}>
<div className={"title"}>
{titleIcon}
{title}
</div>
<button
className={"closeModalButton"}
id={"close"}
onClick={onClose}
>
<XIcon />
</button>
<Overlay
sx={sx}
onClose={onClose}
open={open}
backgroundOverlay={backgroundOverlay}
>
<div css={containerStyles} className={"modalContainer"}>
<div css={titleStyles} className={"modalTitleBar"}>
<div className={"title"}>
{titleIcon}
{title}
</div>
<div className={"dialogContent"}>{children}</div>
<button className={"closeModalButton"} id={"close"} onClick={onClose}>
<XIcon />
</button>
</div>
<div className={"dialogContent"}>{children}</div>
</div>
</div>
</Overlay>
);

return createPortal(modalBox, document.body);
Expand Down
37 changes: 37 additions & 0 deletions src/components/Overlay/Overlay.styles.ts
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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",
},
});
25 changes: 25 additions & 0 deletions src/components/Overlay/Overlay.types.ts
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
import React from "react";
import { OverrideTheme } from "../../global/global.types";

export interface OverlayProps {
onClose: () => void;
open: boolean;
children: React.ReactNode;
backgroundOverlay?: boolean;
sx?: OverrideTheme;
}
74 changes: 74 additions & 0 deletions src/components/Overlay/index.tsx
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

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<OverlayProps> = ({
onClose,
open,
children,
backgroundOverlay = true,
sx,
}) => {
const theme = useTheme();
useEscapeKey(onClose);

const [displayOverlay, setDisplayOverlay] = useState<boolean>(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 = (
<div css={[overrideThemes]} className={"OverlayMain"}>
<div
css={backgroundOverlay ? overlayStyles : {}}
className={`overlay ${displayOverlay ? "active" : ""}`}
>
{children}
</div>
</div>
);

return createPortal(Overlay, document.body);
};

export default Overlay;
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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";
Expand Down

0 comments on commit 6fd15e9

Please sign in to comment.