{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-table",
  "type": "registry:ui",
  "description": "Powerful data table with sorting, filtering, pagination, and row selection",
  "dependencies": [
    "@tanstack/react-table",
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "button",
    "checkbox",
    "dropdown-menu",
    "input",
    "select",
    "table"
  ],
  "files": [
    {
      "path": "registry/default/ui/data-table.tsx",
      "content": "import * as React from 'react'\nimport {\n  flexRender,\n  getCoreRowModel,\n  getFilteredRowModel,\n  getPaginationRowModel,\n  getSortedRowModel,\n  useReactTable,\n  type ColumnDef,\n  type ColumnFiltersState,\n  type SortingState,\n  type VisibilityState,\n  type Table as TanstackTable,\n} from '@tanstack/react-table'\nimport { ArrowDown, ArrowUp, ArrowUpDown, ChevronDown, Search, Settings2 } from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Button } from '@/components/ui/button'\nimport { Checkbox } from '@/components/ui/checkbox'\nimport { Input } from '@/components/ui/input'\nimport {\n  DropdownMenu,\n  DropdownMenuCheckboxItem,\n  DropdownMenuContent,\n  DropdownMenuTrigger,\n} from '@/components/ui/dropdown-menu'\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from '@/components/ui/select'\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '@/components/ui/table'\n\n// DataTable Context\ninterface DataTableContextValue<TData> {\n  table: TanstackTable<TData>\n}\n\nconst DataTableContext = React.createContext<DataTableContextValue<unknown> | null>(null)\n\nfunction useDataTable<TData>() {\n  const context = React.useContext(DataTableContext) as DataTableContextValue<TData> | null\n  if (!context) {\n    throw new Error('DataTable components must be used within a <DataTable />')\n  }\n  return context\n}\n\n// Column Header with sorting\ninterface DataTableColumnHeaderProps<TData, TValue>\n  extends React.HTMLAttributes<HTMLDivElement> {\n  column: import('@tanstack/react-table').Column<TData, TValue>\n  title: string\n}\n\nfunction DataTableColumnHeader<TData, TValue>({\n  column,\n  title,\n  className,\n}: DataTableColumnHeaderProps<TData, TValue>) {\n  if (!column.getCanSort()) {\n    return <div className={cn(className)}>{title}</div>\n  }\n\n  return (\n    <Button\n      variant=\"ghost\"\n      size=\"sm\"\n      className={cn('-ml-3 h-8 data-[state=open]:bg-accent', className)}\n      onClick={() => column.toggleSorting(column.getIsSorted() === 'asc')}\n    >\n      <span>{title}</span>\n      {column.getIsSorted() === 'desc' ? (\n        <ArrowDown className=\"ml-2 h-4 w-4\" />\n      ) : column.getIsSorted() === 'asc' ? (\n        <ArrowUp className=\"ml-2 h-4 w-4\" />\n      ) : (\n        <ArrowUpDown className=\"ml-2 h-4 w-4\" />\n      )}\n    </Button>\n  )\n}\n\n// Toolbar\ninterface DataTableToolbarProps<TData> {\n  table: TanstackTable<TData>\n  filterPlaceholder?: string\n  filterColumn?: string\n  showColumnVisibility?: boolean\n}\n\nfunction DataTableToolbar<TData>({\n  table,\n  filterPlaceholder = 'Filter...',\n  filterColumn,\n  showColumnVisibility = true,\n}: DataTableToolbarProps<TData>) {\n  const column = filterColumn ? table.getColumn(filterColumn) : null\n\n  return (\n    <div className=\"flex items-center justify-between py-4\">\n      <div className=\"flex flex-1 items-center space-x-2\">\n        {column && (\n          <div className=\"relative\">\n            <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\" />\n            <Input\n              placeholder={filterPlaceholder}\n              value={(column.getFilterValue() as string) ?? ''}\n              onChange={(event) => column.setFilterValue(event.target.value)}\n              className=\"h-9 w-[150px] pl-9 lg:w-[250px]\"\n            />\n          </div>\n        )}\n      </div>\n      {showColumnVisibility && (\n        <DropdownMenu>\n          <DropdownMenuTrigger asChild>\n            <Button variant=\"outline\" size=\"sm\" className=\"ml-auto h-9\">\n              <Settings2 className=\"mr-2 h-4 w-4\" />\n              Columns\n              <ChevronDown className=\"ml-2 h-4 w-4\" />\n            </Button>\n          </DropdownMenuTrigger>\n          <DropdownMenuContent align=\"end\">\n            {table\n              .getAllColumns()\n              .filter((column) => column.getCanHide())\n              .map((column) => {\n                return (\n                  <DropdownMenuCheckboxItem\n                    key={column.id}\n                    className=\"capitalize\"\n                    checked={column.getIsVisible()}\n                    onCheckedChange={(value) => column.toggleVisibility(!!value)}\n                  >\n                    {column.id}\n                  </DropdownMenuCheckboxItem>\n                )\n              })}\n          </DropdownMenuContent>\n        </DropdownMenu>\n      )}\n    </div>\n  )\n}\n\n// Pagination\ninterface DataTablePaginationProps<TData> {\n  table: TanstackTable<TData>\n  pageSizeOptions?: number[]\n}\n\nfunction DataTablePagination<TData>({\n  table,\n  pageSizeOptions = [10, 20, 30, 50],\n}: DataTablePaginationProps<TData>) {\n  return (\n    <div className=\"flex items-center justify-between py-4\">\n      <div className=\"flex-1 text-sm text-muted-foreground\">\n        {table.getFilteredSelectedRowModel().rows.length > 0 && (\n          <>\n            {table.getFilteredSelectedRowModel().rows.length} of{' '}\n            {table.getFilteredRowModel().rows.length} row(s) selected.\n          </>\n        )}\n      </div>\n      <div className=\"flex items-center space-x-6 lg:space-x-8\">\n        <div className=\"flex items-center space-x-2\">\n          <p className=\"text-sm font-medium\">Rows per page</p>\n          <Select\n            value={`${table.getState().pagination.pageSize}`}\n            onValueChange={(value) => {\n              table.setPageSize(Number(value))\n            }}\n          >\n            <SelectTrigger className=\"h-9 w-[85px]\">\n              <SelectValue placeholder={table.getState().pagination.pageSize} />\n            </SelectTrigger>\n            <SelectContent side=\"top\">\n              {pageSizeOptions.map((pageSize) => (\n                <SelectItem key={pageSize} value={`${pageSize}`}>\n                  {pageSize}\n                </SelectItem>\n              ))}\n            </SelectContent>\n          </Select>\n        </div>\n        <div className=\"flex w-[100px] items-center justify-center text-sm font-medium\">\n          Page {table.getState().pagination.pageIndex + 1} of{' '}\n          {table.getPageCount()}\n        </div>\n        <div className=\"flex items-center space-x-2\">\n          <Button\n            variant=\"outline\"\n            size=\"sm\"\n            onClick={() => table.previousPage()}\n            disabled={!table.getCanPreviousPage()}\n          >\n            Previous\n          </Button>\n          <Button\n            variant=\"outline\"\n            size=\"sm\"\n            onClick={() => table.nextPage()}\n            disabled={!table.getCanNextPage()}\n          >\n            Next\n          </Button>\n        </div>\n      </div>\n    </div>\n  )\n}\n\n// Main DataTable component\nexport interface DataTableProps<TData, TValue> {\n  columns: ColumnDef<TData, TValue>[]\n  data: TData[]\n\n  // Features\n  enableSorting?: boolean\n  enableFiltering?: boolean\n  enableColumnVisibility?: boolean\n  enableRowSelection?: boolean\n  enablePagination?: boolean\n\n  // Pagination\n  pageSize?: number\n  pageSizeOptions?: number[]\n\n  // Search\n  filterColumn?: string\n  filterPlaceholder?: string\n\n  // Empty/Loading\n  emptyMessage?: string\n  isLoading?: boolean\n\n  // Callbacks\n  onRowSelectionChange?: (selectedRows: TData[]) => void\n}\n\nfunction DataTable<TData, TValue>({\n  columns,\n  data,\n  enableSorting = true,\n  enableFiltering = true,\n  enableColumnVisibility = true,\n  enableRowSelection = false,\n  enablePagination = true,\n  pageSize = 10,\n  pageSizeOptions = [10, 20, 30, 50],\n  filterColumn,\n  filterPlaceholder = 'Filter...',\n  emptyMessage = 'No results.',\n  isLoading = false,\n  onRowSelectionChange,\n}: DataTableProps<TData, TValue>) {\n  const [sorting, setSorting] = React.useState<SortingState>([])\n  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>([])\n  const [columnVisibility, setColumnVisibility] = React.useState<VisibilityState>({})\n  const [rowSelection, setRowSelection] = React.useState({})\n\n  // Add selection column if row selection is enabled\n  const tableColumns = React.useMemo(() => {\n    if (!enableRowSelection) return columns\n\n    const selectionColumn: ColumnDef<TData, unknown> = {\n      id: 'select',\n      header: ({ table }) => (\n        <Checkbox\n          checked={\n            table.getIsAllPageRowsSelected() ||\n            (table.getIsSomePageRowsSelected() && 'indeterminate')\n          }\n          onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}\n          aria-label=\"Select all\"\n        />\n      ),\n      cell: ({ row }) => (\n        <Checkbox\n          checked={row.getIsSelected()}\n          onCheckedChange={(value) => row.toggleSelected(!!value)}\n          aria-label=\"Select row\"\n        />\n      ),\n      enableSorting: false,\n      enableHiding: false,\n    }\n\n    return [selectionColumn, ...columns]\n  }, [columns, enableRowSelection])\n\n  const table = useReactTable({\n    data,\n    columns: tableColumns,\n    onSortingChange: setSorting,\n    onColumnFiltersChange: setColumnFilters,\n    getCoreRowModel: getCoreRowModel(),\n    ...(enablePagination && { getPaginationRowModel: getPaginationRowModel() }),\n    ...(enableSorting && { getSortedRowModel: getSortedRowModel() }),\n    ...(enableFiltering && { getFilteredRowModel: getFilteredRowModel() }),\n    onColumnVisibilityChange: setColumnVisibility,\n    onRowSelectionChange: setRowSelection,\n    state: {\n      sorting,\n      columnFilters,\n      columnVisibility,\n      rowSelection,\n    },\n    initialState: {\n      pagination: {\n        pageSize,\n      },\n    },\n  })\n\n  // Notify parent of selection changes\n  React.useEffect(() => {\n    if (onRowSelectionChange) {\n      const selectedRows = table.getFilteredSelectedRowModel().rows.map((row) => row.original)\n      onRowSelectionChange(selectedRows)\n    }\n  }, [rowSelection, table, onRowSelectionChange])\n\n  return (\n    <DataTableContext.Provider value={{ table: table as TanstackTable<unknown> }}>\n      <div className=\"space-y-4\">\n        {/* Toolbar */}\n        {(enableFiltering || enableColumnVisibility) && (\n          <DataTableToolbar\n            table={table}\n            filterPlaceholder={filterPlaceholder}\n            filterColumn={filterColumn}\n            showColumnVisibility={enableColumnVisibility}\n          />\n        )}\n\n        {/* Table */}\n        <Table>\n          <TableHeader>\n            {table.getHeaderGroups().map((headerGroup) => (\n              <TableRow key={headerGroup.id}>\n                {headerGroup.headers.map((header) => {\n                  return (\n                    <TableHead key={header.id}>\n                      {header.isPlaceholder\n                        ? null\n                        : flexRender(\n                            header.column.columnDef.header,\n                            header.getContext()\n                          )}\n                    </TableHead>\n                  )\n                })}\n              </TableRow>\n            ))}\n          </TableHeader>\n          <TableBody>\n            {isLoading ? (\n              <TableRow>\n                <TableCell\n                  colSpan={tableColumns.length}\n                  className=\"h-24 text-center\"\n                >\n                  <div className=\"flex items-center justify-center\">\n                    <div className=\"h-6 w-6 animate-spin border-3 border-foreground border-t-transparent\" />\n                  </div>\n                </TableCell>\n              </TableRow>\n            ) : table.getRowModel().rows?.length ? (\n              table.getRowModel().rows.map((row) => (\n                <TableRow\n                  key={row.id}\n                  data-state={row.getIsSelected() && 'selected'}\n                >\n                  {row.getVisibleCells().map((cell) => (\n                    <TableCell key={cell.id}>\n                      {flexRender(\n                        cell.column.columnDef.cell,\n                        cell.getContext()\n                      )}\n                    </TableCell>\n                  ))}\n                </TableRow>\n              ))\n            ) : (\n              <TableRow>\n                <TableCell\n                  colSpan={tableColumns.length}\n                  className=\"h-24 text-center\"\n                >\n                  {emptyMessage}\n                </TableCell>\n              </TableRow>\n            )}\n          </TableBody>\n        </Table>\n\n        {/* Pagination */}\n        {enablePagination && (\n          <DataTablePagination table={table} pageSizeOptions={pageSizeOptions} />\n        )}\n      </div>\n    </DataTableContext.Provider>\n  )\n}\n\nexport {\n  DataTable,\n  DataTableColumnHeader,\n  DataTableToolbar,\n  DataTablePagination,\n  useDataTable,\n}\n",
      "type": "registry:ui",
      "target": "components/ui/data-table.tsx"
    }
  ]
}