@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.
- package/README.md +13 -0
- package/dist/index.d.mts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +201 -0
- package/dist/index.js.map +7 -0
- package/dist/index.mjs +169 -0
- package/dist/index.mjs.map +7 -0
- package/package.json +59 -0
- package/src/AlertDialog.stories.module.css +78 -0
- package/src/AlertDialog.stories.tsx +274 -0
- package/src/AlertDialog.test.tsx +61 -0
- package/src/AlertDialog.tsx +306 -0
- package/src/index.ts +35 -0
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { createContextScope } from '@radix-ui/react-context';
|
|
3
|
+
import { useComposedRefs } from '@radix-ui/react-compose-refs';
|
|
4
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
5
|
+
import { createDialogScope } from '@radix-ui/react-dialog';
|
|
6
|
+
import { composeEventHandlers } from '@radix-ui/primitive';
|
|
7
|
+
import { Slottable } from '@radix-ui/react-slot';
|
|
8
|
+
|
|
9
|
+
import type { Scope } from '@radix-ui/react-context';
|
|
10
|
+
|
|
11
|
+
/* -------------------------------------------------------------------------------------------------
|
|
12
|
+
* AlertDialog
|
|
13
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
14
|
+
|
|
15
|
+
const ROOT_NAME = 'AlertDialog';
|
|
16
|
+
|
|
17
|
+
type ScopedProps<P> = P & { __scopeAlertDialog?: Scope };
|
|
18
|
+
const [createAlertDialogContext, createAlertDialogScope] = createContextScope(ROOT_NAME, [
|
|
19
|
+
createDialogScope,
|
|
20
|
+
]);
|
|
21
|
+
const useDialogScope = createDialogScope();
|
|
22
|
+
|
|
23
|
+
type DialogProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Root>;
|
|
24
|
+
interface AlertDialogProps extends Omit<DialogProps, 'modal'> {}
|
|
25
|
+
|
|
26
|
+
const AlertDialog: React.FC<AlertDialogProps> = (props: ScopedProps<AlertDialogProps>) => {
|
|
27
|
+
const { __scopeAlertDialog, ...alertDialogProps } = props;
|
|
28
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
29
|
+
return <DialogPrimitive.Root {...dialogScope} {...alertDialogProps} modal={true} />;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
AlertDialog.displayName = ROOT_NAME;
|
|
33
|
+
|
|
34
|
+
/* -------------------------------------------------------------------------------------------------
|
|
35
|
+
* AlertDialogTrigger
|
|
36
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
37
|
+
const TRIGGER_NAME = 'AlertDialogTrigger';
|
|
38
|
+
|
|
39
|
+
type AlertDialogTriggerElement = React.ElementRef<typeof DialogPrimitive.Trigger>;
|
|
40
|
+
type DialogTriggerProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>;
|
|
41
|
+
interface AlertDialogTriggerProps extends DialogTriggerProps {}
|
|
42
|
+
|
|
43
|
+
const AlertDialogTrigger = React.forwardRef<AlertDialogTriggerElement, AlertDialogTriggerProps>(
|
|
44
|
+
(props: ScopedProps<AlertDialogTriggerProps>, forwardedRef) => {
|
|
45
|
+
const { __scopeAlertDialog, ...triggerProps } = props;
|
|
46
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
47
|
+
return <DialogPrimitive.Trigger {...dialogScope} {...triggerProps} ref={forwardedRef} />;
|
|
48
|
+
}
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
AlertDialogTrigger.displayName = TRIGGER_NAME;
|
|
52
|
+
|
|
53
|
+
/* -------------------------------------------------------------------------------------------------
|
|
54
|
+
* AlertDialogPortal
|
|
55
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
56
|
+
|
|
57
|
+
const PORTAL_NAME = 'AlertDialogPortal';
|
|
58
|
+
|
|
59
|
+
type DialogPortalProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Portal>;
|
|
60
|
+
interface AlertDialogPortalProps extends DialogPortalProps {}
|
|
61
|
+
|
|
62
|
+
const AlertDialogPortal: React.FC<AlertDialogPortalProps> = (
|
|
63
|
+
props: ScopedProps<AlertDialogPortalProps>
|
|
64
|
+
) => {
|
|
65
|
+
const { __scopeAlertDialog, ...portalProps } = props;
|
|
66
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
67
|
+
return <DialogPrimitive.Portal {...dialogScope} {...portalProps} />;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
AlertDialogPortal.displayName = PORTAL_NAME;
|
|
71
|
+
|
|
72
|
+
/* -------------------------------------------------------------------------------------------------
|
|
73
|
+
* AlertDialogOverlay
|
|
74
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
75
|
+
|
|
76
|
+
const OVERLAY_NAME = 'AlertDialogOverlay';
|
|
77
|
+
|
|
78
|
+
type AlertDialogOverlayElement = React.ElementRef<typeof DialogPrimitive.Overlay>;
|
|
79
|
+
type DialogOverlayProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>;
|
|
80
|
+
interface AlertDialogOverlayProps extends DialogOverlayProps {}
|
|
81
|
+
|
|
82
|
+
const AlertDialogOverlay = React.forwardRef<AlertDialogOverlayElement, AlertDialogOverlayProps>(
|
|
83
|
+
(props: ScopedProps<AlertDialogOverlayProps>, forwardedRef) => {
|
|
84
|
+
const { __scopeAlertDialog, ...overlayProps } = props;
|
|
85
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
86
|
+
return <DialogPrimitive.Overlay {...dialogScope} {...overlayProps} ref={forwardedRef} />;
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
AlertDialogOverlay.displayName = OVERLAY_NAME;
|
|
91
|
+
|
|
92
|
+
/* -------------------------------------------------------------------------------------------------
|
|
93
|
+
* AlertDialogContent
|
|
94
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
95
|
+
|
|
96
|
+
const CONTENT_NAME = 'AlertDialogContent';
|
|
97
|
+
|
|
98
|
+
type AlertDialogContentContextValue = {
|
|
99
|
+
cancelRef: React.MutableRefObject<AlertDialogCancelElement | null>;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const [AlertDialogContentProvider, useAlertDialogContentContext] =
|
|
103
|
+
createAlertDialogContext<AlertDialogContentContextValue>(CONTENT_NAME);
|
|
104
|
+
|
|
105
|
+
type AlertDialogContentElement = React.ElementRef<typeof DialogPrimitive.Content>;
|
|
106
|
+
type DialogContentProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>;
|
|
107
|
+
interface AlertDialogContentProps
|
|
108
|
+
extends Omit<DialogContentProps, 'onPointerDownOutside' | 'onInteractOutside'> {}
|
|
109
|
+
|
|
110
|
+
const AlertDialogContent = React.forwardRef<AlertDialogContentElement, AlertDialogContentProps>(
|
|
111
|
+
(props: ScopedProps<AlertDialogContentProps>, forwardedRef) => {
|
|
112
|
+
const { __scopeAlertDialog, children, ...contentProps } = props;
|
|
113
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
114
|
+
const contentRef = React.useRef<AlertDialogContentElement>(null);
|
|
115
|
+
const composedRefs = useComposedRefs(forwardedRef, contentRef);
|
|
116
|
+
const cancelRef = React.useRef<AlertDialogCancelElement | null>(null);
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<DialogPrimitive.WarningProvider
|
|
120
|
+
contentName={CONTENT_NAME}
|
|
121
|
+
titleName={TITLE_NAME}
|
|
122
|
+
docsSlug="alert-dialog"
|
|
123
|
+
>
|
|
124
|
+
<AlertDialogContentProvider scope={__scopeAlertDialog} cancelRef={cancelRef}>
|
|
125
|
+
<DialogPrimitive.Content
|
|
126
|
+
role="alertdialog"
|
|
127
|
+
{...dialogScope}
|
|
128
|
+
{...contentProps}
|
|
129
|
+
ref={composedRefs}
|
|
130
|
+
onOpenAutoFocus={composeEventHandlers(contentProps.onOpenAutoFocus, (event) => {
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
cancelRef.current?.focus({ preventScroll: true });
|
|
133
|
+
})}
|
|
134
|
+
onPointerDownOutside={(event) => event.preventDefault()}
|
|
135
|
+
onInteractOutside={(event) => event.preventDefault()}
|
|
136
|
+
>
|
|
137
|
+
{/**
|
|
138
|
+
* We have to use `Slottable` here as we cannot wrap the `AlertDialogContentProvider`
|
|
139
|
+
* around everything, otherwise the `DescriptionWarning` would be rendered straight away.
|
|
140
|
+
* This is because we want the accessibility checks to run only once the content is actually
|
|
141
|
+
* open and that behaviour is already encapsulated in `DialogContent`.
|
|
142
|
+
*/}
|
|
143
|
+
<Slottable>{children}</Slottable>
|
|
144
|
+
{process.env.NODE_ENV === 'development' && (
|
|
145
|
+
<DescriptionWarning contentRef={contentRef} />
|
|
146
|
+
)}
|
|
147
|
+
</DialogPrimitive.Content>
|
|
148
|
+
</AlertDialogContentProvider>
|
|
149
|
+
</DialogPrimitive.WarningProvider>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
AlertDialogContent.displayName = CONTENT_NAME;
|
|
155
|
+
|
|
156
|
+
/* -------------------------------------------------------------------------------------------------
|
|
157
|
+
* AlertDialogTitle
|
|
158
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
159
|
+
|
|
160
|
+
const TITLE_NAME = 'AlertDialogTitle';
|
|
161
|
+
|
|
162
|
+
type AlertDialogTitleElement = React.ElementRef<typeof DialogPrimitive.Title>;
|
|
163
|
+
type DialogTitleProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;
|
|
164
|
+
interface AlertDialogTitleProps extends DialogTitleProps {}
|
|
165
|
+
|
|
166
|
+
const AlertDialogTitle = React.forwardRef<AlertDialogTitleElement, AlertDialogTitleProps>(
|
|
167
|
+
(props: ScopedProps<AlertDialogTitleProps>, forwardedRef) => {
|
|
168
|
+
const { __scopeAlertDialog, ...titleProps } = props;
|
|
169
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
170
|
+
return <DialogPrimitive.Title {...dialogScope} {...titleProps} ref={forwardedRef} />;
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
AlertDialogTitle.displayName = TITLE_NAME;
|
|
175
|
+
|
|
176
|
+
/* -------------------------------------------------------------------------------------------------
|
|
177
|
+
* AlertDialogDescription
|
|
178
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
179
|
+
|
|
180
|
+
const DESCRIPTION_NAME = 'AlertDialogDescription';
|
|
181
|
+
|
|
182
|
+
type AlertDialogDescriptionElement = React.ElementRef<typeof DialogPrimitive.Description>;
|
|
183
|
+
type DialogDescriptionProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>;
|
|
184
|
+
interface AlertDialogDescriptionProps extends DialogDescriptionProps {}
|
|
185
|
+
|
|
186
|
+
const AlertDialogDescription = React.forwardRef<
|
|
187
|
+
AlertDialogDescriptionElement,
|
|
188
|
+
AlertDialogDescriptionProps
|
|
189
|
+
>((props: ScopedProps<AlertDialogDescriptionProps>, forwardedRef) => {
|
|
190
|
+
const { __scopeAlertDialog, ...descriptionProps } = props;
|
|
191
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
192
|
+
return <DialogPrimitive.Description {...dialogScope} {...descriptionProps} ref={forwardedRef} />;
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
AlertDialogDescription.displayName = DESCRIPTION_NAME;
|
|
196
|
+
|
|
197
|
+
/* -------------------------------------------------------------------------------------------------
|
|
198
|
+
* AlertDialogAction
|
|
199
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
200
|
+
|
|
201
|
+
const ACTION_NAME = 'AlertDialogAction';
|
|
202
|
+
|
|
203
|
+
type AlertDialogActionElement = React.ElementRef<typeof DialogPrimitive.Close>;
|
|
204
|
+
type DialogCloseProps = React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>;
|
|
205
|
+
interface AlertDialogActionProps extends DialogCloseProps {}
|
|
206
|
+
|
|
207
|
+
const AlertDialogAction = React.forwardRef<AlertDialogActionElement, AlertDialogActionProps>(
|
|
208
|
+
(props: ScopedProps<AlertDialogActionProps>, forwardedRef) => {
|
|
209
|
+
const { __scopeAlertDialog, ...actionProps } = props;
|
|
210
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
211
|
+
return <DialogPrimitive.Close {...dialogScope} {...actionProps} ref={forwardedRef} />;
|
|
212
|
+
}
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
AlertDialogAction.displayName = ACTION_NAME;
|
|
216
|
+
|
|
217
|
+
/* -------------------------------------------------------------------------------------------------
|
|
218
|
+
* AlertDialogCancel
|
|
219
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
220
|
+
|
|
221
|
+
const CANCEL_NAME = 'AlertDialogCancel';
|
|
222
|
+
|
|
223
|
+
type AlertDialogCancelElement = React.ElementRef<typeof DialogPrimitive.Close>;
|
|
224
|
+
interface AlertDialogCancelProps extends DialogCloseProps {}
|
|
225
|
+
|
|
226
|
+
const AlertDialogCancel = React.forwardRef<AlertDialogCancelElement, AlertDialogCancelProps>(
|
|
227
|
+
(props: ScopedProps<AlertDialogCancelProps>, forwardedRef) => {
|
|
228
|
+
const { __scopeAlertDialog, ...cancelProps } = props;
|
|
229
|
+
const { cancelRef } = useAlertDialogContentContext(CANCEL_NAME, __scopeAlertDialog);
|
|
230
|
+
const dialogScope = useDialogScope(__scopeAlertDialog);
|
|
231
|
+
const ref = useComposedRefs(forwardedRef, cancelRef);
|
|
232
|
+
return <DialogPrimitive.Close {...dialogScope} {...cancelProps} ref={ref} />;
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
AlertDialogCancel.displayName = CANCEL_NAME;
|
|
237
|
+
|
|
238
|
+
/* ---------------------------------------------------------------------------------------------- */
|
|
239
|
+
|
|
240
|
+
type DescriptionWarningProps = {
|
|
241
|
+
contentRef: React.RefObject<AlertDialogContentElement | null>;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const DescriptionWarning: React.FC<DescriptionWarningProps> = ({ contentRef }) => {
|
|
245
|
+
const MESSAGE = `\`${CONTENT_NAME}\` requires a description for the component to be accessible for screen reader users.
|
|
246
|
+
|
|
247
|
+
You can add a description to the \`${CONTENT_NAME}\` by passing a \`${DESCRIPTION_NAME}\` component as a child, which also benefits sighted users by adding visible context to the dialog.
|
|
248
|
+
|
|
249
|
+
Alternatively, you can use your own component as a description by assigning it an \`id\` and passing the same value to the \`aria-describedby\` prop in \`${CONTENT_NAME}\`. If the description is confusing or duplicative for sighted users, you can use the \`@radix-ui/react-visually-hidden\` primitive as a wrapper around your description component.
|
|
250
|
+
|
|
251
|
+
For more information, see https://radix-ui.com/primitives/docs/components/alert-dialog`;
|
|
252
|
+
|
|
253
|
+
React.useEffect(() => {
|
|
254
|
+
const hasDescription = document.getElementById(
|
|
255
|
+
contentRef.current?.getAttribute('aria-describedby')!
|
|
256
|
+
);
|
|
257
|
+
if (!hasDescription) console.warn(MESSAGE);
|
|
258
|
+
}, [MESSAGE, contentRef]);
|
|
259
|
+
|
|
260
|
+
return null;
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const Root = AlertDialog;
|
|
264
|
+
const Trigger = AlertDialogTrigger;
|
|
265
|
+
const Portal = AlertDialogPortal;
|
|
266
|
+
const Overlay = AlertDialogOverlay;
|
|
267
|
+
const Content = AlertDialogContent;
|
|
268
|
+
const Action = AlertDialogAction;
|
|
269
|
+
const Cancel = AlertDialogCancel;
|
|
270
|
+
const Title = AlertDialogTitle;
|
|
271
|
+
const Description = AlertDialogDescription;
|
|
272
|
+
|
|
273
|
+
export {
|
|
274
|
+
createAlertDialogScope,
|
|
275
|
+
//
|
|
276
|
+
AlertDialog,
|
|
277
|
+
AlertDialogTrigger,
|
|
278
|
+
AlertDialogPortal,
|
|
279
|
+
AlertDialogOverlay,
|
|
280
|
+
AlertDialogContent,
|
|
281
|
+
AlertDialogAction,
|
|
282
|
+
AlertDialogCancel,
|
|
283
|
+
AlertDialogTitle,
|
|
284
|
+
AlertDialogDescription,
|
|
285
|
+
//
|
|
286
|
+
Root,
|
|
287
|
+
Trigger,
|
|
288
|
+
Portal,
|
|
289
|
+
Overlay,
|
|
290
|
+
Content,
|
|
291
|
+
Action,
|
|
292
|
+
Cancel,
|
|
293
|
+
Title,
|
|
294
|
+
Description,
|
|
295
|
+
};
|
|
296
|
+
export type {
|
|
297
|
+
AlertDialogProps,
|
|
298
|
+
AlertDialogTriggerProps,
|
|
299
|
+
AlertDialogPortalProps,
|
|
300
|
+
AlertDialogOverlayProps,
|
|
301
|
+
AlertDialogContentProps,
|
|
302
|
+
AlertDialogActionProps,
|
|
303
|
+
AlertDialogCancelProps,
|
|
304
|
+
AlertDialogTitleProps,
|
|
305
|
+
AlertDialogDescriptionProps,
|
|
306
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
export {
|
|
3
|
+
createAlertDialogScope,
|
|
4
|
+
//
|
|
5
|
+
AlertDialog,
|
|
6
|
+
AlertDialogTrigger,
|
|
7
|
+
AlertDialogPortal,
|
|
8
|
+
AlertDialogOverlay,
|
|
9
|
+
AlertDialogContent,
|
|
10
|
+
AlertDialogAction,
|
|
11
|
+
AlertDialogCancel,
|
|
12
|
+
AlertDialogTitle,
|
|
13
|
+
AlertDialogDescription,
|
|
14
|
+
//
|
|
15
|
+
Root,
|
|
16
|
+
Trigger,
|
|
17
|
+
Portal,
|
|
18
|
+
Overlay,
|
|
19
|
+
Content,
|
|
20
|
+
Action,
|
|
21
|
+
Cancel,
|
|
22
|
+
Title,
|
|
23
|
+
Description,
|
|
24
|
+
} from './AlertDialog';
|
|
25
|
+
export type {
|
|
26
|
+
AlertDialogProps,
|
|
27
|
+
AlertDialogTriggerProps,
|
|
28
|
+
AlertDialogPortalProps,
|
|
29
|
+
AlertDialogOverlayProps,
|
|
30
|
+
AlertDialogContentProps,
|
|
31
|
+
AlertDialogActionProps,
|
|
32
|
+
AlertDialogCancelProps,
|
|
33
|
+
AlertDialogTitleProps,
|
|
34
|
+
AlertDialogDescriptionProps,
|
|
35
|
+
} from './AlertDialog';
|