Replaces ConfirmationModal with ConfirmationDialog

This commit is contained in:
Josh Perez 2021-04-27 12:29:59 -07:00 committed by GitHub
parent c9d74654bf
commit e75bba1c52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 456 additions and 737 deletions

View file

@ -2,8 +2,10 @@
// SPDX-License-Identifier: AGPL-3.0-only
import * as React from 'react';
import classNames from 'classnames';
import { Button, ButtonVariant } from './Button';
import { LocalizerType } from '../types/Util';
import { Modal } from './Modal';
import { Theme } from '../util/theme';
export type ActionSpec = {
text: string;
@ -12,12 +14,14 @@ export type ActionSpec = {
};
export type OwnProps = {
readonly actions: Array<ActionSpec>;
readonly actions?: Array<ActionSpec>;
readonly cancelText?: string;
readonly children?: React.ReactNode;
readonly i18n: LocalizerType;
readonly onCancel?: () => unknown;
readonly onClose: () => unknown;
readonly title?: string | React.ReactNode;
readonly theme?: Theme;
};
export type Props = OwnProps;
@ -28,85 +32,77 @@ function focusRef(el: HTMLElement | null) {
}
}
// TODO: This should use <Modal>. See DESKTOP-1038.
export const ConfirmationDialog = React.memo(
({ i18n, onClose, cancelText, children, title, actions }: Props) => {
React.useEffect(() => {
const handler = ({ key }: KeyboardEvent) => {
if (key === 'Escape') {
onClose();
}
};
document.addEventListener('keydown', handler);
function getButtonVariant(
buttonStyle?: 'affirmative' | 'negative'
): ButtonVariant {
if (buttonStyle === 'affirmative') {
return ButtonVariant.Primary;
}
return () => {
document.removeEventListener('keydown', handler);
};
}, [onClose]);
if (buttonStyle === 'negative') {
return ButtonVariant.Destructive;
}
return ButtonVariant.Secondary;
}
export const ConfirmationDialog = React.memo(
({
actions = [],
cancelText,
children,
i18n,
onCancel,
onClose,
theme,
title,
}: Props) => {
const cancelAndClose = React.useCallback(() => {
if (onCancel) {
onCancel();
}
onClose();
}, [onCancel, onClose]);
const handleCancel = React.useCallback(
(e: React.MouseEvent) => {
if (e.target === e.currentTarget) {
onClose();
cancelAndClose();
}
},
[onClose]
[cancelAndClose]
);
const handleAction = React.useCallback(
(e: React.MouseEvent<HTMLButtonElement>) => {
if (e.currentTarget.dataset.action) {
const actionIndex = parseInt(e.currentTarget.dataset.action, 10);
const { action } = actions[actionIndex];
action();
}
onClose();
},
[onClose, actions]
);
const hasActions = Boolean(actions.length);
return (
<div className="module-confirmation-dialog__container">
{title ? (
<h1 className="module-confirmation-dialog__container__title">
{title}
</h1>
) : null}
<div className="module-confirmation-dialog__container__content">
{children}
</div>
{actions.length > 0 && (
<div className="module-confirmation-dialog__container__buttons">
<button
type="button"
onClick={handleCancel}
ref={focusRef}
className="module-confirmation-dialog__container__buttons__button"
<Modal i18n={i18n} onClose={cancelAndClose} title={title} theme={theme}>
{children}
<Modal.Footer>
<Button
onClick={handleCancel}
ref={focusRef}
variant={
hasActions ? ButtonVariant.Secondary : ButtonVariant.Primary
}
>
{cancelText || i18n('confirmation-dialog--Cancel')}
</Button>
{actions.map((action, i) => (
<Button
key={action.text}
onClick={() => {
action.action();
onClose();
}}
data-action={i}
variant={getButtonVariant(action.style)}
>
{cancelText || i18n('confirmation-dialog--Cancel')}
</button>
{actions.map((action, i) => (
<button
type="button"
key={action.text}
onClick={handleAction}
data-action={i}
className={classNames(
'module-confirmation-dialog__container__buttons__button',
action.style === 'affirmative'
? 'module-confirmation-dialog__container__buttons__button--affirmative'
: null,
action.style === 'negative'
? 'module-confirmation-dialog__container__buttons__button--negative'
: null
)}
>
{action.text}
</button>
))}
</div>
)}
</div>
{action.text}
</Button>
))}
</Modal.Footer>
</Modal>
);
}
);