soapbox/app/soapbox/components/ui/modal/modal.tsx

127 wiersze
3.7 KiB
TypeScript
Czysty Zwykły widok Historia

2022-03-21 18:09:01 +00:00
import classNames from 'classnames';
import * as React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import Button from '../button/button';
import IconButton from '../icon-button/icon-button';
const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' },
confirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
});
interface IModal {
/** Callback when the modal is cancelled. */
2022-03-21 18:09:01 +00:00
cancelAction?: () => void,
/** Cancel button text. */
2022-03-21 18:09:01 +00:00
cancelText?: string,
/** Callback when the modal is confirmed. */
2022-03-21 18:09:01 +00:00
confirmationAction?: () => void,
/** Whether the confirmation button is disabled. */
2022-03-21 18:09:01 +00:00
confirmationDisabled?: boolean,
/** Confirmation button text. */
2022-05-11 20:26:37 +00:00
confirmationText?: React.ReactNode,
/** Confirmation button theme. */
2022-03-21 18:09:01 +00:00
confirmationTheme?: 'danger',
/** Callback when the modal is closed. */
2022-04-07 15:01:38 +00:00
onClose?: () => void,
/** Callback when the secondary action is chosen. */
2022-03-21 18:09:01 +00:00
secondaryAction?: () => void,
/** Secondary button text. */
2022-05-11 20:26:37 +00:00
secondaryText?: React.ReactNode,
2022-04-27 14:11:21 +00:00
/** Don't focus the "confirm" button on mount. */
skipFocus?: boolean,
/** Title text for the modal. */
2022-03-21 18:09:01 +00:00
title: string | React.ReactNode,
}
/** Displays a modal dialog box. */
2022-03-21 18:09:01 +00:00
const Modal: React.FC<IModal> = ({
cancelAction,
cancelText,
children,
confirmationAction,
confirmationDisabled,
confirmationText,
confirmationTheme,
onClose,
secondaryAction,
secondaryText,
2022-04-27 14:11:21 +00:00
skipFocus = false,
2022-03-21 18:09:01 +00:00
title,
}) => {
const intl = useIntl();
const buttonRef = React.useRef<HTMLButtonElement>(null);
React.useEffect(() => {
2022-04-27 14:11:21 +00:00
if (buttonRef?.current && !skipFocus) {
2022-03-21 18:09:01 +00:00
buttonRef.current.focus();
}
2022-04-27 14:11:21 +00:00
}, [skipFocus, buttonRef]);
2022-03-21 18:09:01 +00:00
return (
<div data-testid='modal' className='block w-full max-w-xl p-6 mx-auto overflow-hidden text-left align-middle transition-all transform bg-white dark:bg-slate-800 text-black dark:text-white shadow-xl rounded-2xl pointer-events-auto'>
2022-03-21 18:09:01 +00:00
<div className='sm:flex sm:items-start w-full justify-between'>
<div className='w-full'>
<div className='w-full flex flex-row justify-between items-center'>
<h3 className='text-lg leading-6 font-medium text-gray-900 dark:text-white'>
2022-03-21 18:09:01 +00:00
{title}
</h3>
{onClose && (
<IconButton
src={require('@tabler/icons/icons/x.svg')}
title={intl.formatMessage(messages.close)}
onClick={onClose}
2022-05-12 19:15:22 +00:00
className='text-gray-500 hover:text-gray-700 dark:text-gray-300 dark:hover:text-gray-200'
2022-03-21 18:09:01 +00:00
/>
)}
</div>
<div className={classNames('mt-2 w-full')}>
{children}
</div>
</div>
</div>
{confirmationAction && (
2022-04-07 15:01:38 +00:00
<div className='mt-5 flex flex-row justify-between' data-testid='modal-actions'>
2022-03-21 18:09:01 +00:00
<div className='flex-grow'>
{cancelAction && (
<Button
theme='ghost'
onClick={cancelAction}
>
2022-04-27 14:11:21 +00:00
{cancelText || 'Cancel'}
2022-03-21 18:09:01 +00:00
</Button>
)}
</div>
<div className='flex flex-row space-x-2'>
{secondaryAction && (
<Button
theme='secondary'
onClick={secondaryAction}
>
{secondaryText}
</Button>
)}
<Button
theme={confirmationTheme || 'primary'}
onClick={confirmationAction}
disabled={confirmationDisabled}
ref={buttonRef}
>
{confirmationText}
</Button>
</div>
</div>
)}
</div>
);
};
export default Modal;