Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 0 additions & 84 deletions src/Modal/AlertModal.jsx

This file was deleted.

66 changes: 66 additions & 0 deletions src/Modal/AlertModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React from 'react';
import classNames from 'classnames';

import Icon from '../Icon';
import ModalDialog from './ModalDialog';

type ModalDialogProps = React.ComponentProps<typeof ModalDialog>;

// 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
Comment on lines +11 to +12
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think defaulting to false here (as opposed to making this a required prop) is the right call for this PR (see #4142 (comment))

// - variant: ModalDialog allows 'dark' but AlertModal intentionally excludes it
// footerNode and icon are AlertModal-specific props not present on ModalDialog
interface AlertModalProps extends Omit<ModalDialogProps, 'onClose' | 'isOverflowVisible' | 'variant'> {
/** 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 (
<ModalDialog
{...props}
title={title}
hasCloseButton={hasCloseButton}
onClose={onClose}
isOverflowVisible={isOverflowVisible}
className={classNames('pgn__alert-modal', className)}
>
<ModalDialog.Header>
<ModalDialog.Title>
{icon && (
<Icon
data-testid="title-icon"
src={icon}
className={classNames('pgn__alert-modal__title_icon')}
/>
)}
{title}
</ModalDialog.Title>
</ModalDialog.Header>
<ModalDialog.Body>{children}</ModalDialog.Body>
{footerNode && <ModalDialog.Footer>{footerNode}</ModalDialog.Footer>}
</ModalDialog>
);
}

export default AlertModal;
25 changes: 25 additions & 0 deletions src/Modal/tests/AlertModal.test.jsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -55,6 +56,30 @@ describe('<AlertModal />', () => {
expect(body).toBeInTheDocument();
});

it('renders without optional props', () => {
render(
<IntlProvider locale="en" messages={{}}>
<AlertModal title="minimal" isOpen>
<Body />
</AlertModal>
</IntlProvider>,
);
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(
<IntlProvider locale="en" messages={{}}>
<AlertModal title="closeable" isOpen hasCloseButton>
<Body />
</AlertModal>
</IntlProvider>,
);
await userEvent.click(screen.getByRole('button', { name: 'Close' }));
expect(screen.getByRole('dialog')).toBeInTheDocument();
});

describe('with variant prop', () => {
it('renders warning variant', () => {
render(
Expand Down
3 changes: 1 addition & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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';
Expand Down