diff --git a/src/Modal/AlertModal.jsx b/src/Modal/AlertModal.jsx
deleted file mode 100644
index 0fc42354e5..0000000000
--- a/src/Modal/AlertModal.jsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-
-import { requiredWhenNot } from '../utils/propTypes';
-import Icon from '../Icon';
-import ModalDialog from './ModalDialog';
-
-function AlertModal({
- children,
- footerNode,
- icon,
- ...props
-}) {
- return (
-
-
-
- {icon && (
-
- )}
- {props.title}
-
-
- {children}
- {footerNode && {footerNode}}
-
- );
-}
-
-AlertModal.propTypes = {
- children: PropTypes.node.isRequired,
- /** The aria-label of the dialog */
- title: PropTypes.string.isRequired,
- /** Is the modal dialog open or closed */
- isOpen: PropTypes.bool,
- /** Prevent clicking on the backdrop or pressing Esc to close the modal */
- isBlocking: PropTypes.bool,
- /** Specifies whether the dialog box should contain 'x' icon button in the top right */
- hasCloseButton: PropTypes.bool,
- /** A callback to close the modal dialog */
- onClose: requiredWhenNot(PropTypes.func, 'isBlocking'),
- /** Sizes determine the maximum width of the dialog box */
- size: PropTypes.oneOf(['sm', 'md', 'lg', 'xl', 'fullscreen']),
- /** The visual style of the dialog box */
- variant: PropTypes.oneOf(['default', 'warning', 'danger', 'success']),
- /** The label supplied to the close icon button if one is rendered */
- closeLabel: PropTypes.string,
- /** Specifies class name to append to the base element */
- className: PropTypes.string,
- /**
- * Determines where a scrollbar should appear if a modal is too large for the
- * viewport. When false, the ModalDialog.Body receives a scrollbar, when true
- * the browser window itself receives the scrollbar.
- */
- isFullscreenScroll: PropTypes.bool,
- /** Specifies what should be displayed in the footer of the dialog box */
- footerNode: PropTypes.node,
- /** Icon that will be shown in the header of modal */
- icon: PropTypes.elementType,
-};
-
-AlertModal.defaultProps = {
- isOpen: false,
- isBlocking: false,
- hasCloseButton: false,
- onClose: () => {},
- size: 'md',
- variant: 'default',
- closeLabel: 'Close',
- className: undefined,
- isFullscreenScroll: false,
- footerNode: null,
- icon: undefined,
-};
-
-export default AlertModal;
diff --git a/src/Modal/AlertModal.tsx b/src/Modal/AlertModal.tsx
new file mode 100644
index 0000000000..3b2b7f84ad
--- /dev/null
+++ b/src/Modal/AlertModal.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import classNames from 'classnames';
+
+import Icon from '../Icon';
+import ModalDialog from './ModalDialog';
+
+type ModalDialogProps = React.ComponentProps;
+
+// Extends all ModalDialog props, but omits certain props to re-declare them:
+// - onClose: ModalDialog requires it, but AlertModal defaults it to () => {}
+// - isOverflowVisible: required in ModalDialog but was absent from AlertModal's propTypes;
+// undefined is falsy so defaulting to false matches the previous behavior
+// - variant: ModalDialog allows 'dark' but AlertModal intentionally excludes it
+// footerNode and icon are AlertModal-specific props not present on ModalDialog
+interface AlertModalProps extends Omit {
+ /** A callback to close the modal dialog */
+ onClose?: () => void;
+ /** Specifies whether overflow content inside the modal should be visible */
+ isOverflowVisible?: boolean;
+ /** The visual style of the dialog box */
+ variant?: 'default' | 'warning' | 'danger' | 'success';
+ /** Specifies what should be displayed in the footer of the dialog box */
+ footerNode?: React.ReactNode;
+ /** Icon that will be shown in the header of modal */
+ icon?: React.ComponentType;
+}
+
+function AlertModal({
+ children,
+ footerNode = null,
+ icon,
+ title,
+ hasCloseButton = false,
+ onClose = () => {},
+ isOverflowVisible = false,
+ className,
+ ...props
+}: AlertModalProps) {
+ return (
+
+
+
+ {icon && (
+
+ )}
+ {title}
+
+
+ {children}
+ {footerNode && {footerNode}}
+
+ );
+}
+
+export default AlertModal;
diff --git a/src/Modal/tests/AlertModal.test.jsx b/src/Modal/tests/AlertModal.test.jsx
index 88cbd3ae5c..03e88e49f6 100644
--- a/src/Modal/tests/AlertModal.test.jsx
+++ b/src/Modal/tests/AlertModal.test.jsx
@@ -1,5 +1,6 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
import { IntlProvider } from 'react-intl';
import AlertModal from '../AlertModal';
@@ -55,6 +56,30 @@ describe('', () => {
expect(body).toBeInTheDocument();
});
+ it('renders without optional props', () => {
+ render(
+
+
+
+
+ ,
+ );
+ expect(screen.getByText('The body of alert.')).toBeInTheDocument();
+ expect(screen.queryByText('footer')).not.toBeInTheDocument();
+ });
+
+ it('close button click invokes default no-op onClose without error', async () => {
+ render(
+
+
+
+
+ ,
+ );
+ await userEvent.click(screen.getByRole('button', { name: 'Close' }));
+ expect(screen.getByRole('dialog')).toBeInTheDocument();
+ });
+
describe('with variant prop', () => {
it('renders warning variant', () => {
render(
diff --git a/src/index.ts b/src/index.ts
index 7e11e26a8c..f5b56b7ab3 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,6 +3,7 @@
// // // // // // // // // // // // // // // // // // // // // // // // // // //
export { default as ActionRow } from './ActionRow';
export { default as Alert, ALERT_CLOSE_LABEL_TEXT } from './Alert';
+export { default as AlertModal } from './Modal/AlertModal';
export { default as Annotation } from './Annotation';
export { default as Avatar } from './Avatar';
export { default as AvatarButton } from './AvatarButton';
@@ -117,8 +118,6 @@ export { default as MarketingModal } from './Modal/MarketingModal';
// @ts-ignore: has yet to be converted to TypeScript
export { default as StandardModal, STANDARD_MODAL_CLOSE_LABEL } from './Modal/StandardModal';
// @ts-ignore: has yet to be converted to TypeScript
-export { default as AlertModal } from './Modal/AlertModal';
-// @ts-ignore: has yet to be converted to TypeScript
export { default as ModalPopup } from './Modal/ModalPopup';
// @ts-ignore: has yet to be converted to TypeScript
export { default as PopperElement } from './Modal/PopperElement';