-
Notifications
You must be signed in to change notification settings - Fork 11.7k
/
ConfirmModal.tsx
124 lines (117 loc) · 3.59 KB
/
ConfirmModal.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { css, cx } from '@emotion/css';
import React, { useEffect, useRef, useState } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { HorizontalGroup, Input } from '..';
import { useStyles2 } from '../../themes';
import { IconName } from '../../types/icon';
import { Button, ButtonVariant } from '../Button';
import { Modal } from '../Modal/Modal';
export interface ConfirmModalProps {
/** Toggle modal's open/closed state */
isOpen: boolean;
/** Title for the modal header */
title: string;
/** Modal content */
body: React.ReactNode;
/** Modal description */
description?: React.ReactNode;
/** Text for confirm button */
confirmText: string;
/** Text for dismiss button */
dismissText?: string;
/** Icon for the modal header */
icon?: IconName;
/** Additional styling for modal container */
modalClass?: string;
/** Text user needs to fill in before confirming */
confirmationText?: string;
/** Text for alternative button */
alternativeText?: string;
/** Confirm button variant */
confirmButtonVariant?: ButtonVariant;
/** Confirm action callback */
onConfirm(): void;
/** Dismiss action callback */
onDismiss(): void;
/** Alternative action callback */
onAlternative?(): void;
}
export const ConfirmModal = ({
isOpen,
title,
body,
description,
confirmText,
confirmationText,
dismissText = 'Cancel',
alternativeText,
modalClass,
icon = 'exclamation-triangle',
onConfirm,
onDismiss,
onAlternative,
confirmButtonVariant = 'destructive',
}: ConfirmModalProps): JSX.Element => {
const [disabled, setDisabled] = useState(Boolean(confirmationText));
const styles = useStyles2(getStyles);
const buttonRef = useRef<HTMLButtonElement>(null);
const onConfirmationTextChange = (event: React.FormEvent<HTMLInputElement>) => {
setDisabled(confirmationText?.localeCompare(event.currentTarget.value) !== 0);
};
useEffect(() => {
// for some reason autoFocus property did no work on this button, but this does
if (isOpen) {
buttonRef.current?.focus();
}
}, [isOpen]);
return (
<Modal className={cx(styles.modal, modalClass)} title={title} icon={icon} isOpen={isOpen} onDismiss={onDismiss}>
<div className={styles.modalText}>
{body}
{description ? <div className={styles.modalDescription}>{description}</div> : null}
{confirmationText ? (
<div className={styles.modalConfirmationInput}>
<HorizontalGroup>
<Input placeholder={`Type ${confirmationText} to confirm`} onChange={onConfirmationTextChange} />
</HorizontalGroup>
</div>
) : null}
</div>
<Modal.ButtonRow>
<Button variant="secondary" onClick={onDismiss} fill="outline">
{dismissText}
</Button>
<Button
variant={confirmButtonVariant}
onClick={onConfirm}
disabled={disabled}
ref={buttonRef}
aria-label={selectors.pages.ConfirmModal.delete}
>
{confirmText}
</Button>
{onAlternative ? (
<Button variant="primary" onClick={onAlternative}>
{alternativeText}
</Button>
) : null}
</Modal.ButtonRow>
</Modal>
);
};
const getStyles = (theme: GrafanaTheme2) => ({
modal: css`
width: 500px;
`,
modalText: css({
fontSize: theme.typography.h5.fontSize,
color: theme.colors.text.primary,
}),
modalDescription: css({
fontSize: theme.typography.body.fontSize,
}),
modalConfirmationInput: css({
paddingTop: theme.spacing(1),
}),
});