Skip to content

Commit f4c4928

Browse files
committed
alertdialog added to docs site
1 parent d287c12 commit f4c4928

File tree

5 files changed

+730
-1
lines changed

5 files changed

+730
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dependencies": ["button"]
3+
}
Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
import React, { createContext, useContext, useState, useRef, useEffect } from 'react';
2+
import { cn } from '../../../lib/utils';
3+
4+
// Import styles
5+
import {
6+
alertDialogClassNames,
7+
alertDialogTriggerClassNames,
8+
alertDialogContentClassNames,
9+
alertDialogHeaderClassNames,
10+
alertDialogFooterClassNames,
11+
alertDialogTitleClassNames,
12+
alertDialogDescriptionClassNames,
13+
alertDialogActionClassNames,
14+
alertDialogCancelClassNames,
15+
} from './styles';
16+
17+
// Import Button component
18+
import Button from '../button/index';
19+
20+
// Types
21+
type AlertDialogContextValue = {
22+
open: boolean;
23+
setOpen: (open: boolean) => void;
24+
mode: 'light' | 'dark';
25+
};
26+
27+
// Create context
28+
const AlertDialogContext = createContext<AlertDialogContextValue | null>(null);
29+
30+
// Hook to use AlertDialog context
31+
const useAlertDialog = () => {
32+
const context = useContext(AlertDialogContext);
33+
if (!context) {
34+
throw new Error('useAlertDialog must be used within an AlertDialog');
35+
}
36+
return context;
37+
};
38+
39+
// Root AlertDialog component
40+
interface AlertDialogProps {
41+
open?: boolean;
42+
onOpenChange?: (open: boolean) => void;
43+
mode?: 'light' | 'dark';
44+
children: React.ReactNode;
45+
}
46+
47+
export const AlertDialog: React.FC<AlertDialogProps> = ({
48+
open: controlledOpen,
49+
onOpenChange,
50+
mode = 'light',
51+
children,
52+
}) => {
53+
const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
54+
55+
const isControlled = controlledOpen !== undefined;
56+
const open = isControlled ? controlledOpen : uncontrolledOpen;
57+
58+
const setOpen = (newOpen: boolean) => {
59+
if (isControlled) {
60+
onOpenChange?.(newOpen);
61+
} else {
62+
setUncontrolledOpen(newOpen);
63+
}
64+
};
65+
66+
return (
67+
<AlertDialogContext.Provider value={{ open, setOpen, mode }}>
68+
<div className={cn(alertDialogClassNames.base)}>{children}</div>
69+
</AlertDialogContext.Provider>
70+
);
71+
};
72+
73+
// AlertDialogTrigger component
74+
interface AlertDialogTriggerProps {
75+
className?: string;
76+
children: React.ReactNode;
77+
asChild?: boolean;
78+
}
79+
80+
export const AlertDialogTrigger: React.FC<AlertDialogTriggerProps> = ({
81+
className = '',
82+
children,
83+
asChild = false,
84+
}) => {
85+
const { setOpen, mode } = useAlertDialog();
86+
87+
if (asChild && React.isValidElement(children)) {
88+
return React.cloneElement(children as React.ReactElement<any>, {
89+
onClick: () => setOpen(true),
90+
});
91+
}
92+
93+
return (
94+
<Button
95+
variant="default"
96+
mode={mode}
97+
className={cn(alertDialogTriggerClassNames.base, className)}
98+
onClick={() => setOpen(true)}
99+
>
100+
{children}
101+
</Button>
102+
);
103+
};
104+
105+
// AlertDialogContent component
106+
interface AlertDialogContentProps {
107+
className?: string;
108+
children: React.ReactNode;
109+
}
110+
111+
export const AlertDialogContent: React.FC<AlertDialogContentProps> = ({
112+
className = '',
113+
children,
114+
}) => {
115+
const { open, setOpen, mode } = useAlertDialog();
116+
const isDark = mode === 'dark';
117+
const contentRef = useRef<HTMLDivElement>(null);
118+
119+
useEffect(() => {
120+
const handleClickOutside = (event: MouseEvent) => {
121+
if (contentRef.current && !contentRef.current.contains(event.target as Node)) {
122+
setOpen(false);
123+
}
124+
};
125+
126+
if (open) {
127+
document.addEventListener('mousedown', handleClickOutside);
128+
}
129+
130+
return () => {
131+
document.removeEventListener('mousedown', handleClickOutside);
132+
};
133+
}, [open, setOpen]);
134+
135+
if (!open) return null;
136+
137+
return (
138+
<div className="fixed inset-0 z-50 bg-black/80">
139+
<div className="fixed inset-0 flex items-center justify-center p-4">
140+
<div
141+
ref={contentRef}
142+
className={cn(
143+
alertDialogContentClassNames.base,
144+
isDark
145+
? alertDialogContentClassNames.theme.dark
146+
: alertDialogContentClassNames.theme.light,
147+
'w-full max-w-md transform rounded-lg shadow-xl transition-all',
148+
className
149+
)}
150+
>
151+
<div className="gap-4 w-full">{children}</div>
152+
</div>
153+
</div>
154+
</div>
155+
);
156+
};
157+
158+
// AlertDialogHeader component
159+
interface AlertDialogHeaderProps {
160+
className?: string;
161+
children: React.ReactNode;
162+
}
163+
164+
export const AlertDialogHeader: React.FC<AlertDialogHeaderProps> = ({
165+
className = '',
166+
children,
167+
}) => {
168+
return <div className={cn(alertDialogHeaderClassNames.base, className)}>{children}</div>;
169+
};
170+
171+
// AlertDialogFooter component
172+
interface AlertDialogFooterProps {
173+
className?: string;
174+
children: React.ReactNode;
175+
}
176+
177+
export const AlertDialogFooter: React.FC<AlertDialogFooterProps> = ({
178+
className = '',
179+
children,
180+
}) => {
181+
return (
182+
<div
183+
className={cn(
184+
alertDialogFooterClassNames.base,
185+
'mt-6 flex flex-col-reverse sm:flex-row gap-2 sm:gap-3',
186+
className
187+
)}
188+
>
189+
{children}
190+
</div>
191+
);
192+
};
193+
194+
// AlertDialogTitle component
195+
interface AlertDialogTitleProps {
196+
className?: string;
197+
children: React.ReactNode;
198+
}
199+
200+
export const AlertDialogTitle: React.FC<AlertDialogTitleProps> = ({ className = '', children }) => {
201+
const { mode } = useAlertDialog();
202+
const isDark = mode === 'dark';
203+
204+
return (
205+
<h2
206+
className={cn(
207+
alertDialogTitleClassNames.base,
208+
isDark ? alertDialogTitleClassNames.theme.dark : alertDialogTitleClassNames.theme.light,
209+
className
210+
)}
211+
>
212+
{children}
213+
</h2>
214+
);
215+
};
216+
217+
// AlertDialogDescription component
218+
interface AlertDialogDescriptionProps {
219+
className?: string;
220+
children: React.ReactNode;
221+
}
222+
223+
export const AlertDialogDescription: React.FC<AlertDialogDescriptionProps> = ({
224+
className = '',
225+
children,
226+
}) => {
227+
const { mode } = useAlertDialog();
228+
const isDark = mode === 'dark';
229+
230+
return (
231+
<div className={cn(alertDialogDescriptionClassNames.container, className)}>
232+
<p
233+
className={cn(
234+
alertDialogDescriptionClassNames.base,
235+
isDark
236+
? alertDialogDescriptionClassNames.theme.dark
237+
: alertDialogDescriptionClassNames.theme.light
238+
)}
239+
>
240+
{children}
241+
</p>
242+
</div>
243+
);
244+
};
245+
246+
// AlertDialogAction component
247+
interface AlertDialogActionProps {
248+
className?: string;
249+
children: React.ReactNode;
250+
onClick?: () => void;
251+
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
252+
}
253+
254+
export const AlertDialogAction: React.FC<AlertDialogActionProps> = ({
255+
className = '',
256+
children,
257+
onClick,
258+
variant = 'default',
259+
}) => {
260+
const { setOpen, mode } = useAlertDialog();
261+
262+
const handleClick = () => {
263+
if (onClick) {
264+
onClick();
265+
}
266+
setOpen(false);
267+
};
268+
269+
return (
270+
<Button
271+
variant={variant}
272+
mode={mode}
273+
className={cn(alertDialogActionClassNames.base, className)}
274+
onClick={handleClick}
275+
>
276+
{children}
277+
</Button>
278+
);
279+
};
280+
281+
// AlertDialogCancel component
282+
interface AlertDialogCancelProps {
283+
className?: string;
284+
children: React.ReactNode;
285+
onClick?: () => void;
286+
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link';
287+
}
288+
289+
export const AlertDialogCancel: React.FC<AlertDialogCancelProps> = ({
290+
className = '',
291+
children,
292+
onClick,
293+
variant = 'outline',
294+
}) => {
295+
const { setOpen, mode } = useAlertDialog();
296+
297+
const handleClick = () => {
298+
if (onClick) {
299+
onClick();
300+
}
301+
setOpen(false);
302+
};
303+
304+
return (
305+
<Button
306+
variant={variant}
307+
mode={mode}
308+
className={cn(alertDialogCancelClassNames.base, className)}
309+
onClick={handleClick}
310+
>
311+
{children}
312+
</Button>
313+
);
314+
};
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// AlertDialog styling
2+
export const alertDialogClassNames = {
3+
base: 'relative',
4+
};
5+
6+
// AlertDialogTrigger styling
7+
export const alertDialogTriggerClassNames = {
8+
base: '',
9+
};
10+
11+
// AlertDialogContent styling
12+
export const alertDialogContentClassNames = {
13+
base: 'relative border rounded-lg p-6 shadow-lg',
14+
theme: {
15+
light: 'bg-white border-gray-200',
16+
dark: 'bg-gray-900 border-gray-700',
17+
},
18+
};
19+
20+
// AlertDialogHeader styling
21+
export const alertDialogHeaderClassNames = {
22+
base: 'flex flex-col space-y-2 text-center sm:text-left',
23+
};
24+
25+
// AlertDialogFooter styling
26+
export const alertDialogFooterClassNames = {
27+
base: 'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
28+
};
29+
30+
// AlertDialogTitle styling
31+
export const alertDialogTitleClassNames = {
32+
base: 'text-lg font-semibold leading-none tracking-tight',
33+
theme: {
34+
light: 'text-gray-900',
35+
dark: 'text-gray-50',
36+
},
37+
};
38+
39+
// AlertDialogDescription styling
40+
export const alertDialogDescriptionClassNames = {
41+
base: 'text-sm',
42+
theme: {
43+
light: 'text-gray-500',
44+
dark: 'text-gray-400',
45+
},
46+
container: 'mt-2',
47+
};
48+
49+
// AlertDialogAction styling
50+
export const alertDialogActionClassNames = {
51+
base: 'mt-2 sm:mt-0',
52+
};
53+
54+
// AlertDialogCancel styling
55+
export const alertDialogCancelClassNames = {
56+
base: 'mt-2 sm:mt-0',
57+
};

docs/pages/components/_meta.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"accordion": "Accordion",
33
"alert": "Alert",
4-
"button": "Button"
4+
"button": "Button",
5+
"alert-dialog": "AlertDialog"
56
}

0 commit comments

Comments
 (0)