@radix-ui/react-alert-dialog 0.0.0-20250116175529

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,78 @@
1
+ .trigger {
2
+ }
3
+
4
+ .overlay,
5
+ .overlayAttr {
6
+ /* ensures overlay is positionned correctly */
7
+ position: fixed;
8
+ inset: 0;
9
+ /* --------- */
10
+ background-color: var(--gray-12);
11
+ opacity: 0.2;
12
+ }
13
+
14
+ .content,
15
+ .chromaticContent,
16
+ .contentAttr {
17
+ /* ensures good default position for content */
18
+ position: fixed;
19
+ top: 0;
20
+ left: 0;
21
+ /* --------- */
22
+ top: 50%;
23
+ left: 50%;
24
+ transform: translate(-50%, -50%);
25
+ background: var(--gray-1);
26
+ min-width: 300px;
27
+ min-height: 150px;
28
+ padding: 50px;
29
+ border-radius: 10px;
30
+ background-color: var(--gray-1);
31
+ box-shadow: 0 2px 10px var(--black-a6);
32
+ }
33
+
34
+ .cancel,
35
+ .action {
36
+ appearance: none;
37
+ padding: 10px;
38
+ border: none;
39
+ }
40
+
41
+ .cancel {
42
+ background: var(--gray-3);
43
+ color: var(--gray-12);
44
+ }
45
+
46
+ .action {
47
+ background: var(--red-9);
48
+ color: var(--gray-1);
49
+ }
50
+
51
+ .title {
52
+ }
53
+
54
+ .description {
55
+ }
56
+
57
+ .chromaticContent {
58
+ padding: 10px;
59
+ min-width: auto;
60
+ min-height: auto;
61
+ }
62
+
63
+ .triggerAttr .overlayAttr,
64
+ .contentAttr,
65
+ .cancelAttr,
66
+ .actionAttr,
67
+ .titleAttr,
68
+ .descriptionAttr {
69
+ background-color: var(--blue-a12);
70
+ border: 2px solid var(--blue-9);
71
+ padding: 10px;
72
+ &[data-state='closed'] {
73
+ border-color: var(--red-9);
74
+ }
75
+ &[data-state='open'] {
76
+ border-color: var(--green-9);
77
+ }
78
+ }
@@ -0,0 +1,274 @@
1
+ import * as React from 'react';
2
+ import * as AlertDialog from '@radix-ui/react-alert-dialog';
3
+ import styles from './AlertDialog.stories.module.css';
4
+
5
+ export default { title: 'Components/AlertDialog' };
6
+
7
+ export const Styled = () => (
8
+ <AlertDialog.Root>
9
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
10
+ <AlertDialog.Portal>
11
+ <AlertDialog.Overlay className={styles.overlay} />
12
+ <AlertDialog.Content className={styles.content}>
13
+ <AlertDialog.Title className={styles.title}>Are you sure?</AlertDialog.Title>
14
+ <AlertDialog.Description className={styles.description}>
15
+ This will do a very dangerous thing. Thar be dragons!
16
+ </AlertDialog.Description>
17
+ <AlertDialog.Action className={styles.action}>yolo, do it</AlertDialog.Action>
18
+ <AlertDialog.Cancel className={styles.cancel}>maybe not</AlertDialog.Cancel>
19
+ </AlertDialog.Content>
20
+ </AlertDialog.Portal>
21
+ </AlertDialog.Root>
22
+ );
23
+
24
+ export const Controlled = () => {
25
+ const [open, setOpen] = React.useState(false);
26
+ const [housePurchased, setHousePurchased] = React.useState(false);
27
+
28
+ return (
29
+ <div>
30
+ <div>
31
+ <img src="https://i.ibb.co/K54hsKt/house.jpg" alt="a large white house with a red roof" />
32
+ </div>
33
+ <AlertDialog.Root open={open} onOpenChange={setOpen}>
34
+ <AlertDialog.Trigger
35
+ onClick={(e) => {
36
+ if (housePurchased) {
37
+ e.preventDefault();
38
+ setHousePurchased(false);
39
+ }
40
+ }}
41
+ >
42
+ {housePurchased ? 'You bought the house! Sell it!' : 'Buy this house'}
43
+ </AlertDialog.Trigger>
44
+ <AlertDialog.Portal>
45
+ <AlertDialog.Overlay className={styles.overlay} />
46
+ <AlertDialog.Content className={styles.content}>
47
+ <AlertDialog.Title>Are you sure?</AlertDialog.Title>
48
+ <AlertDialog.Description>
49
+ Houses are very expensive and it looks like you only have €20 in the bank. Maybe
50
+ consult with a financial advisor?
51
+ </AlertDialog.Description>
52
+ <AlertDialog.Action className={styles.action} onClick={() => setHousePurchased(true)}>
53
+ buy it anyway
54
+ </AlertDialog.Action>
55
+ <AlertDialog.Cancel className={styles.cancel}>
56
+ good point, I'll reconsider
57
+ </AlertDialog.Cancel>
58
+ </AlertDialog.Content>
59
+ </AlertDialog.Portal>
60
+ </AlertDialog.Root>
61
+ </div>
62
+ );
63
+ };
64
+
65
+ export const Chromatic = () => (
66
+ <div
67
+ style={{
68
+ display: 'grid',
69
+ gridTemplateColumns: 'repeat(4, 1fr)',
70
+ gridTemplateRows: 'repeat(2, 1fr)',
71
+ height: '100vh',
72
+ }}
73
+ >
74
+ <div>
75
+ <h1>Uncontrolled</h1>
76
+ <h2>Closed</h2>
77
+ <AlertDialog.Root>
78
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
79
+ <AlertDialog.Portal>
80
+ <AlertDialog.Overlay className={styles.overlay} />
81
+ <AlertDialog.Content className={styles.chromaticContent}>
82
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
83
+ <AlertDialog.Description className={styles.description}>
84
+ Description
85
+ </AlertDialog.Description>
86
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
87
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
88
+ </AlertDialog.Content>
89
+ </AlertDialog.Portal>
90
+ </AlertDialog.Root>
91
+
92
+ <h2>Open</h2>
93
+ <AlertDialog.Root defaultOpen>
94
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
95
+ <AlertDialog.Portal>
96
+ <AlertDialog.Overlay
97
+ className={styles.overlay}
98
+ style={{ left: 0, bottom: '50%', width: '25%' }}
99
+ />
100
+ <AlertDialog.Content
101
+ className={styles.chromaticContent}
102
+ style={{ top: '25%', left: '12%' }}
103
+ >
104
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
105
+ <AlertDialog.Description className={styles.description}>
106
+ Description
107
+ </AlertDialog.Description>
108
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
109
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
110
+ </AlertDialog.Content>
111
+ </AlertDialog.Portal>
112
+ </AlertDialog.Root>
113
+ </div>
114
+
115
+ <div>
116
+ <h1>Uncontrolled with reordered parts</h1>
117
+ <h2>Closed</h2>
118
+ <AlertDialog.Root>
119
+ <AlertDialog.Portal>
120
+ <AlertDialog.Overlay className={styles.overlay} />
121
+ <AlertDialog.Content className={styles.chromaticContent}>
122
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
123
+ <AlertDialog.Description className={styles.description}>
124
+ Description
125
+ </AlertDialog.Description>
126
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
127
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
128
+ </AlertDialog.Content>
129
+ </AlertDialog.Portal>
130
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
131
+ </AlertDialog.Root>
132
+
133
+ <h2>Open</h2>
134
+ <AlertDialog.Root defaultOpen>
135
+ <AlertDialog.Portal>
136
+ <AlertDialog.Overlay
137
+ className={styles.overlay}
138
+ style={{ left: '25%', bottom: '50%', width: '25%' }}
139
+ />
140
+ <AlertDialog.Content
141
+ className={styles.chromaticContent}
142
+ style={{ top: '25%', left: '37%' }}
143
+ >
144
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
145
+ <AlertDialog.Description className={styles.description}>
146
+ Description
147
+ </AlertDialog.Description>
148
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
149
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
150
+ </AlertDialog.Content>
151
+ </AlertDialog.Portal>
152
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
153
+ </AlertDialog.Root>
154
+ </div>
155
+
156
+ <div>
157
+ <h1>Controlled</h1>
158
+ <h2>Closed</h2>
159
+ <AlertDialog.Root open={false}>
160
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
161
+ <AlertDialog.Portal>
162
+ <AlertDialog.Overlay className={styles.overlay} />
163
+ <AlertDialog.Content className={styles.chromaticContent}>
164
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
165
+ <AlertDialog.Description className={styles.description}>
166
+ Description
167
+ </AlertDialog.Description>
168
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
169
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
170
+ </AlertDialog.Content>
171
+ </AlertDialog.Portal>
172
+ </AlertDialog.Root>
173
+
174
+ <h2>Open</h2>
175
+ <AlertDialog.Root open>
176
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
177
+ <AlertDialog.Portal>
178
+ <AlertDialog.Overlay
179
+ className={styles.overlay}
180
+ style={{ left: '50%', bottom: '50%', width: '25%' }}
181
+ />
182
+ <AlertDialog.Content
183
+ className={styles.chromaticContent}
184
+ style={{ top: '25%', left: '62%' }}
185
+ >
186
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
187
+ <AlertDialog.Description className={styles.description}>
188
+ Description
189
+ </AlertDialog.Description>
190
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
191
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
192
+ </AlertDialog.Content>
193
+ </AlertDialog.Portal>
194
+ </AlertDialog.Root>
195
+ </div>
196
+
197
+ <div>
198
+ <h1>Controlled with reordered parts</h1>
199
+ <h2>Closed</h2>
200
+ <AlertDialog.Root open={false}>
201
+ <AlertDialog.Portal>
202
+ <AlertDialog.Overlay className={styles.overlay} />
203
+ <AlertDialog.Content className={styles.chromaticContent}>
204
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
205
+ <AlertDialog.Description className={styles.description}>
206
+ Description
207
+ </AlertDialog.Description>
208
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
209
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
210
+ </AlertDialog.Content>
211
+ </AlertDialog.Portal>
212
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
213
+ </AlertDialog.Root>
214
+
215
+ <h2>Open</h2>
216
+ <AlertDialog.Root open>
217
+ <AlertDialog.Portal>
218
+ <AlertDialog.Overlay
219
+ className={styles.overlay}
220
+ style={{ left: '75%', bottom: '50%', width: '25%' }}
221
+ />
222
+ <AlertDialog.Content
223
+ className={styles.chromaticContent}
224
+ style={{ top: '25%', left: '88%' }}
225
+ >
226
+ <AlertDialog.Title className={styles.title}>Title</AlertDialog.Title>
227
+ <AlertDialog.Description className={styles.description}>
228
+ Description
229
+ </AlertDialog.Description>
230
+ <AlertDialog.Action className={styles.action}>Confirm</AlertDialog.Action>
231
+ <AlertDialog.Cancel className={styles.cancel}>Cancel</AlertDialog.Cancel>
232
+ </AlertDialog.Content>
233
+ </AlertDialog.Portal>
234
+ <AlertDialog.Trigger className={styles.trigger}>delete everything</AlertDialog.Trigger>
235
+ </AlertDialog.Root>
236
+ </div>
237
+
238
+ <div>
239
+ <h1>State attributes</h1>
240
+ <h2>Closed</h2>
241
+ <AlertDialog.Root>
242
+ <AlertDialog.Trigger className={styles.triggerAttr}>delete everything</AlertDialog.Trigger>
243
+ <AlertDialog.Portal>
244
+ <AlertDialog.Overlay className={styles.overlayAttr} />
245
+ <AlertDialog.Content className={styles.contentAttr}>
246
+ <AlertDialog.Title className={styles.titleAttr}>Title</AlertDialog.Title>
247
+ <AlertDialog.Description className={styles.descriptionAttr}>
248
+ Description
249
+ </AlertDialog.Description>
250
+ <AlertDialog.Action className={styles.actionAttr}>Confirm</AlertDialog.Action>
251
+ <AlertDialog.Cancel className={styles.cancelAttr}>Cancel</AlertDialog.Cancel>
252
+ </AlertDialog.Content>
253
+ </AlertDialog.Portal>
254
+ </AlertDialog.Root>
255
+
256
+ <h2>Open</h2>
257
+ <AlertDialog.Root defaultOpen>
258
+ <AlertDialog.Trigger className={styles.triggerAttr}>delete everything</AlertDialog.Trigger>
259
+ <AlertDialog.Portal>
260
+ <AlertDialog.Overlay className={styles.overlayAttr} style={{ top: '50%' }} />
261
+ <AlertDialog.Content className={styles.contentAttr} style={{ top: '75%' }}>
262
+ <AlertDialog.Title className={styles.titleAttr}>Title</AlertDialog.Title>
263
+ <AlertDialog.Description className={styles.descriptionAttr}>
264
+ Description
265
+ </AlertDialog.Description>
266
+ <AlertDialog.Action className={styles.actionAttr}>Confirm</AlertDialog.Action>
267
+ <AlertDialog.Cancel className={styles.cancelAttr}>Cancel</AlertDialog.Cancel>
268
+ </AlertDialog.Content>
269
+ </AlertDialog.Portal>
270
+ </AlertDialog.Root>
271
+ </div>
272
+ </div>
273
+ );
274
+ Chromatic.parameters = { chromatic: { disable: false } };
@@ -0,0 +1,61 @@
1
+ import React from 'react';
2
+ import { axe } from 'jest-axe';
3
+ import { RenderResult } from '@testing-library/react';
4
+ import { render, fireEvent } from '@testing-library/react';
5
+ import * as AlertDialog from '@radix-ui/react-alert-dialog';
6
+
7
+ const OPEN_TEXT = 'Open';
8
+ const CANCEL_TEXT = 'Cancel';
9
+ const ACTION_TEXT = 'Do it';
10
+ const TITLE_TEXT = 'Warning';
11
+ const DESC_TEXT = 'This is a warning';
12
+ const OVERLAY_TEST_ID = 'test-overlay';
13
+
14
+ const DialogTest = (props: React.ComponentProps<typeof AlertDialog.Root>) => (
15
+ <AlertDialog.Root {...props}>
16
+ <AlertDialog.Trigger>{OPEN_TEXT}</AlertDialog.Trigger>
17
+ <AlertDialog.Overlay data-testid={OVERLAY_TEST_ID} />
18
+ <AlertDialog.Content>
19
+ <AlertDialog.Title>{TITLE_TEXT}</AlertDialog.Title>
20
+ <AlertDialog.Description>{DESC_TEXT}</AlertDialog.Description>
21
+ <AlertDialog.Cancel>{CANCEL_TEXT}</AlertDialog.Cancel>
22
+ <AlertDialog.Action>{ACTION_TEXT}</AlertDialog.Action>
23
+ </AlertDialog.Content>
24
+ </AlertDialog.Root>
25
+ );
26
+
27
+ describe('given a default Dialog', () => {
28
+ let rendered: RenderResult;
29
+ let title: HTMLElement;
30
+ let trigger: HTMLElement;
31
+ let cancelButton: HTMLElement;
32
+
33
+ beforeEach(() => {
34
+ rendered = render(<DialogTest />);
35
+ trigger = rendered.getByText(OPEN_TEXT);
36
+ });
37
+
38
+ it('should have no accessibility violations in default state', async () => {
39
+ expect(await axe(rendered.container)).toHaveNoViolations();
40
+ });
41
+
42
+ describe('after clicking the trigger', () => {
43
+ beforeEach(() => {
44
+ fireEvent.click(trigger);
45
+ title = rendered.getByText(TITLE_TEXT);
46
+ cancelButton = rendered.getByText(CANCEL_TEXT);
47
+ });
48
+
49
+ it('should open the content', () => {
50
+ expect(title).toBeVisible();
51
+ });
52
+
53
+ it('should have no accessibility violations when open', async () => {
54
+ expect(await axe(rendered.container)).toHaveNoViolations();
55
+ });
56
+
57
+ it('should focus the cancel button', () => {
58
+ expect(cancelButton).toHaveFocus();
59
+ });
60
+ });
61
+ });