{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "master-detail-table",
  "title": "Master-Detail Table",
  "description": "Expand a row to reveal a nested sub-table detail panel, rendered as a full-width row beneath the row that owns it.",
  "dependencies": [
    "@tanstack/react-table"
  ],
  "registryDependencies": [
    "table"
  ],
  "files": [
    {
      "path": "src/components/master-detail/columns.tsx",
      "content": "'use client'\n\nimport type { ColumnDef } from '@tanstack/react-table'\n\nexport type OrderItem = {\n  product: string\n  qty: number\n  price: number\n}\n\nexport type Order = {\n  id: string\n  customer: string\n  date: string\n  status: string\n  total: number\n  shippingAddress: string\n  items: OrderItem[]\n}\n\nexport const currency = (value: number) =>\n  value.toLocaleString('en-US', { style: 'currency', currency: 'USD' })\n\nexport const columns: ColumnDef<Order>[] = [\n  {\n    accessorKey: 'id',\n    header: 'Order',\n  },\n  {\n    accessorKey: 'customer',\n    header: 'Customer',\n  },\n  {\n    accessorKey: 'date',\n    header: 'Date',\n  },\n  {\n    accessorKey: 'status',\n    header: 'Status',\n  },\n  {\n    accessorKey: 'total',\n    header: 'Total',\n    cell: ({ getValue }) => currency(getValue() as number),\n  },\n]\n",
      "type": "registry:component",
      "target": "@components/tables/master-detail-table/columns.tsx"
    },
    {
      "path": "src/components/master-detail/data-table.tsx",
      "content": "'use client'\n\nimport { Fragment, useMemo, useState } from 'react'\nimport {\n  flexRender,\n  getCoreRowModel,\n  useReactTable,\n} from '@tanstack/react-table'\nimport type { ColumnDef } from '@tanstack/react-table'\nimport { ChevronRight } from 'lucide-react'\n\nimport {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '#/components/ui/table'\nimport type { Order } from './columns'\nimport { OrderDetail } from './order-detail'\n\ninterface MasterDetailTableProps {\n  columns: ColumnDef<Order, any>[]\n  data: Order[]\n}\n\nexport function MasterDetailTable({ columns, data }: MasterDetailTableProps) {\n  const [expandedRows, setExpandedRows] = useState<Set<string>>(new Set())\n\n  function toggleRow(id: string) {\n    setExpandedRows((prev) => {\n      const next = new Set(prev)\n      if (next.has(id)) {\n        next.delete(id)\n      } else {\n        next.add(id)\n      }\n      return next\n    })\n  }\n\n  const allColumns = useMemo<ColumnDef<Order, any>[]>(\n    () => [\n      {\n        id: 'expander',\n        header: () => null,\n        cell: ({ row }) => {\n          const isExpanded = expandedRows.has(row.original.id)\n          return (\n            <button\n              type=\"button\"\n              onClick={() => toggleRow(row.original.id)}\n              className=\"flex h-4 w-4 items-center justify-center text-muted-foreground\"\n              aria-label={isExpanded ? 'Collapse row' : 'Expand row'}\n              aria-expanded={isExpanded}\n            >\n              <ChevronRight\n                className={`h-3.5 w-3.5 transition-transform ${\n                  isExpanded ? 'rotate-90' : ''\n                }`}\n              />\n            </button>\n          )\n        },\n      },\n      ...columns,\n    ],\n    [columns, expandedRows],\n  )\n\n  const table = useReactTable({\n    data,\n    columns: allColumns,\n    getCoreRowModel: getCoreRowModel(),\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              const isExpanded = expandedRows.has(row.original.id)\n              return (\n                <Fragment key={row.id}>\n                  <TableRow data-state={isExpanded ? 'expanded' : undefined}>\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                  {isExpanded ? (\n                    <TableRow>\n                      <TableCell\n                        colSpan={allColumns.length}\n                        className=\"bg-muted/30 p-4\"\n                      >\n                        <OrderDetail order={row.original} />\n                      </TableCell>\n                    </TableRow>\n                  ) : null}\n                </Fragment>\n              )\n            })\n          ) : (\n            <TableRow>\n              <TableCell\n                colSpan={allColumns.length}\n                className=\"h-24 text-center\"\n              >\n                No results.\n              </TableCell>\n            </TableRow>\n          )}\n        </TableBody>\n      </Table>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/tables/master-detail-table/data-table.tsx"
    },
    {
      "path": "src/components/master-detail/order-detail.tsx",
      "content": "import {\n  Table,\n  TableBody,\n  TableCell,\n  TableHead,\n  TableHeader,\n  TableRow,\n} from '#/components/ui/table'\nimport type { Order } from './columns'\nimport { currency } from './columns'\n\nexport function OrderDetail({ order }: { order: Order }) {\n  return (\n    <div className=\"grid gap-4 py-1 md:grid-cols-[minmax(0,200px)_1fr]\">\n      <div className=\"space-y-1 text-sm\">\n        <p className=\"font-medium text-foreground\">Shipping address</p>\n        <p className=\"text-muted-foreground\">{order.shippingAddress}</p>\n      </div>\n      <div className=\"overflow-hidden rounded-md border bg-background\">\n        <Table>\n          <TableHeader>\n            <TableRow>\n              <TableHead>Product</TableHead>\n              <TableHead>Qty</TableHead>\n              <TableHead>Price</TableHead>\n              <TableHead>Subtotal</TableHead>\n            </TableRow>\n          </TableHeader>\n          <TableBody>\n            {order.items.map((item) => (\n              <TableRow key={item.product}>\n                <TableCell>{item.product}</TableCell>\n                <TableCell>{item.qty}</TableCell>\n                <TableCell>{currency(item.price)}</TableCell>\n                <TableCell>{currency(item.qty * item.price)}</TableCell>\n              </TableRow>\n            ))}\n          </TableBody>\n        </Table>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "@components/tables/master-detail-table/order-detail.tsx"
    },
    {
      "path": "src/components/master-detail/index.tsx",
      "content": "import { columns } from './columns'\nimport type { Order } from './columns'\nimport { MasterDetailTable } from './data-table'\n\nconst data: Order[] = [\n  {\n    id: 'ORD-1001',\n    customer: 'Ava Thompson',\n    date: '2026-06-02',\n    status: 'Delivered',\n    total: 154.97,\n    shippingAddress: '221 Baker St, Springfield, IL',\n    items: [\n      { product: 'Wireless Mouse', qty: 1, price: 29.99 },\n      { product: 'Mechanical Keyboard', qty: 1, price: 89.0 },\n      { product: 'USB-C Hub', qty: 2, price: 17.99 },\n    ],\n  },\n  {\n    id: 'ORD-1002',\n    customer: 'Liam Chen',\n    date: '2026-06-04',\n    status: 'Processing',\n    total: 42.5,\n    shippingAddress: '88 Market Ave, Austin, TX',\n    items: [{ product: 'Phone Case', qty: 2, price: 21.25 }],\n  },\n  {\n    id: 'ORD-1003',\n    customer: 'Sofia Patel',\n    date: '2026-06-05',\n    status: 'Delivered',\n    total: 310.0,\n    shippingAddress: '14 Harbor Rd, Seattle, WA',\n    items: [\n      { product: '27\" Monitor', qty: 1, price: 249.0 },\n      { product: 'Monitor Arm', qty: 1, price: 61.0 },\n    ],\n  },\n  {\n    id: 'ORD-1004',\n    customer: 'Noah Garcia',\n    date: '2026-06-06',\n    status: 'Cancelled',\n    total: 18.99,\n    shippingAddress: '5 Elm Court, Denver, CO',\n    items: [{ product: 'Cable Sleeve', qty: 1, price: 18.99 }],\n  },\n]\n\nexport function MasterDetailDemo() {\n  return <MasterDetailTable columns={columns} data={data} />\n}\n",
      "type": "registry:component",
      "target": "@components/tables/master-detail-table/index.tsx"
    }
  ],
  "type": "registry:block"
}