"use client" import * as React from "react"; import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "../../lib/utils"; export type SortDirection = "asc" | "desc" | null; const tableVariants = cva( "w-full caption-bottom text-sm", { variants: { variant: { default: "dark:text-gray-200", bordered: "border border-border dark:border-gray-700", striped: "dark:text-gray-200", card: "border border-border dark:border-gray-700 rounded-md shadow-sm dark:shadow-gray-900/20", minimal: "border-none dark:text-gray-200", }, size: { sm: "text-xs", default: "text-sm", lg: "text-base", }, }, defaultVariants: { variant: "default", size: "default", }, } ); export interface ColumnDefinition { id: string; header: React.ReactNode; accessorKey?: keyof T; cell?: (row: T) => React.ReactNode; sortable?: boolean; } interface TableProps extends React.HTMLAttributes, VariantProps { /** Veri yükleniyor durumunu gösterir */ loading?: boolean; /** Sıralama için kullanılan sütun */ sortColumn?: string; /** Sıralama yönü */ sortDirection?: SortDirection; /** Sıralama değiştiğinde çağrılacak fonksiyon */ onSortChange?: (column: string, direction: SortDirection) => void; /** Boş durum için özel içerik */ emptyContent?: React.ReactNode; /** Seçili satır id'leri */ selectedRowIds?: string[]; /** Satır seçim değiştiğinde çağrılacak fonksiyon */ onRowSelectionChange?: (selectedRowIds: string[]) => void; /** Satır seçim devre dışı */ disableRowSelection?: boolean; /** Her satır için benzersiz id çıkarma fonksiyonu */ getRowId?: (row: T) => string; } // Tip parametresiz Table bileşeni için varsayılan tip, herhangi bir veri tipini kabul edebilmesi için const Table = React.forwardRef< HTMLTableElement, TableProps >(({ className, variant, size, loading, emptyContent, // Kullanılmayan özellikleri yoruma alarak lint uyarılarını önlüyoruz // sortColumn, // sortDirection, // onSortChange, // selectedRowIds, // onRowSelectionChange, // disableRowSelection, // getRowId, ...props }, ref) => { // Apply striped styles to the tbody via a class name const striped = variant === "striped"; // Çocukları güvenli bir şekilde işle ve tip kontrollerini doğru yap const childrenWithProps = React.Children.map(props.children, (child) => { if (React.isValidElement(child)) { if (child.type === "tbody") { // Tip güvenliği için props'ları düzgün şekilde ele alıyoruz const tbodyProps = child.props as Record; return React.cloneElement(child as React.ReactElement>, { className: cn(tbodyProps.className as string | undefined, striped && "even:[&>tr]:bg-muted/50") }); } } return child; }); return (
{/* Yükleniyor durumu için overlay */} {loading && (
)} {childrenWithProps}
); }); Table.displayName = "Table"; const TableHeader = React.forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( )); TableHeader.displayName = "TableHeader"; interface TableBodyProps extends React.HTMLAttributes { /** Veri yoksa gösterilecek boş durum içeriği */ emptyContent?: React.ReactNode; /** Varsayılan boş durum mesajı */ emptyMessage?: string; } const TableBody = React.forwardRef< HTMLTableSectionElement, TableBodyProps >(({ className, emptyContent, emptyMessage = "No data available", children, ...props }, ref) => { // Çocuk elementlerin varlığını kontrol et const hasChildren = React.Children.count(children) > 0; return ( {hasChildren ? ( children ) : ( {emptyContent || (
{emptyMessage}
)} )} ) }); TableBody.displayName = "TableBody"; const TableFooter = React.forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( )); TableFooter.displayName = "TableFooter"; const TableRow = React.forwardRef< HTMLTableRowElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( )); TableRow.displayName = "TableRow"; interface TableHeadProps extends React.ThHTMLAttributes { /** Bu sütun için sıralama durumu */ sortable?: boolean; /** Bu sütunun sıralanma durumu */ sorted?: SortDirection; /** Sıralama değiştiğinde çağrılacak fonksiyon */ onSort?: () => void; /** Text alignment */ align?: 'left' | 'center' | 'right'; } const TableHead = React.forwardRef( ({ className, sortable, sorted, onSort, align = 'left', children, ...props }, ref) => { // Sıralama için simgeler const renderSortIcon = () => { if (!sortable) return null; if (sorted === "asc") { return ( ); } if (sorted === "desc") { return ( ); } return ( ); }; const alignmentClasses = { left: 'text-left justify-start', center: 'text-center justify-center', right: 'text-right justify-end' }; return ( {sortable || align !== 'left' ? (
{children} {sortable && renderSortIcon()}
) : ( children )} ); } ); TableHead.displayName = "TableHead"; interface TableCellProps extends React.TdHTMLAttributes { /** Text alignment */ align?: 'left' | 'center' | 'right'; } const TableCell = React.forwardRef< HTMLTableCellElement, TableCellProps >(({ className, align = 'left', ...props }, ref) => { const alignmentClass = { left: 'text-left', center: 'text-center', right: 'text-right' }[align]; return ( ); }); TableCell.displayName = "TableCell"; const TableCaption = React.forwardRef< HTMLTableCaptionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( )); TableCaption.displayName = "TableCaption"; export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption, }; export type { TableBodyProps };