@tidecloak/ui-framework 0.0.1

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.
Files changed (48) hide show
  1. package/README.md +377 -0
  2. package/dist/index.d.mts +2739 -0
  3. package/dist/index.d.ts +2739 -0
  4. package/dist/index.js +12869 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.mjs +12703 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +54 -0
  9. package/src/components/common/ActionButton.tsx +234 -0
  10. package/src/components/common/EmptyState.tsx +140 -0
  11. package/src/components/common/LoadingSkeleton.tsx +121 -0
  12. package/src/components/common/RefreshButton.tsx +127 -0
  13. package/src/components/common/StatusBadge.tsx +177 -0
  14. package/src/components/common/index.ts +31 -0
  15. package/src/components/data-table/DataTable.tsx +201 -0
  16. package/src/components/data-table/PaginatedTable.tsx +247 -0
  17. package/src/components/data-table/index.ts +2 -0
  18. package/src/components/dialogs/CollapsibleSection.tsx +184 -0
  19. package/src/components/dialogs/ConfirmDialog.tsx +264 -0
  20. package/src/components/dialogs/DetailDialog.tsx +228 -0
  21. package/src/components/dialogs/index.ts +3 -0
  22. package/src/components/index.ts +5 -0
  23. package/src/components/pages/base/ApprovalsPageBase.tsx +680 -0
  24. package/src/components/pages/base/LogsPageBase.tsx +581 -0
  25. package/src/components/pages/base/RolesPageBase.tsx +1470 -0
  26. package/src/components/pages/base/TemplatesPageBase.tsx +761 -0
  27. package/src/components/pages/base/UsersPageBase.tsx +843 -0
  28. package/src/components/pages/base/index.ts +58 -0
  29. package/src/components/pages/connected/ApprovalsPage.tsx +797 -0
  30. package/src/components/pages/connected/LogsPage.tsx +267 -0
  31. package/src/components/pages/connected/RolesPage.tsx +525 -0
  32. package/src/components/pages/connected/TemplatesPage.tsx +181 -0
  33. package/src/components/pages/connected/UsersPage.tsx +237 -0
  34. package/src/components/pages/connected/index.ts +36 -0
  35. package/src/components/pages/index.ts +5 -0
  36. package/src/components/tabs/TabsView.tsx +300 -0
  37. package/src/components/tabs/index.ts +1 -0
  38. package/src/components/ui/index.tsx +1001 -0
  39. package/src/hooks/index.ts +3 -0
  40. package/src/hooks/useAutoRefresh.ts +119 -0
  41. package/src/hooks/usePagination.ts +152 -0
  42. package/src/hooks/useSelection.ts +81 -0
  43. package/src/index.ts +256 -0
  44. package/src/theme.ts +185 -0
  45. package/src/tide/index.ts +19 -0
  46. package/src/tide/tidePolicy.ts +270 -0
  47. package/src/types/index.ts +484 -0
  48. package/src/utils/index.ts +121 -0
@@ -0,0 +1,184 @@
1
+ import React, { useState } from "react";
2
+ import { ChevronDown, ChevronRight } from "lucide-react";
3
+ import { cn } from "../../utils";
4
+
5
+ export interface CollapsibleSectionProps {
6
+ /** Trigger/header content */
7
+ trigger: React.ReactNode;
8
+ /** Collapsible content */
9
+ children: React.ReactNode;
10
+ /** Default open state */
11
+ defaultOpen?: boolean;
12
+ /** Controlled open state */
13
+ open?: boolean;
14
+ /** Open state change handler */
15
+ onOpenChange?: (open: boolean) => void;
16
+ /** Icon to show when collapsed */
17
+ collapsedIcon?: React.ReactNode;
18
+ /** Icon to show when expanded */
19
+ expandedIcon?: React.ReactNode;
20
+ /** Additional class name */
21
+ className?: string;
22
+ /** Trigger class name */
23
+ triggerClassName?: string;
24
+ /** Content class name */
25
+ contentClassName?: string;
26
+ /** Custom components */
27
+ components?: {
28
+ Collapsible?: React.ComponentType<{
29
+ open: boolean;
30
+ onOpenChange: (open: boolean) => void;
31
+ children: React.ReactNode;
32
+ }>;
33
+ CollapsibleTrigger?: React.ComponentType<{
34
+ asChild?: boolean;
35
+ children: React.ReactNode;
36
+ }>;
37
+ CollapsibleContent?: React.ComponentType<{
38
+ children: React.ReactNode;
39
+ className?: string;
40
+ }>;
41
+ Button?: React.ComponentType<{
42
+ variant?: string;
43
+ size?: string;
44
+ className?: string;
45
+ children: React.ReactNode;
46
+ onClick?: () => void;
47
+ }>;
48
+ };
49
+ }
50
+
51
+ /**
52
+ * CollapsibleSection - Expandable content section
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * <CollapsibleSection
57
+ * trigger={<><Code className="h-4 w-4" /> View Code</>}
58
+ * defaultOpen={false}
59
+ * >
60
+ * <pre className="p-3 text-xs font-mono">{code}</pre>
61
+ * </CollapsibleSection>
62
+ * ```
63
+ */
64
+ export function CollapsibleSection({
65
+ trigger,
66
+ children,
67
+ defaultOpen = false,
68
+ open: controlledOpen,
69
+ onOpenChange,
70
+ collapsedIcon,
71
+ expandedIcon,
72
+ className,
73
+ triggerClassName,
74
+ contentClassName,
75
+ components = {},
76
+ }: CollapsibleSectionProps) {
77
+ const [internalOpen, setInternalOpen] = useState(defaultOpen);
78
+
79
+ const isControlled = controlledOpen !== undefined;
80
+ const isOpen = isControlled ? controlledOpen : internalOpen;
81
+
82
+ const handleOpenChange = (newOpen: boolean) => {
83
+ if (!isControlled) {
84
+ setInternalOpen(newOpen);
85
+ }
86
+ onOpenChange?.(newOpen);
87
+ };
88
+
89
+ // Custom components
90
+ const Collapsible = components.Collapsible;
91
+ const CollapsibleTrigger = components.CollapsibleTrigger;
92
+ const CollapsibleContent = components.CollapsibleContent;
93
+ const Button = components.Button;
94
+
95
+ // Use custom Radix-style components if all are provided
96
+ if (Collapsible && CollapsibleTrigger && CollapsibleContent && Button) {
97
+ return (
98
+ <Collapsible open={isOpen} onOpenChange={handleOpenChange}>
99
+ <CollapsibleTrigger asChild>
100
+ <Button
101
+ variant="ghost"
102
+ size="sm"
103
+ className={cn("w-full justify-start gap-2 text-muted-foreground hover:text-foreground", triggerClassName)}
104
+ >
105
+ {isOpen
106
+ ? (expandedIcon || <ChevronDown className="h-4 w-4" />)
107
+ : (collapsedIcon || <ChevronRight className="h-4 w-4" />)
108
+ }
109
+ {trigger}
110
+ </Button>
111
+ </CollapsibleTrigger>
112
+ <CollapsibleContent className={contentClassName}>
113
+ {children}
114
+ </CollapsibleContent>
115
+ </Collapsible>
116
+ );
117
+ }
118
+
119
+ // Default implementation
120
+ return (
121
+ <div className={className}>
122
+ <button
123
+ type="button"
124
+ onClick={() => handleOpenChange(!isOpen)}
125
+ className={cn(
126
+ "flex w-full items-center justify-start gap-2 rounded-md px-3 py-2 text-sm",
127
+ "text-muted-foreground hover:text-foreground hover:bg-accent",
128
+ triggerClassName
129
+ )}
130
+ >
131
+ {isOpen
132
+ ? (expandedIcon || <ChevronDown className="h-4 w-4" />)
133
+ : (collapsedIcon || <ChevronRight className="h-4 w-4" />)
134
+ }
135
+ {trigger}
136
+ </button>
137
+ {isOpen && (
138
+ <div className={cn("mt-2", contentClassName)}>
139
+ {children}
140
+ </div>
141
+ )}
142
+ </div>
143
+ );
144
+ }
145
+
146
+ /**
147
+ * CodePreview - Pre-styled collapsible code section
148
+ */
149
+ export function CodePreview({
150
+ code,
151
+ language = "text",
152
+ label = "View Code",
153
+ icon,
154
+ maxHeight = "300px",
155
+ className,
156
+ ...props
157
+ }: {
158
+ code: string;
159
+ language?: string;
160
+ label?: string;
161
+ icon?: React.ReactNode;
162
+ maxHeight?: string;
163
+ className?: string;
164
+ } & Omit<CollapsibleSectionProps, 'trigger' | 'children'>) {
165
+ return (
166
+ <CollapsibleSection
167
+ trigger={
168
+ <>
169
+ {icon}
170
+ {label}
171
+ </>
172
+ }
173
+ contentClassName={cn("mt-2 border rounded-lg bg-muted/50", className)}
174
+ {...props}
175
+ >
176
+ <pre
177
+ className="p-3 text-xs font-mono overflow-x-auto overflow-y-auto whitespace-pre-wrap"
178
+ style={{ maxHeight }}
179
+ >
180
+ {code}
181
+ </pre>
182
+ </CollapsibleSection>
183
+ );
184
+ }
@@ -0,0 +1,264 @@
1
+ import React from "react";
2
+
3
+ export interface ConfirmDialogProps {
4
+ /** Whether dialog is open */
5
+ open: boolean;
6
+ /** Close handler */
7
+ onClose: () => void;
8
+ /** Confirm handler */
9
+ onConfirm: () => void | Promise<void>;
10
+ /** Dialog title */
11
+ title: string;
12
+ /** Dialog description */
13
+ description: string;
14
+ /** Confirm button label */
15
+ confirmLabel?: string;
16
+ /** Cancel button label */
17
+ cancelLabel?: string;
18
+ /** Confirm button variant */
19
+ confirmVariant?: "default" | "destructive";
20
+ /** Whether action is in progress */
21
+ isLoading?: boolean;
22
+ /** Additional class name */
23
+ className?: string;
24
+ /** Custom components */
25
+ components?: {
26
+ AlertDialog?: React.ComponentType<{
27
+ open: boolean;
28
+ onOpenChange: (open: boolean) => void;
29
+ children: React.ReactNode;
30
+ }>;
31
+ AlertDialogContent?: React.ComponentType<{ children: React.ReactNode }>;
32
+ AlertDialogHeader?: React.ComponentType<{ children: React.ReactNode }>;
33
+ AlertDialogTitle?: React.ComponentType<{ children: React.ReactNode }>;
34
+ AlertDialogDescription?: React.ComponentType<{ children: React.ReactNode }>;
35
+ AlertDialogFooter?: React.ComponentType<{ children: React.ReactNode }>;
36
+ AlertDialogAction?: React.ComponentType<{
37
+ onClick: () => void;
38
+ className?: string;
39
+ style?: React.CSSProperties;
40
+ disabled?: boolean;
41
+ children: React.ReactNode;
42
+ }>;
43
+ AlertDialogCancel?: React.ComponentType<{
44
+ onClick?: () => void;
45
+ children: React.ReactNode;
46
+ }>;
47
+ };
48
+ }
49
+
50
+ /**
51
+ * ConfirmDialog - Confirmation dialog for destructive actions
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * <ConfirmDialog
56
+ * open={showDelete}
57
+ * onClose={() => setShowDelete(false)}
58
+ * onConfirm={handleDelete}
59
+ * title="Delete Item"
60
+ * description="Are you sure? This action cannot be undone."
61
+ * confirmLabel="Delete"
62
+ * confirmVariant="destructive"
63
+ * isLoading={isDeleting}
64
+ * />
65
+ * ```
66
+ */
67
+ export function ConfirmDialog({
68
+ open,
69
+ onClose,
70
+ onConfirm,
71
+ title,
72
+ description,
73
+ confirmLabel = "Confirm",
74
+ cancelLabel = "Cancel",
75
+ confirmVariant = "default",
76
+ isLoading = false,
77
+ className,
78
+ components = {},
79
+ }: ConfirmDialogProps) {
80
+ const AlertDialog = components.AlertDialog || DefaultAlertDialog;
81
+ const AlertDialogContent = components.AlertDialogContent || DefaultAlertDialogContent;
82
+ const AlertDialogHeader = components.AlertDialogHeader || DefaultAlertDialogHeader;
83
+ const AlertDialogTitle = components.AlertDialogTitle || DefaultAlertDialogTitle;
84
+ const AlertDialogDescription = components.AlertDialogDescription || DefaultAlertDialogDescription;
85
+ const AlertDialogFooter = components.AlertDialogFooter || DefaultAlertDialogFooter;
86
+ const AlertDialogAction = components.AlertDialogAction || DefaultAlertDialogAction;
87
+ const AlertDialogCancel = components.AlertDialogCancel || DefaultAlertDialogCancel;
88
+
89
+ const handleConfirm = async () => {
90
+ await onConfirm();
91
+ onClose();
92
+ };
93
+
94
+ const destructiveStyle: React.CSSProperties = confirmVariant === "destructive"
95
+ ? { backgroundColor: "#ef4444", color: "#ffffff" }
96
+ : {};
97
+
98
+ return (
99
+ <AlertDialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
100
+ <AlertDialogContent>
101
+ <AlertDialogHeader>
102
+ <AlertDialogTitle>{title}</AlertDialogTitle>
103
+ <AlertDialogDescription>{description}</AlertDialogDescription>
104
+ </AlertDialogHeader>
105
+ <AlertDialogFooter>
106
+ <AlertDialogCancel onClick={onClose}>{cancelLabel}</AlertDialogCancel>
107
+ <AlertDialogAction
108
+ onClick={handleConfirm}
109
+ disabled={isLoading}
110
+ style={destructiveStyle}
111
+ >
112
+ {isLoading ? "Processing..." : confirmLabel}
113
+ </AlertDialogAction>
114
+ </AlertDialogFooter>
115
+ </AlertDialogContent>
116
+ </AlertDialog>
117
+ );
118
+ }
119
+
120
+ // Default alert dialog components with inline styles
121
+ function DefaultAlertDialog({
122
+ open,
123
+ onOpenChange,
124
+ children,
125
+ }: {
126
+ open: boolean;
127
+ onOpenChange: (open: boolean) => void;
128
+ children: React.ReactNode;
129
+ }) {
130
+ if (!open) return null;
131
+
132
+ return (
133
+ <div style={{ position: "fixed", inset: 0, zIndex: 50 }} role="presentation">
134
+ <div
135
+ style={{ position: "fixed", inset: 0, backgroundColor: "rgba(0, 0, 0, 0.8)" }}
136
+ onClick={() => onOpenChange(false)}
137
+ aria-hidden="true"
138
+ />
139
+ <div style={{ position: "fixed", inset: 0, display: "flex", alignItems: "center", justifyContent: "center", padding: "1rem" }}>
140
+ {children}
141
+ </div>
142
+ </div>
143
+ );
144
+ }
145
+
146
+ function DefaultAlertDialogContent({ children }: { children: React.ReactNode }) {
147
+ return (
148
+ <div
149
+ role="alertdialog"
150
+ aria-modal="true"
151
+ aria-labelledby="alert-dialog-title"
152
+ aria-describedby="alert-dialog-description"
153
+ style={{
154
+ position: "relative",
155
+ zIndex: 50,
156
+ display: "grid",
157
+ width: "100%",
158
+ maxWidth: "32rem",
159
+ gap: "1rem",
160
+ border: "1px solid #e5e7eb",
161
+ backgroundColor: "#ffffff",
162
+ padding: "1.5rem",
163
+ boxShadow: "0 10px 15px -3px rgba(0, 0, 0, 0.1)",
164
+ borderRadius: "0.5rem",
165
+ }}
166
+ onClick={(e) => e.stopPropagation()}
167
+ >
168
+ {children}
169
+ </div>
170
+ );
171
+ }
172
+
173
+ function DefaultAlertDialogHeader({ children }: { children: React.ReactNode }) {
174
+ return <div style={{ display: "flex", flexDirection: "column", gap: "0.5rem" }}>{children}</div>;
175
+ }
176
+
177
+ function DefaultAlertDialogTitle({ children }: { children: React.ReactNode }) {
178
+ return <h2 id="alert-dialog-title" style={{ fontSize: "1.125rem", fontWeight: 600, margin: 0 }}>{children}</h2>;
179
+ }
180
+
181
+ function DefaultAlertDialogDescription({ children }: { children: React.ReactNode }) {
182
+ return <p id="alert-dialog-description" style={{ fontSize: "0.875rem", color: "#6b7280", margin: 0 }}>{children}</p>;
183
+ }
184
+
185
+ function DefaultAlertDialogFooter({ children }: { children: React.ReactNode }) {
186
+ return (
187
+ <div style={{ display: "flex", justifyContent: "flex-end", gap: "0.5rem" }}>
188
+ {children}
189
+ </div>
190
+ );
191
+ }
192
+
193
+ function DefaultAlertDialogAction({
194
+ onClick,
195
+ className,
196
+ style,
197
+ disabled,
198
+ children,
199
+ }: {
200
+ onClick: () => void;
201
+ className?: string;
202
+ style?: React.CSSProperties;
203
+ disabled?: boolean;
204
+ children: React.ReactNode;
205
+ }) {
206
+ const baseStyle: React.CSSProperties = {
207
+ display: "inline-flex",
208
+ alignItems: "center",
209
+ justifyContent: "center",
210
+ borderRadius: "0.375rem",
211
+ fontSize: "0.875rem",
212
+ fontWeight: 500,
213
+ height: "2.5rem",
214
+ padding: "0.5rem 1rem",
215
+ backgroundColor: "#3b82f6",
216
+ color: "#ffffff",
217
+ border: "none",
218
+ cursor: disabled ? "not-allowed" : "pointer",
219
+ opacity: disabled ? 0.5 : 1,
220
+ ...style,
221
+ };
222
+
223
+ return (
224
+ <button
225
+ type="button"
226
+ onClick={onClick}
227
+ disabled={disabled}
228
+ style={baseStyle}
229
+ className={className}
230
+ >
231
+ {children}
232
+ </button>
233
+ );
234
+ }
235
+
236
+ function DefaultAlertDialogCancel({
237
+ onClick,
238
+ children,
239
+ }: {
240
+ onClick?: () => void;
241
+ children: React.ReactNode;
242
+ }) {
243
+ return (
244
+ <button
245
+ type="button"
246
+ onClick={onClick}
247
+ style={{
248
+ display: "inline-flex",
249
+ alignItems: "center",
250
+ justifyContent: "center",
251
+ borderRadius: "0.375rem",
252
+ fontSize: "0.875rem",
253
+ fontWeight: 500,
254
+ height: "2.5rem",
255
+ padding: "0.5rem 1rem",
256
+ border: "1px solid #e5e7eb",
257
+ backgroundColor: "#ffffff",
258
+ cursor: "pointer",
259
+ }}
260
+ >
261
+ {children}
262
+ </button>
263
+ );
264
+ }
@@ -0,0 +1,228 @@
1
+ import React from "react";
2
+ import { X } from "lucide-react";
3
+ import { cn } from "../../utils";
4
+ import type { DetailField, BaseDataItem } from "../../types";
5
+
6
+ export interface DetailDialogProps<T extends BaseDataItem> {
7
+ /** Whether dialog is open */
8
+ open: boolean;
9
+ /** Close handler */
10
+ onClose: () => void;
11
+ /** Item to display */
12
+ item: T | null;
13
+ /** Dialog title */
14
+ title: string;
15
+ /** Dialog description */
16
+ description?: string;
17
+ /** Field definitions */
18
+ fields: DetailField<T>[];
19
+ /** Footer content (actions) */
20
+ footer?: React.ReactNode;
21
+ /** Additional content after fields */
22
+ children?: React.ReactNode;
23
+ /** Dialog size */
24
+ size?: "sm" | "md" | "lg" | "xl" | "full";
25
+ /** Additional class name */
26
+ className?: string;
27
+ /** Custom components */
28
+ components?: {
29
+ Dialog?: React.ComponentType<{
30
+ open: boolean;
31
+ onOpenChange: (open: boolean) => void;
32
+ children: React.ReactNode;
33
+ }>;
34
+ DialogContent?: React.ComponentType<{
35
+ className?: string;
36
+ children: React.ReactNode;
37
+ }>;
38
+ DialogHeader?: React.ComponentType<{ children: React.ReactNode }>;
39
+ DialogTitle?: React.ComponentType<{ children: React.ReactNode; className?: string }>;
40
+ DialogDescription?: React.ComponentType<{ children: React.ReactNode }>;
41
+ DialogFooter?: React.ComponentType<{ children: React.ReactNode; className?: string }>;
42
+ };
43
+ }
44
+
45
+ const SIZE_CLASSES = {
46
+ sm: "max-w-sm",
47
+ md: "max-w-md",
48
+ lg: "max-w-lg",
49
+ xl: "max-w-xl",
50
+ full: "max-w-4xl",
51
+ };
52
+
53
+ /**
54
+ * DetailDialog - Dialog for displaying item details
55
+ *
56
+ * @example
57
+ * ```tsx
58
+ * <DetailDialog
59
+ * open={!!selectedItem}
60
+ * onClose={() => setSelectedItem(null)}
61
+ * item={selectedItem}
62
+ * title="Policy Details"
63
+ * fields={[
64
+ * { key: 'role', label: 'Role', render: (item) => item.roleId },
65
+ * { key: 'status', label: 'Status', render: (item) => <StatusBadge status={item.status} /> },
66
+ * ]}
67
+ * footer={<Button onClick={() => handleApprove()}>Approve</Button>}
68
+ * />
69
+ * ```
70
+ */
71
+ export function DetailDialog<T extends BaseDataItem>({
72
+ open,
73
+ onClose,
74
+ item,
75
+ title,
76
+ description,
77
+ fields,
78
+ footer,
79
+ children,
80
+ size = "lg",
81
+ className,
82
+ components = {},
83
+ }: DetailDialogProps<T>) {
84
+ // Use custom components or defaults
85
+ const Dialog = components.Dialog || DefaultDialog;
86
+ const DialogContent = components.DialogContent || DefaultDialogContent;
87
+ const DialogHeader = components.DialogHeader || DefaultDialogHeader;
88
+ const DialogTitle = components.DialogTitle || DefaultDialogTitle;
89
+ const DialogDescription = components.DialogDescription || DefaultDialogDescription;
90
+ const DialogFooter = components.DialogFooter || DefaultDialogFooter;
91
+
92
+ if (!item) return null;
93
+
94
+ // Filter visible fields
95
+ const visibleFields = fields.filter(
96
+ (field) => !field.hidden || !field.hidden(item)
97
+ );
98
+
99
+ return (
100
+ <Dialog open={open} onOpenChange={(isOpen) => !isOpen && onClose()}>
101
+ <DialogContent className={cn(SIZE_CLASSES[size], "max-h-[90vh] overflow-y-auto", className)}>
102
+ <DialogHeader>
103
+ <DialogTitle>{title}</DialogTitle>
104
+ {description && <DialogDescription>{description}</DialogDescription>}
105
+ </DialogHeader>
106
+
107
+ <div className="space-y-4">
108
+ {/* Fields Grid */}
109
+ <div className="grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm">
110
+ {visibleFields.map((field) => (
111
+ <div
112
+ key={field.key}
113
+ className={field.fullWidth ? "col-span-2" : ""}
114
+ >
115
+ <p className="text-muted-foreground">{field.label}</p>
116
+ <div className="font-medium mt-1">{field.render(item)}</div>
117
+ </div>
118
+ ))}
119
+ </div>
120
+
121
+ {/* Additional content */}
122
+ {children}
123
+ </div>
124
+
125
+ {/* Footer */}
126
+ {footer && <DialogFooter>{footer}</DialogFooter>}
127
+ </DialogContent>
128
+ </Dialog>
129
+ );
130
+ }
131
+
132
+ // Default dialog components
133
+ function DefaultDialog({
134
+ open,
135
+ onOpenChange,
136
+ children,
137
+ }: {
138
+ open: boolean;
139
+ onOpenChange: (open: boolean) => void;
140
+ children: React.ReactNode;
141
+ }) {
142
+ if (!open) return null;
143
+
144
+ return (
145
+ <div className="fixed inset-0 z-50">
146
+ {/* Backdrop */}
147
+ <div
148
+ className="fixed inset-0 bg-black/80"
149
+ onClick={() => onOpenChange(false)}
150
+ />
151
+ {/* Content container */}
152
+ <div className="fixed inset-0 flex items-center justify-center p-4">
153
+ {children}
154
+ </div>
155
+ </div>
156
+ );
157
+ }
158
+
159
+ function DefaultDialogContent({
160
+ className,
161
+ children,
162
+ }: {
163
+ className?: string;
164
+ children: React.ReactNode;
165
+ }) {
166
+ return (
167
+ <div
168
+ className={cn(
169
+ "relative z-50 grid w-full gap-4 border bg-background p-6 shadow-lg",
170
+ "duration-200 sm:rounded-lg",
171
+ className
172
+ )}
173
+ onClick={(e) => e.stopPropagation()}
174
+ >
175
+ {children}
176
+ </div>
177
+ );
178
+ }
179
+
180
+ function DefaultDialogHeader({ children }: { children: React.ReactNode }) {
181
+ return (
182
+ <div className="flex flex-col space-y-1.5 text-center sm:text-left">
183
+ {children}
184
+ </div>
185
+ );
186
+ }
187
+
188
+ function DefaultDialogTitle({
189
+ children,
190
+ className,
191
+ }: {
192
+ children: React.ReactNode;
193
+ className?: string;
194
+ }) {
195
+ return (
196
+ <h2
197
+ className={cn(
198
+ "text-lg font-semibold leading-none tracking-tight",
199
+ className
200
+ )}
201
+ >
202
+ {children}
203
+ </h2>
204
+ );
205
+ }
206
+
207
+ function DefaultDialogDescription({ children }: { children: React.ReactNode }) {
208
+ return <p className="text-sm text-muted-foreground">{children}</p>;
209
+ }
210
+
211
+ function DefaultDialogFooter({
212
+ children,
213
+ className,
214
+ }: {
215
+ children: React.ReactNode;
216
+ className?: string;
217
+ }) {
218
+ return (
219
+ <div
220
+ className={cn(
221
+ "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
222
+ className
223
+ )}
224
+ >
225
+ {children}
226
+ </div>
227
+ );
228
+ }
@@ -0,0 +1,3 @@
1
+ export { DetailDialog, type DetailDialogProps } from "./DetailDialog";
2
+ export { ConfirmDialog, type ConfirmDialogProps } from "./ConfirmDialog";
3
+ export { CollapsibleSection, CodePreview, type CollapsibleSectionProps } from "./CollapsibleSection";
@@ -0,0 +1,5 @@
1
+ export * from "./common";
2
+ export * from "./data-table";
3
+ export * from "./tabs";
4
+ export * from "./dialogs";
5
+ export * from "./pages";