@moontra/moonui-pro 2.3.8 → 2.4.0
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/dist/index.d.ts +23 -3
- package/dist/index.mjs +687 -83
- package/package.json +4 -3
- package/scripts/postinstall.js +26 -0
- package/src/components/data-table/data-table-bulk-actions.tsx +204 -0
- package/src/components/data-table/data-table-column-toggle.tsx +166 -0
- package/src/components/data-table/data-table-export.ts +156 -0
- package/src/components/data-table/index.tsx +196 -86
- package/src/components/ui/alert-dialog.tsx +141 -0
|
@@ -33,18 +33,34 @@ import {
|
|
|
33
33
|
Settings,
|
|
34
34
|
Lock,
|
|
35
35
|
Sparkles,
|
|
36
|
-
Loader2
|
|
36
|
+
Loader2,
|
|
37
|
+
FileDown,
|
|
38
|
+
FileJson,
|
|
39
|
+
FileSpreadsheet
|
|
37
40
|
} from 'lucide-react'
|
|
38
41
|
import { cn } from '../../lib/utils'
|
|
39
42
|
import { useSubscription } from '../../hooks/use-subscription'
|
|
40
43
|
import { motion, AnimatePresence } from 'framer-motion'
|
|
44
|
+
import { DataTableColumnToggle } from './data-table-column-toggle'
|
|
45
|
+
import { DataTableBulkActions, type BulkAction } from './data-table-bulk-actions'
|
|
46
|
+
import { exportData, type ExportFormat, getVisibleColumns } from './data-table-export'
|
|
47
|
+
import {
|
|
48
|
+
DropdownMenu,
|
|
49
|
+
DropdownMenuContent,
|
|
50
|
+
DropdownMenuItem,
|
|
51
|
+
DropdownMenuTrigger,
|
|
52
|
+
} from '../ui/dropdown-menu'
|
|
41
53
|
|
|
42
54
|
interface DataTableProps<TData, TValue> {
|
|
43
55
|
columns: ColumnDef<TData, TValue>[]
|
|
44
56
|
data: TData[]
|
|
45
57
|
searchable?: boolean
|
|
46
58
|
filterable?: boolean
|
|
47
|
-
exportable?: boolean
|
|
59
|
+
exportable?: boolean | {
|
|
60
|
+
formats?: ExportFormat[]
|
|
61
|
+
filename?: string
|
|
62
|
+
onExport?: (data: TData[], format: ExportFormat) => void
|
|
63
|
+
}
|
|
48
64
|
selectable?: boolean
|
|
49
65
|
pagination?: boolean
|
|
50
66
|
pageSize?: number
|
|
@@ -55,6 +71,7 @@ interface DataTableProps<TData, TValue> {
|
|
|
55
71
|
renderSubComponent?: (props: { row: { original: TData; id: string } }) => React.ReactNode
|
|
56
72
|
expandedRows?: Set<string>
|
|
57
73
|
onRowExpandChange?: (expandedRows: Set<string>) => void
|
|
74
|
+
bulkActions?: BulkAction<TData>[]
|
|
58
75
|
// Additional props for compatibility
|
|
59
76
|
enableSorting?: boolean
|
|
60
77
|
enableFiltering?: boolean
|
|
@@ -116,6 +133,7 @@ export function DataTable<TData, TValue>({
|
|
|
116
133
|
renderSubComponent,
|
|
117
134
|
expandedRows: controlledExpandedRows,
|
|
118
135
|
onRowExpandChange,
|
|
136
|
+
bulkActions = [],
|
|
119
137
|
features = {},
|
|
120
138
|
theme = {},
|
|
121
139
|
texts = {},
|
|
@@ -213,6 +231,11 @@ export function DataTable<TData, TValue>({
|
|
|
213
231
|
pageSize: actualPageSize,
|
|
214
232
|
},
|
|
215
233
|
},
|
|
234
|
+
// Prevent re-renders on state changes
|
|
235
|
+
autoResetAll: false,
|
|
236
|
+
autoResetPageIndex: false,
|
|
237
|
+
autoResetExpanded: false,
|
|
238
|
+
getRowId: (row: TData) => (row as any).id || (row as any).orderId || Math.random().toString(),
|
|
216
239
|
})
|
|
217
240
|
|
|
218
241
|
React.useEffect(() => {
|
|
@@ -224,11 +247,19 @@ export function DataTable<TData, TValue>({
|
|
|
224
247
|
|
|
225
248
|
// Memoize row model to prevent unnecessary re-renders when only expanded state changes
|
|
226
249
|
const tableState = table.getState()
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
)
|
|
250
|
+
const rowModel = table.getRowModel()
|
|
251
|
+
|
|
252
|
+
// Use a ref to track if rows actually changed
|
|
253
|
+
const rowsRef = React.useRef(rowModel.rows)
|
|
254
|
+
const rowsChanged = React.useMemo(() => {
|
|
255
|
+
const changed = rowsRef.current !== rowModel.rows
|
|
256
|
+
if (changed) {
|
|
257
|
+
rowsRef.current = rowModel.rows
|
|
258
|
+
}
|
|
259
|
+
return changed
|
|
260
|
+
}, [rowModel.rows])
|
|
261
|
+
|
|
262
|
+
const rows = rowsRef.current
|
|
232
263
|
|
|
233
264
|
// Merge features with defaults
|
|
234
265
|
const enabledFeatures = {
|
|
@@ -241,14 +272,51 @@ export function DataTable<TData, TValue>({
|
|
|
241
272
|
export: features.export !== false || exportable,
|
|
242
273
|
}
|
|
243
274
|
|
|
244
|
-
const handleExport = () => {
|
|
275
|
+
const handleExport = async (format: ExportFormat) => {
|
|
276
|
+
const selectedRows = table.getFilteredSelectedRowModel().rows
|
|
277
|
+
const dataToExport = selectedRows.length > 0
|
|
278
|
+
? selectedRows.map(row => row.original)
|
|
279
|
+
: table.getFilteredRowModel().rows.map(row => row.original)
|
|
280
|
+
|
|
281
|
+
// Use custom export handler if provided
|
|
282
|
+
if (typeof exportable === 'object' && exportable.onExport) {
|
|
283
|
+
exportable.onExport(dataToExport, format)
|
|
284
|
+
return
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Use legacy onExport if provided
|
|
245
288
|
if (onExport) {
|
|
246
|
-
const selectedRows = table.getFilteredSelectedRowModel().rows
|
|
247
|
-
const dataToExport = selectedRows.length > 0
|
|
248
|
-
? selectedRows.map(row => row.original)
|
|
249
|
-
: table.getFilteredRowModel().rows.map(row => row.original)
|
|
250
289
|
onExport(dataToExport)
|
|
290
|
+
return
|
|
251
291
|
}
|
|
292
|
+
|
|
293
|
+
// Default export behavior
|
|
294
|
+
const filename = typeof exportable === 'object' && exportable.filename
|
|
295
|
+
? exportable.filename
|
|
296
|
+
: 'data-export'
|
|
297
|
+
|
|
298
|
+
const visibleColumns = getVisibleColumns(columns as any, columnVisibility)
|
|
299
|
+
|
|
300
|
+
await exportData(dataToExport as Record<string, any>[], {
|
|
301
|
+
format,
|
|
302
|
+
filename,
|
|
303
|
+
columns: visibleColumns,
|
|
304
|
+
includeHeaders: true
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Parse export options
|
|
309
|
+
const exportFormats: ExportFormat[] = React.useMemo(() => {
|
|
310
|
+
if (!exportable) return []
|
|
311
|
+
if (exportable === true) return ['csv', 'json']
|
|
312
|
+
if (typeof exportable === 'object' && exportable.formats) {
|
|
313
|
+
return exportable.formats
|
|
314
|
+
}
|
|
315
|
+
return ['csv', 'json']
|
|
316
|
+
}, [exportable])
|
|
317
|
+
|
|
318
|
+
const clearRowSelection = () => {
|
|
319
|
+
table.resetRowSelection()
|
|
252
320
|
}
|
|
253
321
|
|
|
254
322
|
return (
|
|
@@ -276,20 +344,52 @@ export function DataTable<TData, TValue>({
|
|
|
276
344
|
Filters
|
|
277
345
|
</Button>
|
|
278
346
|
)}
|
|
347
|
+
|
|
348
|
+
{/* Bulk actions */}
|
|
349
|
+
{selectable && bulkActions.length > 0 && (
|
|
350
|
+
<DataTableBulkActions
|
|
351
|
+
selectedRows={table.getFilteredSelectedRowModel().rows.map(row => row.original)}
|
|
352
|
+
actions={bulkActions}
|
|
353
|
+
onClearSelection={clearRowSelection}
|
|
354
|
+
/>
|
|
355
|
+
)}
|
|
279
356
|
</div>
|
|
280
357
|
|
|
281
358
|
<div className="flex items-center space-x-2">
|
|
282
|
-
{
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
359
|
+
{/* Export dropdown */}
|
|
360
|
+
{exportable && exportFormats.length > 0 && (
|
|
361
|
+
<DropdownMenu>
|
|
362
|
+
<DropdownMenuTrigger asChild>
|
|
363
|
+
<Button variant="outline" size="sm">
|
|
364
|
+
<span suppressHydrationWarning><Download className="mr-2 h-4 w-4" /></span>
|
|
365
|
+
Export
|
|
366
|
+
</Button>
|
|
367
|
+
</DropdownMenuTrigger>
|
|
368
|
+
<DropdownMenuContent align="end">
|
|
369
|
+
{exportFormats.includes('csv') && (
|
|
370
|
+
<DropdownMenuItem onClick={() => handleExport('csv')}>
|
|
371
|
+
<FileSpreadsheet className="mr-2 h-4 w-4" />
|
|
372
|
+
Export as CSV
|
|
373
|
+
</DropdownMenuItem>
|
|
374
|
+
)}
|
|
375
|
+
{exportFormats.includes('json') && (
|
|
376
|
+
<DropdownMenuItem onClick={() => handleExport('json')}>
|
|
377
|
+
<FileJson className="mr-2 h-4 w-4" />
|
|
378
|
+
Export as JSON
|
|
379
|
+
</DropdownMenuItem>
|
|
380
|
+
)}
|
|
381
|
+
{exportFormats.includes('xlsx') && (
|
|
382
|
+
<DropdownMenuItem onClick={() => handleExport('xlsx')}>
|
|
383
|
+
<FileDown className="mr-2 h-4 w-4" />
|
|
384
|
+
Export as Excel
|
|
385
|
+
</DropdownMenuItem>
|
|
386
|
+
)}
|
|
387
|
+
</DropdownMenuContent>
|
|
388
|
+
</DropdownMenu>
|
|
287
389
|
)}
|
|
288
390
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
Columns
|
|
292
|
-
</Button>
|
|
391
|
+
{/* Column visibility toggle */}
|
|
392
|
+
<DataTableColumnToggle table={table} />
|
|
293
393
|
</div>
|
|
294
394
|
</div>
|
|
295
395
|
|
|
@@ -355,71 +455,14 @@ export function DataTable<TData, TValue>({
|
|
|
355
455
|
const isExpanded = enableExpandable && expandedRows.has(rowId)
|
|
356
456
|
|
|
357
457
|
return (
|
|
358
|
-
<
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
{row.getVisibleCells().map((cell) => (
|
|
367
|
-
<td key={cell.id} className="moonui-data-table-td p-4 align-middle">
|
|
368
|
-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
369
|
-
</td>
|
|
370
|
-
))}
|
|
371
|
-
</tr>
|
|
372
|
-
|
|
373
|
-
<AnimatePresence initial={false}>
|
|
374
|
-
{isExpanded && renderSubComponent && (
|
|
375
|
-
<motion.tr
|
|
376
|
-
key={`${row.id}-expanded`}
|
|
377
|
-
initial={{ height: 0, opacity: 0 }}
|
|
378
|
-
animate={{
|
|
379
|
-
height: "auto",
|
|
380
|
-
opacity: 1,
|
|
381
|
-
transition: {
|
|
382
|
-
height: {
|
|
383
|
-
duration: 0.3,
|
|
384
|
-
ease: "easeOut"
|
|
385
|
-
},
|
|
386
|
-
opacity: {
|
|
387
|
-
duration: 0.2,
|
|
388
|
-
delay: 0.1
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
}}
|
|
392
|
-
exit={{
|
|
393
|
-
height: 0,
|
|
394
|
-
opacity: 0,
|
|
395
|
-
transition: {
|
|
396
|
-
height: {
|
|
397
|
-
duration: 0.3,
|
|
398
|
-
ease: "easeIn"
|
|
399
|
-
},
|
|
400
|
-
opacity: {
|
|
401
|
-
duration: 0.2
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}}
|
|
405
|
-
style={{ overflow: "hidden" }}
|
|
406
|
-
className="border-b"
|
|
407
|
-
>
|
|
408
|
-
<td colSpan={columns.length} className="p-0">
|
|
409
|
-
<motion.div
|
|
410
|
-
initial={{ y: -10 }}
|
|
411
|
-
animate={{ y: 0 }}
|
|
412
|
-
exit={{ y: -10 }}
|
|
413
|
-
transition={{ duration: 0.2 }}
|
|
414
|
-
className="border-t border-border/50"
|
|
415
|
-
>
|
|
416
|
-
{renderSubComponent({ row: { original: row.original, id: rowId } })}
|
|
417
|
-
</motion.div>
|
|
418
|
-
</td>
|
|
419
|
-
</motion.tr>
|
|
420
|
-
)}
|
|
421
|
-
</AnimatePresence>
|
|
422
|
-
</React.Fragment>
|
|
458
|
+
<TableRow
|
|
459
|
+
key={rowId}
|
|
460
|
+
row={row}
|
|
461
|
+
columns={columns}
|
|
462
|
+
isExpanded={isExpanded}
|
|
463
|
+
enableExpandable={enableExpandable}
|
|
464
|
+
renderSubComponent={renderSubComponent}
|
|
465
|
+
/>
|
|
423
466
|
);
|
|
424
467
|
})}
|
|
425
468
|
</>
|
|
@@ -624,5 +667,72 @@ export function useExpandableRows(initialExpanded: Set<string> = new Set()) {
|
|
|
624
667
|
};
|
|
625
668
|
}
|
|
626
669
|
|
|
670
|
+
// Memoized table row component
|
|
671
|
+
interface TableRowProps {
|
|
672
|
+
row: Row<any>
|
|
673
|
+
columns: ColumnDef<any, any>[]
|
|
674
|
+
isExpanded: boolean
|
|
675
|
+
enableExpandable: boolean
|
|
676
|
+
renderSubComponent?: (props: { row: { original: any; id: string } }) => React.ReactNode
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
const TableRow = React.memo(({
|
|
680
|
+
row,
|
|
681
|
+
columns,
|
|
682
|
+
isExpanded,
|
|
683
|
+
enableExpandable,
|
|
684
|
+
renderSubComponent
|
|
685
|
+
}: TableRowProps) => {
|
|
686
|
+
const rowId = (row.original as any).id || row.id
|
|
687
|
+
|
|
688
|
+
return (
|
|
689
|
+
<>
|
|
690
|
+
<tr
|
|
691
|
+
className={cn(
|
|
692
|
+
"border-b transition-colors hover:bg-muted/50",
|
|
693
|
+
row.getIsSelected() && "bg-muted",
|
|
694
|
+
isExpanded && "border-b-0"
|
|
695
|
+
)}
|
|
696
|
+
>
|
|
697
|
+
{row.getVisibleCells().map((cell) => (
|
|
698
|
+
<td key={cell.id} className="moonui-data-table-td p-4 align-middle">
|
|
699
|
+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
700
|
+
</td>
|
|
701
|
+
))}
|
|
702
|
+
</tr>
|
|
703
|
+
|
|
704
|
+
{isExpanded && renderSubComponent && (
|
|
705
|
+
<tr className="border-b">
|
|
706
|
+
<td colSpan={columns.length} className="p-0 overflow-hidden">
|
|
707
|
+
<div
|
|
708
|
+
className="transition-all duration-300 ease-out"
|
|
709
|
+
style={{
|
|
710
|
+
maxHeight: isExpanded ? '1000px' : '0',
|
|
711
|
+
opacity: isExpanded ? 1 : 0,
|
|
712
|
+
}}
|
|
713
|
+
>
|
|
714
|
+
<div className="border-t border-border/50">
|
|
715
|
+
{renderSubComponent({ row: { original: row.original, id: rowId } })}
|
|
716
|
+
</div>
|
|
717
|
+
</div>
|
|
718
|
+
</td>
|
|
719
|
+
</tr>
|
|
720
|
+
)}
|
|
721
|
+
</>
|
|
722
|
+
)
|
|
723
|
+
}, (prevProps, nextProps) => {
|
|
724
|
+
// Custom comparison - only re-render if row data or expanded state changed
|
|
725
|
+
const prevRowId = (prevProps.row.original as any).id || prevProps.row.id
|
|
726
|
+
const nextRowId = (nextProps.row.original as any).id || nextProps.row.id
|
|
727
|
+
|
|
728
|
+
return prevRowId === nextRowId &&
|
|
729
|
+
prevProps.isExpanded === nextProps.isExpanded &&
|
|
730
|
+
prevProps.row.getIsSelected() === nextProps.row.getIsSelected()
|
|
731
|
+
})
|
|
732
|
+
|
|
733
|
+
TableRow.displayName = 'TableRow'
|
|
734
|
+
|
|
627
735
|
// Re-export types for convenience
|
|
628
736
|
export { type ColumnDef } from "@tanstack/react-table";
|
|
737
|
+
export type { BulkAction } from './data-table-bulk-actions';
|
|
738
|
+
export type { ExportFormat } from './data-table-export';
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
|
|
5
|
+
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
import { buttonVariants } from "./button"
|
|
8
|
+
|
|
9
|
+
const AlertDialog = AlertDialogPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
|
12
|
+
|
|
13
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
|
14
|
+
|
|
15
|
+
const AlertDialogOverlay = React.forwardRef<
|
|
16
|
+
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
|
17
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
|
18
|
+
>(({ className, ...props }, ref) => (
|
|
19
|
+
<AlertDialogPrimitive.Overlay
|
|
20
|
+
className={cn(
|
|
21
|
+
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
22
|
+
className
|
|
23
|
+
)}
|
|
24
|
+
{...props}
|
|
25
|
+
ref={ref}
|
|
26
|
+
/>
|
|
27
|
+
))
|
|
28
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
|
29
|
+
|
|
30
|
+
const AlertDialogContent = React.forwardRef<
|
|
31
|
+
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
32
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
|
33
|
+
>(({ className, ...props }, ref) => (
|
|
34
|
+
<AlertDialogPortal>
|
|
35
|
+
<AlertDialogOverlay />
|
|
36
|
+
<AlertDialogPrimitive.Content
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
</AlertDialogPortal>
|
|
45
|
+
))
|
|
46
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
|
47
|
+
|
|
48
|
+
const AlertDialogHeader = ({
|
|
49
|
+
className,
|
|
50
|
+
...props
|
|
51
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
52
|
+
<div
|
|
53
|
+
className={cn(
|
|
54
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
55
|
+
className
|
|
56
|
+
)}
|
|
57
|
+
{...props}
|
|
58
|
+
/>
|
|
59
|
+
)
|
|
60
|
+
AlertDialogHeader.displayName = "AlertDialogHeader"
|
|
61
|
+
|
|
62
|
+
const AlertDialogFooter = ({
|
|
63
|
+
className,
|
|
64
|
+
...props
|
|
65
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
66
|
+
<div
|
|
67
|
+
className={cn(
|
|
68
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
69
|
+
className
|
|
70
|
+
)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
)
|
|
74
|
+
AlertDialogFooter.displayName = "AlertDialogFooter"
|
|
75
|
+
|
|
76
|
+
const AlertDialogTitle = React.forwardRef<
|
|
77
|
+
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
|
78
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
|
79
|
+
>(({ className, ...props }, ref) => (
|
|
80
|
+
<AlertDialogPrimitive.Title
|
|
81
|
+
ref={ref}
|
|
82
|
+
className={cn("text-lg font-semibold", className)}
|
|
83
|
+
{...props}
|
|
84
|
+
/>
|
|
85
|
+
))
|
|
86
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
|
87
|
+
|
|
88
|
+
const AlertDialogDescription = React.forwardRef<
|
|
89
|
+
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
|
90
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
|
91
|
+
>(({ className, ...props }, ref) => (
|
|
92
|
+
<AlertDialogPrimitive.Description
|
|
93
|
+
ref={ref}
|
|
94
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
95
|
+
{...props}
|
|
96
|
+
/>
|
|
97
|
+
))
|
|
98
|
+
AlertDialogDescription.displayName =
|
|
99
|
+
AlertDialogPrimitive.Description.displayName
|
|
100
|
+
|
|
101
|
+
const AlertDialogAction = React.forwardRef<
|
|
102
|
+
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
|
103
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
|
104
|
+
>(({ className, ...props }, ref) => (
|
|
105
|
+
<AlertDialogPrimitive.Action
|
|
106
|
+
ref={ref}
|
|
107
|
+
className={cn(buttonVariants(), className)}
|
|
108
|
+
{...props}
|
|
109
|
+
/>
|
|
110
|
+
))
|
|
111
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
|
112
|
+
|
|
113
|
+
const AlertDialogCancel = React.forwardRef<
|
|
114
|
+
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
|
115
|
+
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
|
116
|
+
>(({ className, ...props }, ref) => (
|
|
117
|
+
<AlertDialogPrimitive.Cancel
|
|
118
|
+
ref={ref}
|
|
119
|
+
className={cn(
|
|
120
|
+
buttonVariants({ variant: "outline" }),
|
|
121
|
+
"mt-2 sm:mt-0",
|
|
122
|
+
className
|
|
123
|
+
)}
|
|
124
|
+
{...props}
|
|
125
|
+
/>
|
|
126
|
+
))
|
|
127
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
AlertDialog,
|
|
131
|
+
AlertDialogPortal,
|
|
132
|
+
AlertDialogOverlay,
|
|
133
|
+
AlertDialogTrigger,
|
|
134
|
+
AlertDialogContent,
|
|
135
|
+
AlertDialogHeader,
|
|
136
|
+
AlertDialogFooter,
|
|
137
|
+
AlertDialogTitle,
|
|
138
|
+
AlertDialogDescription,
|
|
139
|
+
AlertDialogAction,
|
|
140
|
+
AlertDialogCancel,
|
|
141
|
+
}
|