@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,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';