{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "grouped-table",
  "title": "Grouped Table",
  "description": "Rows grouped by a column value with collapsible group headers and live subtotals via aggregationFn.",
  "dependencies": [
    "@tanstack/react-table"
  ],
  "registryDependencies": [
    "table"
  ],
  "files": [
    {
      "path": "src/components/grouped/columns.tsx",
      "content": "'use client'\n\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ChevronRight } from 'lucide-react'\n\nexport type Order = {\n  id: string\n  customer: string\n  category: string\n  amount: number\n  status: string\n}\n\nconst currency = (value: number) =>\n  value.toLocaleString('en-US', { style: 'currency', currency: 'USD' })\n\nexport const columns: ColumnDef<Order>[] = [\n  {\n    accessorKey: 'category',\n    header: 'Category',\n    cell: ({ row, cell, getValue }) => {\n      if (cell.getIsGrouped()) {\n        return (\n          <button\n            type=\"button\"\n            onClick={row.getToggleExpandedHandler()}\n            className=\"flex items-center gap-1.5 font-medium\"\n          >\n            <ChevronRight\n              className={`h-3.5 w-3.5 transition-transform ${\n                row.getIsExpanded() ? 'rotate-90' : ''\n              }`}\n            />\n            {getValue() as string}\n            <span className=\"font-normal text-muted-foreground\">\n              ({row.subRows.length})\n            </span>\n          </button>\n        )\n      }\n      if (cell.getIsPlaceholder()) return null\n      return <span className=\"pl-5\">{getValue() as string}</span>\n    },\n  },\n  {\n    accessorKey: 'customer',\n    header: 'Customer',\n    cell: ({ cell, getValue }) =>\n      cell.getIsAggregated() ? null : (getValue() as string),\n  },\n  {\n    accessorKey: 'status',\n    header: 'Status',\n    cell: ({ cell, getValue }) =>\n      cell.getIsAggregated() ? null : (getValue() as string),\n  },\n  {\n    accessorKey: 'amount',\n    header: 'Amount',\n    aggregationFn: 'sum',\n    cell: ({ cell, getValue }) => (\n      <span className={cell.getIsAggregated() ? 'font-medium' : undefined}>\n        {currency(getValue() as number)}\n      </span>\n    ),\n  },\n]\n",
      "type": "registry:component",
      "target": "@components/tables/grouped-table/columns.tsx"
    },
    {
      "path": "src/components/grouped/data-table.tsx",
      "content": "'use client'\n\nimport {\n  flexRender,\n  getCoreRowModel,\n  getExpandedRowModel,\n  getGroupedRowModel,\n  useReactTable,\n} from '@tanstack/react-table'\n\nimport type {\n  ColumnDef,\n  ExpandedState,\n  GroupingState,\n} from '@tanstack/react-table'\n\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '#/components/ui/table'\nimport { useState } from 'react'\nimport { cn } from '#/lib/utils.ts'\n\ninterface GroupedDataTableProps<TData> {\n  columns: ColumnDef<TData, any>[]\n  data: TData[]\n  groupBy: string\n}\n\nexport function GroupedDataTable<TData>({\n  columns,\n  data,\n  groupBy,\n}: GroupedDataTableProps<TData>) {\n  const [grouping, setGrouping] = useState<GroupingState>([groupBy])\n  const [expanded, setExpanded] = useState<ExpandedState>(true)\n\n  const table = useReactTable({\n    data,\n    columns,\n    getCoreRowModel: getCoreRowModel(),\n    getGroupedRowModel: getGroupedRowModel(),\n    getExpandedRowModel: getExpandedRowModel(),\n    onGroupingChange: setGrouping,\n    onExpandedChange: setExpanded,\n    state: {\n      grouping,\n      expanded,\n    },\n  })\n\n  return (\n    <div className=\"overflow-hidden rounded-md border\">\n      <Table>\n        <TableHeader>\n          {table.getHeaderGroups().map((headerGroup) => (\n            <TableRow key={headerGroup.id}>\n              {headerGroup.headers.map((header) => (\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            </TableRow>\n          ))}\n        </TableHeader>\n        <TableBody>\n          {table.getRowModel().rows.length ? (\n            table.getRowModel().rows.map((row) => (\n              <TableRow\n                key={row.id}\n                className={cn(row.getIsGrouped() && 'bg-muted/50')}\n              >\n                {row.getVisibleCells().map((cell) => (\n                  <TableCell key={cell.id}>\n                    {flexRender(cell.column.columnDef.cell, cell.getContext())}\n                  </TableCell>\n                ))}\n              </TableRow>\n            ))\n          ) : (\n            <TableRow>\n              <TableCell colSpan={columns.length} className=\"h-24 text-center\">\n                No results.\n              </TableCell>\n            </TableRow>\n          )}\n        </TableBody>\n      </Table>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/tables/grouped-table/data-table.tsx"
    },
    {
      "path": "src/components/grouped/index.tsx",
      "content": "import { columns } from './columns'\nimport type { Order } from './columns'\nimport { GroupedDataTable } from './data-table'\n\nconst data: Order[] = [\n  { id: 'ord-1', customer: 'Ava Thompson', category: 'Electronics', amount: 249.99, status: 'Paid' },\n  { id: 'ord-2', customer: 'Liam Chen', category: 'Electronics', amount: 79.5, status: 'Paid' },\n  { id: 'ord-3', customer: 'Sofia Patel', category: 'Electronics', amount: 1099.0, status: 'Pending' },\n  { id: 'ord-4', customer: 'Noah Garcia', category: 'Clothing', amount: 45.0, status: 'Paid' },\n  { id: 'ord-5', customer: 'Mia Johnson', category: 'Clothing', amount: 120.75, status: 'Refunded' },\n  { id: 'ord-6', customer: 'Ethan Kim', category: 'Clothing', amount: 32.2, status: 'Paid' },\n  { id: 'ord-7', customer: 'Isabella Rossi', category: 'Clothing', amount: 58.0, status: 'Pending' },\n  { id: 'ord-8', customer: 'Lucas Martin', category: 'Home', amount: 310.4, status: 'Paid' },\n  { id: 'ord-9', customer: 'Amelia Novak', category: 'Home', amount: 89.99, status: 'Paid' },\n]\n\nexport function GroupedTableDemo() {\n  return <GroupedDataTable columns={columns} data={data} groupBy=\"category\" />\n}\n",
      "type": "registry:component",
      "target": "@components/tables/grouped-table/index.tsx"
    }
  ],
  "type": "registry:block"
}