+
{React.cloneElement(child, {
// @ts-expect-error React.cloneElement issue
ref: child.ref
@@ -87,7 +41,7 @@ const wrappedChildren = (children: React.ReactNode, flex: Props["flex"]) => {
}
: null,
})}
-
+
);
});
};
@@ -95,6 +49,7 @@ const wrappedChildren = (children: React.ReactNode, flex: Props["flex"]) => {
const ModalFooter = ({ dataTest, children, flex = "0 1 auto" }: Props) => {
const { isMobileFullPage, setFooterHeight } = React.useContext(ModalContext);
const containerRef = React.useRef(null);
+ const childrenLength = React.Children.toArray(children).length;
useModalContextFunctions();
@@ -112,14 +67,21 @@ const ModalFooter = ({ dataTest, children, flex = "0 1 auto" }: Props) => {
}, [setFooterHeight]);
return (
- 1 ? "lm:justify-between" : "lm:justify-end",
+ !isMobileFullPage && "lm:rounded-b-modal",
+ "[&_.orbit-modal-footer-child:last-of-type]:p-0",
+ )}
ref={containerRef}
data-test={dataTest}
- isMobileFullPage={isMobileFullPage}
- childrenLength={React.Children.toArray(children).length}
>
{flex && wrappedChildren(children, flex)}
-
+
);
};
diff --git a/packages/orbit-components/src/Modal/ModalHeader/index.js.flow b/packages/orbit-components/src/Modal/ModalHeader/index.js.flow
index 7f840a1933..4147138332 100644
--- a/packages/orbit-components/src/Modal/ModalHeader/index.js.flow
+++ b/packages/orbit-components/src/Modal/ModalHeader/index.js.flow
@@ -1,6 +1,5 @@
// @flow
import * as React from "react";
-import type { StyledComponent } from "styled-components";
import type { Globals } from "../../common/common.js.flow";
@@ -15,9 +14,3 @@ export type Props = {|
|};
declare export default React.ComponentType;
-
-declare export var MobileHeader: StyledComponent;
-
-declare export var StyledModalHeader: StyledComponent;
-
-declare export var ModalHeading: StyledComponent;
diff --git a/packages/orbit-components/src/Modal/ModalHeader/index.tsx b/packages/orbit-components/src/Modal/ModalHeader/index.tsx
index 7f939ff894..09cfbf9703 100644
--- a/packages/orbit-components/src/Modal/ModalHeader/index.tsx
+++ b/packages/orbit-components/src/Modal/ModalHeader/index.tsx
@@ -1,167 +1,48 @@
"use client";
import * as React from "react";
-import styled, { css } from "styled-components";
+import cx from "clsx";
-import transition from "../../utils/transition";
import Text from "../../Text";
-import defaultTheme from "../../defaultTheme";
-import media from "../../utils/mediaQuery";
-import { StyledModalSection } from "../ModalSection";
-import { left, right, rtlSpacing } from "../../utils/rtl";
import { ModalContext } from "../ModalContext";
import useModalContextFunctions from "../helpers/useModalContextFunctions";
import type { Props } from "./types";
-export const ModalHeading = styled.h2`
- ${({ theme }) => css`
- margin: 0;
- font-size: ${theme.orbit.fontSizeHeadingTitle2};
- font-weight: ${theme.orbit.fontWeightHeadingTitle2};
- line-height: ${theme.orbit.lineHeightHeadingTitle2};
- color: ${theme.orbit.colorHeading};
- ${media.largeMobile(css`
- font-size: ${theme.orbit.fontSizeHeadingTitle1};
- font-weight: ${theme.orbit.fontWeightHeadingTitle1};
- line-height: ${theme.orbit.lineHeightHeadingTitle1};
- `)};
- `}
-`;
-
-ModalHeading.defaultProps = {
- theme: defaultTheme,
-};
-
-// TODO: create token marginModalTitle and marginModalTitleWithIllustration
-const ModalTitle = styled.div<{ illustration?: boolean }>`
- ${({ theme, illustration }) => css`
- margin-top: ${illustration && theme.orbit.spaceMedium};
-
- ${ModalHeading} {
- padding-${right}: ${theme.orbit.spaceXLarge};
- }
-
- ${media.desktop(css`
- ${ModalHeading} {
- padding: 0;
- }
- `)};
- `}
-`;
-
-ModalTitle.defaultProps = {
- theme: defaultTheme,
-};
-
-const ModalDescription = styled.div`
- margin-top: ${({ theme }) => theme.orbit.spaceXSmall};
-`;
-
-ModalDescription.defaultProps = {
- theme: defaultTheme,
-};
-
-const getModalHeaderPadding =
- (desktop = false) =>
- ({ theme, suppressed }) => {
- if (desktop) {
- if (suppressed) {
- return theme.orbit.spaceXLarge;
- }
- return `${theme.orbit.spaceXLarge} ${theme.orbit.spaceXLarge} 0 ${theme.orbit.spaceXLarge}`;
- }
- if (suppressed) {
- return `${theme.orbit.spaceXLarge} ${theme.orbit.spaceMedium}`;
- }
- return `${theme.orbit.spaceLarge} ${theme.orbit.spaceMedium} 0 ${theme.orbit.spaceMedium}`;
- };
-
-export const StyledModalHeader = styled.div<{
- suppressed?: Props["suppressed"];
+export const ModalHeaderWrapper = ({
+ className,
+ suppressed,
+ isMobileFullPage,
+ dataTest,
+ children,
+}: {
+ className?: string;
+ suppressed?: boolean;
isMobileFullPage?: boolean;
- illustration?: boolean;
-}>`
- ${({ theme, suppressed, isMobileFullPage }) => css`
- width: 100%;
- display: block;
- padding: ${rtlSpacing(getModalHeaderPadding()({ theme, suppressed }))};
- border-top-left-radius: ${!isMobileFullPage && "12px"};
- border-top-right-radius: ${!isMobileFullPage && "12px"};
- box-sizing: border-box;
- background-color: ${suppressed ? theme.orbit.paletteCloudLight : theme.orbit.paletteWhite};
-
- & ~ ${StyledModalSection}:first-of-type {
- border-top: ${suppressed && `1px solid ${theme.orbit.paletteCloudNormal}`};
- border-top-left-radius: 0;
- border-top-right-radius: 0;
- margin-top: ${suppressed && "0!important"};
- }
-
- ${media.largeMobile(css`
- padding: ${rtlSpacing(getModalHeaderPadding(true)({ theme, suppressed }))};
-
- & ~ ${StyledModalSection}:first-of-type {
- border-top-left-radius: 0;
- border-top-right-radius: 0;
- }
- `)};
- `}
-`;
-
-StyledModalHeader.defaultProps = {
- theme: defaultTheme,
-};
-
-export const MobileHeader = styled.div<{ isMobileFullPage?: boolean }>`
- ${({ theme, isMobileFullPage }) => css`
- display: inline-block;
- position: fixed;
- visibility: hidden;
- height: 52px;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- top: ${isMobileFullPage ? "0" : "16px"};
- ${right}: 48px;
- ${left}: 0;
- font-family: ${theme.orbit.fontFamily};
- font-weight: ${theme.orbit.fontWeightHeadingDisplay};
- font-size: 18px;
- color: ${theme.orbit.colorHeading};
- line-height: 52px;
- box-sizing: border-box;
- padding: ${rtlSpacing(`0 0 0 ${theme.orbit.spaceLarge}`)};
- opacity: 0;
- transition: ${transition(["top", "opacity", "visibility"], "fast", "ease-in-out")};
- z-index: 800;
-
- ${media.largeMobile(css`
- left: auto;
- right: auto;
- padding: 0;
- `)};
- `}
-`;
-
-MobileHeader.defaultProps = {
- theme: defaultTheme,
-};
-
-const getModalHeaderContentMargin = ({ hasHeader, hasDescription, hasChildren }) => {
- if (!hasHeader && hasChildren) return "0";
-
- return hasDescription ? "32px" : "16px";
+ dataTest?: string;
+ children?: React.ReactNode;
+}) => {
+ return (
+
+ {children}
+
+ );
};
-const StyledModalHeaderContent = styled.div<{
- hasHeader: boolean;
- hasDescription: boolean;
- hasChildren: boolean;
-}>`
- margin-top: ${({ hasHeader, hasDescription, hasChildren }) =>
- getModalHeaderContentMargin({ hasHeader, hasDescription, hasChildren })};
-`;
-
const ModalHeader = ({
illustration,
suppressed,
@@ -182,43 +63,59 @@ const ModalHeader = ({
};
}, [title, setHasModalTitle]);
- const hasHeader = title || description;
+ const hasHeader = Boolean(title || description);
return (
-
{illustration}
{hasHeader && (
-
- {title && {title}}
+
+ {title && (
+
+ {title}
+
+ )}
{description && (
-
+
{description}
-
+
)}
-
+
)}
{children && (
-
+
{children}
-
+
)}
{title && hasMobileHeader && (
-
+
{title}
-
+
)}
-
+
);
};
diff --git a/packages/orbit-components/src/Modal/ModalSection/index.js.flow b/packages/orbit-components/src/Modal/ModalSection/index.js.flow
index 34e46a4076..2ae73f624a 100644
--- a/packages/orbit-components/src/Modal/ModalSection/index.js.flow
+++ b/packages/orbit-components/src/Modal/ModalSection/index.js.flow
@@ -1,6 +1,5 @@
// @flow
import * as React from "react";
-import type { StyledComponent } from "styled-components";
import type { Globals } from "../../common/common.js.flow";
@@ -11,5 +10,3 @@ export type Props = {|
|};
declare export default React.ComponentType;
-
-declare export var StyledModalSection: StyledComponent;
diff --git a/packages/orbit-components/src/Modal/ModalSection/index.tsx b/packages/orbit-components/src/Modal/ModalSection/index.tsx
index 25ad7f1908..067ce4d1ab 100644
--- a/packages/orbit-components/src/Modal/ModalSection/index.tsx
+++ b/packages/orbit-components/src/Modal/ModalSection/index.tsx
@@ -1,70 +1,56 @@
"use client";
import * as React from "react";
-import styled, { css } from "styled-components";
+import cx from "clsx";
-import defaultTheme from "../../defaultTheme";
-import media from "../../utils/mediaQuery";
-import { StyledModalFooter } from "../ModalFooter";
import { ModalContext } from "../ModalContext";
import useModalContextFunctions from "../helpers/useModalContextFunctions";
import type { Props } from "./types";
-export const StyledModalSection = styled.section<{
+export const ModalSectionWrapper = ({
+ className,
+ children,
+ suppressed,
+ closable,
+ isMobileFullPage,
+ dataTest,
+}: {
+ className?: string;
+ children: React.ReactNode;
suppressed?: boolean;
closable?: boolean;
isMobileFullPage?: boolean;
-}>`
- ${({ theme, suppressed, closable, isMobileFullPage }) => css`
- width: 100%;
- padding: ${`${theme.orbit.spaceLarge} ${theme.orbit.spaceMedium}`};
- background-color: ${suppressed ? theme.orbit.paletteCloudLight : theme.orbit.paletteWhite};
- border-bottom: 1px solid ${theme.orbit.paletteCloudNormal};
- box-sizing: border-box;
-
- &:first-of-type {
- border-top: ${suppressed && `1px solid ${theme.orbit.paletteCloudNormal}`};
- border-top-left-radius: ${!isMobileFullPage && "12px"};
- border-top-right-radius: ${!isMobileFullPage && "12px"};
- margin-top: ${suppressed && closable && theme.orbit.spaceLarge};
- }
-
- &:last-of-type {
- border-bottom: ${suppressed ? `1px solid ${theme.orbit.paletteCloudNormal}` : "0"};
- border-bottom-left-radius: ${!isMobileFullPage && "12px"};
- border-bottom-right-radius: ${!isMobileFullPage && "12px"};
- & ~ ${StyledModalFooter} {
- margin-top: ${suppressed && theme.orbit.spaceMedium};
- }
- &:not(:last-child) {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- }
- }
-
- ${media.largeMobile(css`
- padding: ${theme.orbit.spaceXLarge};
-
- &:first-of-type {
- margin-top: ${((suppressed && closable) || suppressed) && theme.orbit.spaceXXLarge};
- border-top-left-radius: ${!isMobileFullPage && "9px"};
- border-top-right-radius: ${!isMobileFullPage && "9px"};
- }
-
- &:last-of-type {
- border-bottom-left-radius: ${!isMobileFullPage && "9px"};
- border-bottom-right-radius: ${!isMobileFullPage && "9px"};
- & ~ ${StyledModalFooter} {
- padding-top: ${!suppressed && "0"};
- margin-top: 0;
- }
- }
- `)};
- `}
-`;
-
-StyledModalSection.defaultProps = {
- theme: defaultTheme,
+ dataTest?: string;
+}) => {
+ return (
+
+ );
};
const ModalSection = ({ children, suppressed, dataTest }: Props) => {
@@ -87,14 +73,14 @@ const ModalSection = ({ children, suppressed, dataTest }: Props) => {
}, [removeHasModalSection]);
return (
-
{children}
-
+
);
};
diff --git a/packages/orbit-components/src/Modal/__tests__/index.test.tsx b/packages/orbit-components/src/Modal/__tests__/index.test.tsx
index 4b6d75ddf1..2aab56d2bd 100644
--- a/packages/orbit-components/src/Modal/__tests__/index.test.tsx
+++ b/packages/orbit-components/src/Modal/__tests__/index.test.tsx
@@ -17,8 +17,6 @@ jest.mock("../../hooks/useMediaQuery", () => {
const mockUseMediaQuery = useMediaQuery;
describe("Modal", () => {
- const user = userEvent.setup();
-
it("should have expected DOM output", () => {
render(
@@ -52,6 +50,7 @@ describe("Modal", () => {
});
it("should be able to focus content", async () => {
+ const user = userEvent.setup();
jest.useFakeTimers();
render(
@@ -127,7 +126,10 @@ describe("Modal", () => {
});
it("should call callback function when clicking on close button", async () => {
+ // Needed the pointerEventsCheck to be 0 because of JestDOM not being able to detect pointer events definition on ModalCloseButton
+ const user = userEvent.setup({ pointerEventsCheck: 0 });
const onClose = jest.fn();
+
render(
content
diff --git a/packages/orbit-components/src/Modal/index.tsx b/packages/orbit-components/src/Modal/index.tsx
index 277ebbcac0..d984c7184d 100644
--- a/packages/orbit-components/src/Modal/index.tsx
+++ b/packages/orbit-components/src/Modal/index.tsx
@@ -1,296 +1,42 @@
"use client";
import * as React from "react";
-import styled, { css } from "styled-components";
+import cx from "clsx";
import { ModalContext } from "./ModalContext";
-import { MobileHeader, StyledModalHeader, ModalHeading } from "./ModalHeader";
-import { StyledModalFooter } from "./ModalFooter";
-import { StyledModalSection } from "./ModalSection";
import ModalCloseButton from "./ModalCloseButton";
import { SIZES, CLOSE_BUTTON_DATA_TEST } from "./consts";
import KEY_CODE_MAP from "../common/keyMaps";
-import defaultTheme from "../defaultTheme";
-import media from "../utils/mediaQuery";
-import { right } from "../utils/rtl";
-import transition from "../utils/transition";
import useRandomId from "../hooks/useRandomId";
import useMediaQuery from "../hooks/useMediaQuery";
import FOCUSABLE_ELEMENT_SELECTORS from "../hooks/useFocusTrap/consts";
import usePrevious from "../hooks/usePrevious";
import useLockScrolling from "../hooks/useLockScrolling";
import type { Instance, Props } from "./types";
-
-const getSizeToken = ({ size, theme }: { size: Props["size"]; theme: typeof defaultTheme }) => {
- const tokens = {
- [SIZES.EXTRASMALL]: "360px",
- [SIZES.SMALL]: theme.orbit.widthModalSmall,
- [SIZES.NORMAL]: theme.orbit.widthModalNormal,
- [SIZES.LARGE]: theme.orbit.widthModalLarge,
- [SIZES.EXTRALARGE]: theme.orbit.widthModalExtraLarge,
- };
-
- if (!size) return null;
-
- return tokens[size];
-};
-
-const ModalBody = styled.div<{ autoFocus?: boolean; isMobileFullPage: Props["isMobileFullPage"] }>`
- ${({ theme, isMobileFullPage }) => css`
- width: 100%;
- height: 100%;
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- z-index: ${theme.orbit.zIndexModalOverlay};
- box-sizing: border-box;
- outline: none;
- overflow-x: hidden;
- background-color: ${!isMobileFullPage && "rgba(0, 0, 0, 0.5)"};
- font-family: ${theme.orbit.fontFamily};
- -webkit-overflow-scrolling: auto;
- ${media.largeMobile(css`
- overflow-y: auto;
- padding: ${theme.orbit.spaceXXLarge};
- background-color: rgba(0, 0, 0, 0.5);
- `)};
- `}
-`;
-
-ModalBody.defaultProps = {
- theme: defaultTheme,
-};
-
-const ModalWrapper = styled.div<{
- isMobileFullPage: Props["isMobileFullPage"];
- disableAnimation?: boolean;
- loaded: boolean;
- fixedFooter: Props["fixedFooter"];
- size: Props["size"];
-}>`
- ${({ isMobileFullPage, disableAnimation, loaded }) => css`
- box-sizing: border-box;
- min-height: 100%;
- display: flex;
- align-items: flex-start;
- margin: 0 auto;
- position: fixed;
- width: 100%;
- border-top-left-radius: ${!isMobileFullPage && "12px"};
- border-top-right-radius: ${!isMobileFullPage && "12px"};
- ${disableAnimation
- ? css`
- top: ${!isMobileFullPage && "32px"};
- `
- : css`
- transition: ${transition(["top"], "normal", "ease-in-out")};
- top: ${loaded ? !isMobileFullPage && "32px" : "100%"};
- `}
-
- ${media.largeMobile(css`
- position: relative;
- top: 0;
- max-width: ${getSizeToken};
- align-items: center;
- `)};
- `}
-`;
-
-ModalWrapper.defaultProps = {
- theme: defaultTheme,
-};
-
-const CloseContainer = styled.div<{
- scrolled?: boolean;
- fixedClose?: boolean;
- size?: Props["size"];
- isMobileFullPage?: Props["isMobileFullPage"];
- modalWidth?: number;
-}>`
- ${({ theme, scrolled, fixedClose, isMobileFullPage, modalWidth, size }) => css`
- display: flex;
- ${
- fixedClose || scrolled
- ? css`
- position: fixed;
- `
- : css`
- position: absolute;
- `
- };
- position: ${fixedClose || scrolled ? "fixed" : "absolute"};
- top: ${!isMobileFullPage && (fixedClose || scrolled) ? "32px" : "0"};
- right: 0;
- z-index: 800;
- justify-content: flex-end;
- align-items: center;
- box-sizing: border-box;
- height: 52px;
- width: 100%;
- max-width: ${modalWidth ? `${modalWidth}px` : getSizeToken({ size, theme })};
- box-shadow: ${scrolled && theme.orbit.boxShadowFixed};
- background-color: ${scrolled && theme.orbit.paletteWhite};
- border-top-left-radius: ${!isMobileFullPage && "12px"};
- border-top-right-radius: ${!isMobileFullPage && "12px"};
- transition: ${transition(["box-shadow", "background-color"], "fast", "ease-in-out")};
- pointer-events: none;
-
-
- ${media.largeMobile(css`
- top: ${(fixedClose || scrolled) && "0"};
- right: ${(fixedClose || scrolled) && "auto"};
- border-radius: 0;
- `)};
-
- & + ${StyledModalSection}:first-of-type {
- padding-top: 52px;
- border-top: 0;
- margin: 0;
- }
-
- .orbit-button-primitive {
- pointer-events: auto;
- margin-${right}: ${theme.orbit.spaceXXSmall};
-
- & svg {
- transition: ${transition(["color"], "fast", "ease-in-out")};
- color: ${theme.orbit.paletteInkNormal};
- }
-
- &:hover svg {
- color: ${theme.orbit.paletteInkLightHover};
- }
-
- &:active svg {
- color: ${theme.orbit.paletteInkLightActive};
- }
- }
-`}
-`;
-
-CloseContainer.defaultProps = {
- theme: defaultTheme,
-};
-
-export const ModalWrapperContent = styled.div<{
- isMobileFullPage: Props["isMobileFullPage"];
- fixedFooter: Props["fixedFooter"];
- footerHeight: number;
- fullyScrolled?: boolean;
- scrolled?: boolean;
- fixedClose?: boolean;
- size: Props["size"];
- modalWidth: number;
- hasModalSection?: boolean;
-}>`
- ${({
- theme,
- isMobileFullPage,
- fixedFooter,
- footerHeight,
- size,
- fullyScrolled,
- scrolled,
- modalWidth,
- hasModalSection,
- }) => css`
- position: absolute;
- box-sizing: border-box;
- border-top-left-radius: ${!isMobileFullPage && "12px"};
- border-top-right-radius: ${!isMobileFullPage && "12px"};
- background-color: ${theme.orbit.backgroundModal};
- font-family: ${theme.orbit.fontFamily};
- width: 100%;
- ${isMobileFullPage
- ? css`
- max-height: 100%;
- top: 0;
- `
- : css`
- max-height: calc(
- 100% - ${theme.orbit.spaceXLarge} -
- ${`${fixedFooter && Boolean(footerHeight) ? footerHeight : 0}px`}
- );
- `};
- bottom: ${`${
- (!isMobileFullPage ? parseInt(theme.orbit.spaceXLarge, 10) : 0) +
- (fixedFooter && Boolean(footerHeight) ? footerHeight : 0)
- }px`};
- box-shadow: ${theme.orbit.boxShadowOverlay};
- overflow-y: auto;
- overflow-x: hidden;
-
- ${fixedFooter &&
- footerHeight &&
- css`
- ${StyledModalFooter} {
- bottom: 0;
- padding: ${theme.orbit.spaceMedium};
- box-shadow: ${fullyScrolled
- ? `inset 0 1px 0 ${theme.orbit.paletteCloudNormal}, ${theme.orbit.boxShadowFixedReverse}`
- : `inset 0 0 0 transparent, ${theme.orbit.boxShadowFixedReverse}`};
- position: fixed;
- transition: ${transition(["box-shadow"], "fast", "ease-in-out")};
- }
- ${StyledModalSection}:last-of-type {
- padding-bottom: ${theme.orbit.spaceLarge};
- margin-bottom: 0;
- }
- `};
-
- ${MobileHeader} {
- top: ${!isMobileFullPage && scrolled && theme.orbit.spaceXLarge};
- opacity: ${scrolled && "1"};
- visibility: ${scrolled && "visible"};
- transition: ${scrolled &&
- css`
- ${transition(["top"], "normal", "ease-in-out")},
- ${transition(["opacity", "visibility"], "fast", "ease-in-out")}
- `};
- }
-
- ${StyledModalHeader} {
- margin-bottom: ${!hasModalSection && theme.orbit.spaceXLarge};
- }
-
- ${media.largeMobile(css`
- position: relative;
- bottom: auto;
- border-radius: ${!isMobileFullPage && "9px"};
- padding-bottom: 0;
- height: auto;
- overflow: visible;
- max-height: 100%;
- ${StyledModalSection}:last-of-type {
- padding-bottom: ${theme.orbit.spaceXXLarge};
- margin-bottom: ${fixedFooter ? `${footerHeight}px` : "0"};
- &::after {
- content: none;
- }
- }
- ${StyledModalHeader} {
- margin-bottom: ${!hasModalSection && fixedFooter ? `${footerHeight}px` : "0"};
- }
- ${StyledModalFooter} {
- padding: ${fixedFooter
- ? `${theme.orbit.spaceXLarge} ${theme.orbit.spaceXLarge}!important`
- : theme.orbit.spaceXLarge};
- max-width: ${modalWidth ? `${modalWidth}px` : getSizeToken({ size, theme })};
- position: ${fixedFooter && fullyScrolled && "absolute"};
- box-shadow: ${fullyScrolled && "none"};
- }
- ${MobileHeader} {
- top: ${scrolled ? "0" : `-${theme.orbit.spaceXXLarge}`};
- width: ${`calc(${modalWidth}px - 48px - ${theme.orbit.spaceXXLarge})`};
- }
- `)};
- `}
-`;
-
-ModalWrapperContent.defaultProps = {
- theme: defaultTheme,
+import useTheme from "../hooks/useTheme";
+
+const maxWidthClasses: {
+ [K in SIZES | "largeMobile" | "footer"]: K extends SIZES ? string : Record;
+} = {
+ [SIZES.EXTRASMALL]: "max-w-modal-extra-small",
+ [SIZES.SMALL]: "max-w-modal-small",
+ [SIZES.NORMAL]: "max-w-modal-normal",
+ [SIZES.LARGE]: "max-w-modal-large",
+ [SIZES.EXTRALARGE]: "max-w-modal-extra-large",
+ largeMobile: {
+ [SIZES.EXTRASMALL]: "lm:max-w-modal-extra-small",
+ [SIZES.SMALL]: "lm:max-w-modal-small",
+ [SIZES.NORMAL]: "lm:max-w-modal-normal",
+ [SIZES.LARGE]: "lm:max-w-modal-large",
+ [SIZES.EXTRALARGE]: "lm:max-w-modal-extra-large",
+ },
+ footer: {
+ [SIZES.EXTRASMALL]: "lm:[&_.orbit-modal-footer]:max-w-modal-extra-small",
+ [SIZES.SMALL]: "lm:[&_.orbit-modal-footer]:max-w-modal-small",
+ [SIZES.NORMAL]: "lm:[&_.orbit-modal-footer]:max-w-modal-normal",
+ [SIZES.LARGE]: "lm:[&_.orbit-modal-footer]:max-w-modal-large",
+ [SIZES.EXTRALARGE]: "lm:[&_.orbit-modal-footer]:max-w-modal-extra-large",
+ },
};
const OFFSET = 40;
@@ -333,6 +79,7 @@ const Modal = React.forwardRef(
const modalContent = React.useRef(null);
const modalBody = React.useRef(null);
const modalTitleID = useRandomId();
+ const theme = useTheme();
const { isLargeMobile } = useMediaQuery();
const scrollingElement = React.useRef(null);
@@ -376,8 +123,7 @@ const Modal = React.forwardRef(
if (!content) return;
- // added in 4.0.3, interpolation of styled component return static className
- const footerEl = content.querySelector(`${StyledModalFooter}`);
+ const footerEl = content.querySelector(".orbit-modal-footer");
const contentDimensions = content.getBoundingClientRect();
setModalWidth(contentDimensions.width);
@@ -458,7 +204,8 @@ const Modal = React.forwardRef(
modalContent.current &&
event.target instanceof Element &&
!modalContent.current.contains(event.target) &&
- /ModalBody|ModalWrapper/.test(event.target.className);
+ (event.target.className.includes("orbit-modal-wrapper") ||
+ event.target.className.includes("orbit-modal-body"));
if (clickedOutside && onClose) onClose(event);
@@ -487,8 +234,7 @@ const Modal = React.forwardRef(
? contentHeight + 80
: target.scrollHeight;
- // @ts-expect-error TODO
- setScrolled(target.scrollTop >= scrollBegin + (!mobile ? target.scrollTop : 0));
+ setScrolled(target.scrollTop >= Number(scrollBegin) + (!mobile ? target.scrollTop : 0));
setFixedClose(target.scrollTop >= fixCloseOffset);
// set fullyScrolled state sooner than the exact end of the scroll (with fullScrollOffset value)
setFullyScrolled(
@@ -501,7 +247,7 @@ const Modal = React.forwardRef(
if (!content) return null;
- const headingEl = content.querySelector(`${ModalHeading}`);
+ const headingEl = content.querySelector(".orbit-modal-heading");
if (headingEl) {
const { top } = headingEl.getBoundingClientRect();
@@ -629,8 +375,35 @@ const Modal = React.forwardRef(
],
);
+ const cssVars = {
+ ...(!isLargeMobile
+ ? {
+ maxHeight: isMobileFullPage
+ ? "100%"
+ : `calc(100% - ${theme.orbit.spaceXLarge} - ${
+ fixedFooter && Boolean(footerHeight) ? footerHeight : 0
+ }px)`,
+ bottom: `${
+ (!isMobileFullPage ? parseInt(theme.orbit.spaceXLarge, 10) : 0) +
+ (fixedFooter && Boolean(footerHeight) ? footerHeight : 0)
+ }px`,
+ }
+ : {
+ "--orbit-modal-footer-height": fixedFooter ? `${footerHeight}px` : "0",
+ }),
+ "--orbit-modal-width": `${modalWidth}px`,
+ };
+
return (
- (
id={id}
ref={modalBodyRef}
role="dialog"
- isMobileFullPage={isMobileFullPage}
+ // eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus={autoFocus}
aria-modal="true"
aria-labelledby={hasModalTitle ? modalTitleID : ""}
>
-
-
{hasCloseContainer && (
-
{onClose && hasCloseButton && (
(
title={labelClose}
/>
)}
-
+
)}
{children}
-
-
-
+
+
+
);
},
);
@@ -694,6 +519,6 @@ const Modal = React.forwardRef(
Modal.displayName = "Modal";
export default Modal;
-export { default as ModalHeader, ModalHeading } from "./ModalHeader";
+export { default as ModalHeader } from "./ModalHeader";
export { default as ModalSection } from "./ModalSection";
export { default as ModalFooter } from "./ModalFooter";