{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"table","type":"registry:ui","title":"table","description":"Table views are used to display data in a tabular format. They are useful for displaying large amounts of data in a structured way.","author":"Hayden Bleasel <hello@haydenbleasel.com>","dependencies":["@tanstack/react-table","jotai","lucide-react"],"devDependencies":[],"registryDependencies":["button","dropdown-menu","table"],"files":[{"type":"registry:ui","path":"index.tsx","content":"import type {\n  Cell,\n  Column,\n  ColumnDef,\n  Header,\n  HeaderGroup,\n  Row,\n  SortingState,\n  Table,\n} from \"@tanstack/react-table\";\nimport {\n  flexRender,\n  getCoreRowModel,\n  getSortedRowModel,\n  useReactTable,\n} from \"@tanstack/react-table\";\nimport { atom, useAtom } from \"jotai\";\nimport { ArrowDownIcon, ArrowUpIcon, ChevronsUpDownIcon } from \"lucide-react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { createContext, memo, useCallback, useContext } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\";\nimport {\n  TableBody as TableBodyRaw,\n  TableCell as TableCellRaw,\n  TableHeader as TableHeaderRaw,\n  TableHead as TableHeadRaw,\n  Table as TableRaw,\n  TableRow as TableRowRaw,\n} from \"@/components/ui/table\";\nimport { cn } from \"@/lib/utils\";\n\nexport type { ColumnDef } from \"@tanstack/react-table\";\n\nconst sortingAtom = atom<SortingState>([]);\n\nexport const TableContext = createContext<{\n  data: unknown[];\n  columns: ColumnDef<unknown, unknown>[];\n  table: Table<unknown> | null;\n}>({\n  data: [],\n  columns: [],\n  table: null,\n});\n\nexport type TableProviderProps<TData, TValue> = {\n  columns: ColumnDef<TData, TValue>[];\n  data: TData[];\n  children: ReactNode;\n  className?: string;\n};\n\nexport function TableProvider<TData, TValue>({\n  columns,\n  data,\n  children,\n  className,\n}: TableProviderProps<TData, TValue>) {\n  const [sorting, setSorting] = useAtom(sortingAtom);\n  const table = useReactTable({\n    data,\n    columns,\n    getCoreRowModel: getCoreRowModel(),\n    getSortedRowModel: getSortedRowModel(),\n    onSortingChange: (updater) => {\n      // @ts-expect-error updater is a function that returns a sorting object\n      const newSorting = updater(sorting);\n\n      setSorting(newSorting);\n    },\n    state: {\n      sorting,\n    },\n  });\n\n  return (\n    <TableContext.Provider\n      value={{\n        data,\n        columns: columns as never,\n        table: table as never,\n      }}\n    >\n      <TableRaw className={className}>{children}</TableRaw>\n    </TableContext.Provider>\n  );\n}\n\nexport type TableHeadProps = {\n  header: Header<unknown, unknown>;\n  className?: string;\n};\n\nexport const TableHead = memo(({ header, className }: TableHeadProps) => (\n  <TableHeadRaw className={className} key={header.id}>\n    {header.isPlaceholder\n      ? null\n      : flexRender(header.column.columnDef.header, header.getContext())}\n  </TableHeadRaw>\n));\n\nTableHead.displayName = \"TableHead\";\n\nexport type TableHeaderGroupProps = {\n  headerGroup: HeaderGroup<unknown>;\n  children: (props: { header: Header<unknown, unknown> }) => ReactNode;\n};\n\nexport const TableHeaderGroup = ({\n  headerGroup,\n  children,\n}: TableHeaderGroupProps) => (\n  <TableRowRaw key={headerGroup.id}>\n    {headerGroup.headers.map((header) => children({ header }))}\n  </TableRowRaw>\n);\n\nexport type TableHeaderProps = {\n  className?: string;\n  children: (props: { headerGroup: HeaderGroup<unknown> }) => ReactNode;\n};\n\nexport const TableHeader = ({ className, children }: TableHeaderProps) => {\n  const { table } = useContext(TableContext);\n\n  return (\n    <TableHeaderRaw className={className}>\n      {table?.getHeaderGroups().map((headerGroup) => children({ headerGroup }))}\n    </TableHeaderRaw>\n  );\n};\n\nexport interface TableColumnHeaderProps<TData, TValue>\n  extends HTMLAttributes<HTMLDivElement> {\n  column: Column<TData, TValue>;\n  title: string;\n}\n\nexport function TableColumnHeader<TData, TValue>({\n  column,\n  title,\n  className,\n}: TableColumnHeaderProps<TData, TValue>) {\n  // Extract inline event handlers to prevent unnecessary re-renders\n  const handleSortAsc = useCallback(() => {\n    column.toggleSorting(false);\n  }, [column]);\n\n  const handleSortDesc = useCallback(() => {\n    column.toggleSorting(true);\n  }, [column]);\n\n  if (!column.getCanSort()) {\n    return <div className={cn(className)}>{title}</div>;\n  }\n\n  return (\n    <div className={cn(\"flex items-center space-x-2\", className)}>\n      <DropdownMenu>\n        <DropdownMenuTrigger asChild>\n          <Button\n            className=\"-ml-3 h-8 data-[state=open]:bg-accent\"\n            size=\"sm\"\n            variant=\"ghost\"\n          >\n            <span>{title}</span>\n            {column.getIsSorted() === \"desc\" ? (\n              <ArrowDownIcon className=\"ml-2 h-4 w-4\" />\n            ) : column.getIsSorted() === \"asc\" ? (\n              <ArrowUpIcon className=\"ml-2 h-4 w-4\" />\n            ) : (\n              <ChevronsUpDownIcon className=\"ml-2 h-4 w-4\" />\n            )}\n          </Button>\n        </DropdownMenuTrigger>\n        <DropdownMenuContent align=\"start\">\n          <DropdownMenuItem onClick={handleSortAsc}>\n            <ArrowUpIcon className=\"mr-2 h-3.5 w-3.5 text-muted-foreground/70\" />\n            Asc\n          </DropdownMenuItem>\n          <DropdownMenuItem onClick={handleSortDesc}>\n            <ArrowDownIcon className=\"mr-2 h-3.5 w-3.5 text-muted-foreground/70\" />\n            Desc\n          </DropdownMenuItem>\n        </DropdownMenuContent>\n      </DropdownMenu>\n    </div>\n  );\n}\n\nexport type TableCellProps = {\n  cell: Cell<unknown, unknown>;\n  className?: string;\n};\n\nexport const TableCell = ({ cell, className }: TableCellProps) => (\n  <TableCellRaw className={className}>\n    {flexRender(cell.column.columnDef.cell, cell.getContext())}\n  </TableCellRaw>\n);\n\nexport type TableRowProps = {\n  row: Row<unknown>;\n  children: (props: { cell: Cell<unknown, unknown> }) => ReactNode;\n  className?: string;\n};\n\nexport const TableRow = ({ row, children, className }: TableRowProps) => (\n  <TableRowRaw\n    className={className}\n    data-state={row.getIsSelected() && \"selected\"}\n    key={row.id}\n  >\n    {row.getVisibleCells().map((cell) => children({ cell }))}\n  </TableRowRaw>\n);\n\nexport type TableBodyProps = {\n  children: (props: { row: Row<unknown> }) => ReactNode;\n  className?: string;\n};\n\nexport const TableBody = ({ children, className }: TableBodyProps) => {\n  const { columns, table } = useContext(TableContext);\n  const rows = table?.getRowModel().rows;\n\n  return (\n    <TableBodyRaw className={className}>\n      {rows?.length ? (\n        rows.map((row) => children({ row }))\n      ) : (\n        <TableRowRaw>\n          <TableCellRaw className=\"h-24 text-center\" colSpan={columns.length}>\n            No results.\n          </TableCellRaw>\n        </TableRowRaw>\n      )}\n    </TableBodyRaw>\n  );\n};\n","target":"components/kibo-ui/table/index.tsx"}],"css":{}}