{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "density-export-table",
  "title": "Density & Export",
  "description": "Compact/comfortable/spacious density toggle, CSV/Excel export, and a print-optimized PDF view via window.print().",
  "dependencies": [
    "@tanstack/react-table"
  ],
  "registryDependencies": [
    "table",
    "button",
    "select"
  ],
  "files": [
    {
      "path": "src/components/utility/columns.tsx",
      "content": "'use client'\n\nimport type { ColumnDef } from '@tanstack/react-table'\n\nexport type Employee = {\n  id: string\n  name: string\n  email: string\n  role: string\n  status: string\n}\n\nexport const columns: ColumnDef<Employee>[] = [\n  { accessorKey: 'name', header: 'Name' },\n  { accessorKey: 'email', header: 'Email' },\n  { accessorKey: 'role', header: 'Role' },\n  { accessorKey: 'status', header: 'Status' },\n]\n",
      "type": "registry:component",
      "target": "@components/tables/density-export-table/columns.tsx"
    },
    {
      "path": "src/components/utility/export.ts",
      "content": "export function toCsv(headers: string[], rows: string[][]): string {\n  const escape = (value: string) =>\n    /[\",\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value\n\n  return [headers, ...rows]\n    .map((row) => row.map(escape).join(','))\n    .join('\\n')\n}\n\nexport function toExcelHtml(headers: string[], rows: string[][]): string {\n  const th = headers.map((h) => `<th>${h}</th>`).join('')\n  const trs = rows\n    .map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join('')}</tr>`)\n    .join('')\n\n  return `<table><thead><tr>${th}</tr></thead><tbody>${trs}</tbody></table>`\n}\n\nexport function downloadFile(content: string, filename: string, mimeType: string) {\n  const blob = new Blob([content], { type: mimeType })\n  const url = URL.createObjectURL(blob)\n  const link = document.createElement('a')\n  link.href = url\n  link.download = filename\n  link.click()\n  URL.revokeObjectURL(url)\n}\n",
      "type": "registry:component",
      "target": "@components/tables/density-export-table/export.ts"
    },
    {
      "path": "src/components/utility/data-table.tsx",
      "content": "'use client'\n\nimport { useState } from 'react'\nimport {\n  flexRender,\n  getCoreRowModel,\n  useReactTable,\n} from '@tanstack/react-table'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { FileSpreadsheet, FileText, Printer } from 'lucide-react'\n\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '#/components/ui/table'\nimport { Button } from '#/components/ui/button'\nimport {\n  Select,\n  SelectContent,\n  SelectItem,\n  SelectTrigger,\n  SelectValue,\n} from '#/components/ui/select'\nimport { cn } from '#/lib/utils.ts'\nimport { downloadFile, toCsv, toExcelHtml } from './export'\n\ntype Density = 'compact' | 'comfortable' | 'spacious'\n\nconst densityCell: Record<Density, string> = {\n  compact: 'py-1 text-xs',\n  comfortable: 'py-2 text-sm',\n  spacious: 'py-4 text-base',\n}\n\nconst densityHead: Record<Density, string> = {\n  compact: 'h-8 text-xs',\n  comfortable: 'h-10 text-sm',\n  spacious: 'h-14 text-base',\n}\n\ninterface UtilityTableProps<TData> {\n  columns: ColumnDef<TData, any>[]\n  data: TData[]\n}\n\nexport function UtilityTable<TData>({ columns, data }: UtilityTableProps<TData>) {\n  const [density, setDensity] = useState<Density>('comfortable')\n\n  const table = useReactTable({\n    data,\n    columns,\n    getCoreRowModel: getCoreRowModel(),\n  })\n\n  function getExportData() {\n    const headers = table.getHeaderGroups()[0].headers.map((header) =>\n      typeof header.column.columnDef.header === 'string'\n        ? header.column.columnDef.header\n        : header.column.id,\n    )\n    const rows = table\n      .getRowModel()\n      .rows.map((row) =>\n        row.getVisibleCells().map((cell) => String(cell.getValue() ?? '')),\n      )\n    return { headers, rows }\n  }\n\n  function exportCsv() {\n    const { headers, rows } = getExportData()\n    downloadFile(toCsv(headers, rows), 'table-export.csv', 'text/csv;charset=utf-8;')\n  }\n\n  function exportExcel() {\n    const { headers, rows } = getExportData()\n    downloadFile(\n      toExcelHtml(headers, rows),\n      'table-export.xls',\n      'application/vnd.ms-excel',\n    )\n  }\n\n  function exportPdf() {\n    window.print()\n  }\n\n  return (\n    <div>\n      <div className=\"mb-3 flex flex-wrap items-center justify-between gap-3 print:hidden\">\n        <div className=\"flex items-center gap-2\">\n          <span className=\"text-sm text-muted-foreground\">Density</span>\n          <Select value={density} onValueChange={(v) => setDensity(v as Density)}>\n            <SelectTrigger className=\"w-36\">\n              <SelectValue />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem value=\"compact\">Compact</SelectItem>\n              <SelectItem value=\"comfortable\">Comfortable</SelectItem>\n              <SelectItem value=\"spacious\">Spacious</SelectItem>\n            </SelectContent>\n          </Select>\n        </div>\n        <div className=\"flex items-center gap-2\">\n          <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={exportCsv}>\n            <FileText className=\"h-3.5 w-3.5\" />\n            CSV\n          </Button>\n          <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={exportExcel}>\n            <FileSpreadsheet className=\"h-3.5 w-3.5\" />\n            Excel\n          </Button>\n          <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={exportPdf}>\n            <Printer className=\"h-3.5 w-3.5\" />\n            PDF\n          </Button>\n        </div>\n      </div>\n\n      <div className=\"overflow-hidden rounded-md border print:border-black print:shadow-none\">\n        <Table className=\"print:bg-white print:text-black\">\n          <TableHeader>\n            {table.getHeaderGroups().map((headerGroup) => (\n              <TableRow key={headerGroup.id} className=\"print:border-black\">\n                {headerGroup.headers.map((header) => (\n                  <TableHead\n                    key={header.id}\n                    className={cn(\n                      densityHead[density],\n                      'print:h-auto print:py-2 print:text-black',\n                    )}\n                  >\n                    {header.isPlaceholder\n                      ? null\n                      : flexRender(\n                          header.column.columnDef.header,\n                          header.getContext(),\n                        )}\n                  </TableHead>\n                ))}\n              </TableRow>\n            ))}\n          </TableHeader>\n          <TableBody>\n            {table.getRowModel().rows.map((row) => (\n              <TableRow key={row.id} className=\"print:border-black\">\n                {row.getVisibleCells().map((cell) => (\n                  <TableCell\n                    key={cell.id}\n                    className={cn(\n                      densityCell[density],\n                      'print:py-1 print:text-black',\n                    )}\n                  >\n                    {flexRender(\n                      cell.column.columnDef.cell,\n                      cell.getContext(),\n                    )}\n                  </TableCell>\n                ))}\n              </TableRow>\n            ))}\n          </TableBody>\n        </Table>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/tables/density-export-table/data-table.tsx"
    },
    {
      "path": "src/components/utility/index.tsx",
      "content": "import { columns } from './columns'\nimport type { Employee } from './columns'\nimport { UtilityTable } from './data-table'\n\nconst data: Employee[] = [\n  { id: '1', name: 'Ava Thompson', email: 'ava.t@example.com', role: 'Admin', status: 'Active' },\n  { id: '2', name: 'Liam Chen', email: 'liam.chen@example.com', role: 'Editor', status: 'Active' },\n  { id: '3', name: 'Sofia Patel', email: 'sofia.p@example.com', role: 'Viewer', status: 'Inactive' },\n  { id: '4', name: 'Noah Garcia', email: 'noah.g@example.com', role: 'Editor', status: 'Active' },\n  { id: '5', name: 'Mia Johnson', email: 'mia.j@example.com', role: 'Admin', status: 'Pending' },\n  { id: '6', name: 'Ethan Kim', email: 'ethan.kim@example.com', role: 'Viewer', status: 'Active' },\n]\n\nexport function UtilityTableDemo() {\n  return <UtilityTable columns={columns} data={data} />\n}\n",
      "type": "registry:component",
      "target": "@components/tables/density-export-table/index.tsx"
    }
  ],
  "type": "registry:block"
}