{
  "$schema": "https://ethereal-ui.saefulrohman.dev/schema/registry-item.json",
  "name": "table",
  "title": "Table",
  "type": "registry:primitives",
  "description": "Clean, responsive tabular layout with subtle row hover states, avatars, and status badges.",
  "dependencies": [],
  "usage": "import { Avatar, Badge } from \"@etherealui/react\"\n\nexport function SimpleTableDemo() {\n  return (\n    <div className=\"w-full max-w-xl overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-800\">\n      <table className=\"w-full text-left text-xs\">\n        <thead className=\"border-b border-zinc-200 bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900\">\n          <tr>\n            <th className=\"px-4 py-2.5 font-medium text-zinc-500\">Member</th>\n            <th className=\"px-4 py-2.5 font-medium text-zinc-500\">Status</th>\n            <th className=\"px-4 py-2.5 font-medium text-zinc-500 text-right\">Role</th>\n          </tr>\n        </thead>\n        <tbody className=\"divide-y divide-zinc-200 bg-white dark:divide-zinc-800 dark:bg-zinc-950\">\n          <tr>\n            <td className=\"px-4 py-2.5 flex items-center gap-2.5\">\n              <Avatar fallback=\"SR\" tint=\"blue\" size=\"xs\" />\n              <span className=\"font-medium\">Saeful Rohman</span>\n            </td>\n            <td className=\"px-4 py-2.5\"><Badge variant=\"emerald\" dot>Active</Badge></td>\n            <td className=\"px-4 py-2.5 text-right text-zinc-500\">Owner</td>\n          </tr>\n        </tbody>\n      </table>\n    </div>\n  )\n}",
  "files": [
    {
      "path": "packages/ui/src/blocks/data-table.tsx",
      "target": "components/ui/table.tsx",
      "type": "registry:primitives",
      "content": "import * as React from \"react\"\nimport {\n  ArrowUpDown,\n  Search,\n  MoreHorizontal,\n  Download,\n  Eye,\n  Copy,\n  Trash2,\n  ChevronLeft,\n  ChevronRight,\n  SlidersHorizontal,\n} from \"lucide-react\"\nimport { cn } from \"../utils/cn\"\nimport { Avatar } from \"../primitives/avatar\"\nimport { Badge } from \"../primitives/badge\"\nimport { Button } from \"../primitives/button\"\nimport { Checkbox } from \"../primitives/switch\"\nimport { Input } from \"../primitives/input\"\nimport {\n  DropdownMenu,\n  DropdownMenuTrigger,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n} from \"../primitives/dropdown-menu\"\nimport {\n  Drawer,\n  DrawerContent,\n  DrawerHeader,\n  DrawerTitle,\n  DrawerDescription,\n  DrawerFooter,\n} from \"../primitives/drawer\"\nimport { Progress } from \"../primitives/progress\"\n\nexport interface EnterpriseRowData {\n  id: string\n  customer: string\n  email: string\n  plan: string\n  status: \"active\" | \"trialing\" | \"past_due\" | \"canceled\"\n  mrrAmount: number\n  mrrFormatted: string\n  seatUsage: number\n  updatedAt: string\n}\n\nconst defaultRows: EnterpriseRowData[] = [\n  {\n    id: \"cus-9921\",\n    customer: \"Linear Orbit Inc.\",\n    email: \"billing@linearorbit.io\",\n    plan: \"Enterprise Annual\",\n    status: \"active\",\n    mrrAmount: 4200,\n    mrrFormatted: \"$4,200.00\",\n    seatUsage: 84,\n    updatedAt: \"2 hours ago\",\n  },\n  {\n    id: \"cus-8840\",\n    customer: \"Raycast Labs GmbH\",\n    email: \"finance@raycastlabs.de\",\n    plan: \"Enterprise Annual\",\n    status: \"active\",\n    mrrAmount: 3150,\n    mrrFormatted: \"$3,150.00\",\n    seatUsage: 62,\n    updatedAt: \"5 hours ago\",\n  },\n  {\n    id: \"cus-7732\",\n    customer: \"chronicle.so\",\n    email: \"accounts@chronicle.so\",\n    plan: \"Pro Monthly\",\n    status: \"trialing\",\n    mrrAmount: 890,\n    mrrFormatted: \"$890.00\",\n    seatUsage: 45,\n    updatedAt: \"1 day ago\",\n  },\n  {\n    id: \"cus-6419\",\n    customer: \"Northstar Analytics\",\n    email: \"ops@northstar.co\",\n    plan: \"Scale Annual\",\n    status: \"past_due\",\n    mrrAmount: 1950,\n    mrrFormatted: \"$1,950.00\",\n    seatUsage: 92,\n    updatedAt: \"2 days ago\",\n  },\n  {\n    id: \"cus-5108\",\n    customer: \"Veloce Design Studio\",\n    email: \"team@veloce.design\",\n    plan: \"Pro Monthly\",\n    status: \"active\",\n    mrrAmount: 640,\n    mrrFormatted: \"$640.00\",\n    seatUsage: 38,\n    updatedAt: \"3 days ago\",\n  },\n]\n\nconst statusBadgeVariant: Record<\n  EnterpriseRowData[\"status\"],\n  { variant: \"emerald\" | \"blue\" | \"amber\" | \"rose\"; label: string }\n> = {\n  active: { variant: \"emerald\", label: \"Active\" },\n  trialing: { variant: \"blue\", label: \"Trialing\" },\n  past_due: { variant: \"amber\", label: \"Past Due\" },\n  canceled: { variant: \"rose\", label: \"Canceled\" },\n}\n\nexport interface EnterpriseDataTableProps {\n  data?: EnterpriseRowData[]\n  className?: string\n}\n\nexport const EnterpriseDataTable: React.FC<EnterpriseDataTableProps> = ({\n  data = defaultRows,\n  className,\n}) => {\n  const [rows, setRows] = React.useState<EnterpriseRowData[]>(data)\n  const [search, setSearch] = React.useState(\"\")\n  const [statusFilter, setStatusFilter] = React.useState<string>(\"all\")\n  const [sortAsc, setSortAsc] = React.useState(false)\n  const [selectedIds, setSelectedIds] = React.useState<Record<string, boolean>>({})\n  const [inspectedRow, setInspectedRow] = React.useState<EnterpriseRowData | null>(null)\n  const [showPlanCol, setShowPlanCol] = React.useState(true)\n\n  const filteredRows = React.useMemo(() => {\n    return rows\n      .filter((r) => {\n        if (statusFilter !== \"all\" && r.status !== statusFilter) return false\n        if (!search.trim()) return true\n        const q = search.toLowerCase()\n        return (\n          r.customer.toLowerCase().includes(q) ||\n          r.email.toLowerCase().includes(q) ||\n          r.id.toLowerCase().includes(q) ||\n          r.plan.toLowerCase().includes(q)\n        )\n      })\n      .sort((a, b) =>\n        sortAsc ? a.mrrAmount - b.mrrAmount : b.mrrAmount - a.mrrAmount\n      )\n  }, [rows, search, statusFilter, sortAsc])\n\n  const selectedCount = Object.values(selectedIds).filter(Boolean).length\n\n  return (\n    <div\n      className={cn(\n        \"rounded-xl border border-zinc-200 bg-white overflow-hidden dark:border-zinc-800 dark:bg-zinc-900\",\n        className\n      )}\n    >\n      {/* Table Toolbar */}\n      <div className=\"flex flex-col gap-3 border-b border-zinc-200 p-4 lg:flex-row lg:items-center lg:justify-between dark:border-zinc-800\">\n        <div className=\"flex flex-wrap items-center gap-2.5\">\n          <Input\n            value={search}\n            onChange={(e) => setSearch(e.target.value)}\n            placeholder=\"Filter customers...\"\n            leftIcon={<Search className=\"h-3.5 w-3.5\" />}\n            className=\"w-full sm:w-64\"\n          />\n\n          <div className=\"flex items-center rounded-lg border border-zinc-200 bg-zinc-100/70 p-0.5 text-xs dark:border-zinc-800 dark:bg-zinc-800/60\">\n            {([\"all\", \"active\", \"trialing\", \"past_due\"] as const).map((st) => (\n              <button\n                key={st}\n                type=\"button\"\n                onClick={() => setStatusFilter(st)}\n                className={cn(\n                  \"rounded-md px-2.5 py-1 capitalize transition-colors cursor-pointer\",\n                  statusFilter === st\n                    ? \"bg-white text-zinc-900 font-medium shadow-2xs dark:bg-zinc-900 dark:text-white\"\n                    : \"text-zinc-500 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-200\"\n                )}\n              >\n                {st.replace(\"_\", \" \")}\n              </button>\n            ))}\n          </div>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          {selectedCount > 0 && (\n            <Badge variant=\"blue\">{selectedCount} selected</Badge>\n          )}\n          <Button\n            variant=\"outline\"\n            size=\"sm\"\n            onClick={() => setShowPlanCol((prev) => !prev)}\n          >\n            <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n            Columns\n          </Button>\n          <Button variant=\"outline\" size=\"sm\">\n            <Download className=\"h-3.5 w-3.5\" />\n            Export\n          </Button>\n        </div>\n      </div>\n\n      {/* Table */}\n      <div className=\"overflow-x-auto\">\n        <table className=\"w-full border-collapse text-left text-xs\">\n          <thead>\n            <tr className=\"border-b border-zinc-200 bg-zinc-50/70 text-[11px] font-medium text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950/40 dark:text-zinc-400\">\n              <th className=\"w-10 px-4 py-3\">\n                <Checkbox\n                  checked={\n                    filteredRows.length > 0 &&\n                    filteredRows.every((r) => selectedIds[r.id])\n                  }\n                  onCheckedChange={(checked) => {\n                    const next: Record<string, boolean> = {}\n                    if (checked) {\n                      filteredRows.forEach((r) => {\n                        next[r.id] = true\n                      })\n                    }\n                    setSelectedIds(next)\n                  }}\n                />\n              </th>\n              <th className=\"px-4 py-3\">Customer</th>\n              {showPlanCol && <th className=\"px-4 py-3\">Plan</th>}\n              <th className=\"px-4 py-3\">Status</th>\n              <th className=\"px-4 py-3\">\n                <button\n                  type=\"button\"\n                  onClick={() => setSortAsc(!sortAsc)}\n                  className=\"inline-flex items-center gap-1 text-zinc-600 hover:text-zinc-900 dark:text-zinc-300 dark:hover:text-white cursor-pointer\"\n                >\n                  MRR\n                  <ArrowUpDown className=\"h-3 w-3 text-zinc-400\" />\n                </button>\n              </th>\n              <th className=\"px-4 py-3\">Seat Utilization</th>\n              <th className=\"px-4 py-3\">Updated</th>\n              <th className=\"px-4 py-3 text-right\">Actions</th>\n            </tr>\n          </thead>\n          <tbody className=\"divide-y divide-zinc-200 dark:divide-zinc-800\">\n            {filteredRows.length === 0 ? (\n              <tr>\n                <td\n                  colSpan={8}\n                  className=\"py-12 text-center text-xs text-zinc-400\"\n                >\n                  No customers match your filter criteria.\n                </td>\n              </tr>\n            ) : (\n              filteredRows.map((row, idx) => {\n                const badgeInfo = statusBadgeVariant[row.status]\n                return (\n                  <tr\n                    key={row.id}\n                    onClick={() => setInspectedRow(row)}\n                    className=\"group transition-colors hover:bg-zinc-50 dark:hover:bg-zinc-800/40 cursor-pointer\"\n                  >\n                    <td\n                      className=\"px-4 py-3\"\n                      onClick={(e) => e.stopPropagation()}\n                    >\n                      <Checkbox\n                        checked={Boolean(selectedIds[row.id])}\n                        onCheckedChange={(checked) =>\n                          setSelectedIds((prev) => ({\n                            ...prev,\n                            [row.id]: Boolean(checked),\n                          }))\n                        }\n                      />\n                    </td>\n                    <td className=\"px-4 py-3\">\n                      <div className=\"flex items-center gap-2.5\">\n                        <Avatar\n                          fallback={row.customer.slice(0, 2)}\n                          tint={idx % 2 === 0 ? \"blue\" : \"neutral\"}\n                          size=\"sm\"\n                        />\n                        <div>\n                          <div className=\"font-medium text-zinc-900 dark:text-zinc-100\">\n                            {row.customer}\n                          </div>\n                          <div className=\"text-[11px] text-zinc-500\">\n                            {row.email}\n                          </div>\n                        </div>\n                      </div>\n                    </td>\n                    {showPlanCol && (\n                      <td className=\"px-4 py-3 text-zinc-600 dark:text-zinc-300\">\n                        {row.plan}\n                      </td>\n                    )}\n                    <td className=\"px-4 py-3\">\n                      <Badge variant={badgeInfo.variant} dot>\n                        {badgeInfo.label}\n                      </Badge>\n                    </td>\n                    <td className=\"px-4 py-3 font-medium text-zinc-900 dark:text-zinc-100\">\n                      {row.mrrFormatted}\n                    </td>\n                    <td className=\"px-4 py-3 w-36\">\n                      <Progress\n                        value={row.seatUsage}\n                        size=\"sm\"\n                        variant={row.seatUsage > 85 ? \"amber\" : \"blue\"}\n                      />\n                    </td>\n                    <td className=\"px-4 py-3 text-zinc-500\">{row.updatedAt}</td>\n                    <td\n                      className=\"px-4 py-3 text-right\"\n                      onClick={(e) => e.stopPropagation()}\n                    >\n                      <DropdownMenu>\n                        <DropdownMenuTrigger asChild>\n                          <button\n                            type=\"button\"\n                            className=\"rounded-lg p-1.5 text-zinc-400 hover:bg-zinc-100 hover:text-zinc-700 dark:hover:bg-zinc-800 dark:hover:text-zinc-200 cursor-pointer\"\n                          >\n                            <MoreHorizontal className=\"h-4 w-4\" />\n                          </button>\n                        </DropdownMenuTrigger>\n                        <DropdownMenuContent align=\"end\">\n                          <DropdownMenuItem\n                            onSelect={() => setInspectedRow(row)}\n                          >\n                            <Eye className=\"h-3.5 w-3.5 text-zinc-400\" />\n                            View details\n                          </DropdownMenuItem>\n                          <DropdownMenuItem\n                            onSelect={() =>\n                              navigator.clipboard?.writeText(row.id)\n                            }\n                          >\n                            <Copy className=\"h-3.5 w-3.5 text-zinc-400\" />\n                            Copy customer ID\n                          </DropdownMenuItem>\n                          <DropdownMenuSeparator />\n                          <DropdownMenuItem\n                            destructive\n                            onSelect={() =>\n                              setRows((prev) =>\n                                prev.filter((item) => item.id !== row.id)\n                              )\n                            }\n                          >\n                            <Trash2 className=\"h-3.5 w-3.5\" />\n                            Remove customer\n                          </DropdownMenuItem>\n                        </DropdownMenuContent>\n                      </DropdownMenu>\n                    </td>\n                  </tr>\n                )\n              })\n            )}\n          </tbody>\n        </table>\n      </div>\n\n      {/* Pagination Footer */}\n      <div className=\"flex items-center justify-between border-t border-zinc-200 px-4 py-3 text-xs text-zinc-500 dark:border-zinc-800 dark:text-zinc-400\">\n        <div>\n          Showing <strong className=\"text-zinc-900 dark:text-zinc-100\">1</strong>{\" \"}\n          to{\" \"}\n          <strong className=\"text-zinc-900 dark:text-zinc-100\">\n            {filteredRows.length}\n          </strong>{\" \"}\n          of{\" \"}\n          <strong className=\"text-zinc-900 dark:text-zinc-100\">\n            {rows.length}\n          </strong>{\" \"}\n          results\n        </div>\n        <div className=\"flex items-center gap-1.5\">\n          <Button variant=\"outline\" size=\"sm\" disabled>\n            <ChevronLeft className=\"h-3.5 w-3.5\" />\n            Previous\n          </Button>\n          <Button variant=\"outline\" size=\"sm\">\n            Next\n            <ChevronRight className=\"h-3.5 w-3.5\" />\n          </Button>\n        </div>\n      </div>\n\n      {/* Slide-over Inspector Drawer */}\n      <Drawer\n        open={Boolean(inspectedRow)}\n        onOpenChange={(open) => !open && setInspectedRow(null)}\n      >\n        <DrawerContent side=\"right\">\n          {inspectedRow && (\n            <>\n              <DrawerHeader>\n                <div className=\"flex items-center gap-2\">\n                  <Badge\n                    variant={statusBadgeVariant[inspectedRow.status].variant}\n                    dot\n                  >\n                    {statusBadgeVariant[inspectedRow.status].label}\n                  </Badge>\n                  <span className=\"font-mono text-xs text-zinc-400\">\n                    {inspectedRow.id}\n                  </span>\n                </div>\n                <DrawerTitle className=\"mt-2\">\n                  {inspectedRow.customer}\n                </DrawerTitle>\n                <DrawerDescription>\n                  {inspectedRow.email} • {inspectedRow.plan}\n                </DrawerDescription>\n              </DrawerHeader>\n\n              <div className=\"my-5 space-y-4 overflow-y-auto text-xs\">\n                <div className=\"grid grid-cols-2 gap-3\">\n                  <div className=\"rounded-xl border border-zinc-200 bg-zinc-50 p-3.5 dark:border-zinc-800 dark:bg-zinc-800/50\">\n                    <span className=\"text-zinc-500\">Monthly Revenue</span>\n                    <div className=\"mt-1 text-lg font-semibold text-zinc-900 dark:text-white\">\n                      {inspectedRow.mrrFormatted}\n                    </div>\n                  </div>\n                  <div className=\"rounded-xl border border-zinc-200 bg-zinc-50 p-3.5 dark:border-zinc-800 dark:bg-zinc-800/50\">\n                    <span className=\"text-zinc-500\">Seat Utilization</span>\n                    <div className=\"mt-1 text-lg font-semibold text-zinc-900 dark:text-white\">\n                      {inspectedRow.seatUsage}%\n                    </div>\n                  </div>\n                </div>\n\n                <div className=\"rounded-xl border border-zinc-200 p-4 space-y-3 dark:border-zinc-800\">\n                  <div className=\"font-medium text-zinc-900 dark:text-zinc-100\">\n                    Quota Usage\n                  </div>\n                  <Progress\n                    value={inspectedRow.seatUsage}\n                    label=\"Team Seats\"\n                    showValue\n                    variant=\"blue\"\n                  />\n                  <Progress\n                    value={64}\n                    label=\"Storage Volume\"\n                    showValue\n                    variant=\"emerald\"\n                  />\n                </div>\n              </div>\n\n              <DrawerFooter>\n                <Button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  onClick={() => setInspectedRow(null)}\n                >\n                  Close\n                </Button>\n                <Button variant=\"primary\" size=\"sm\">\n                  Edit subscription\n                </Button>\n              </DrawerFooter>\n            </>\n          )}\n        </DrawerContent>\n      </Drawer>\n    </div>\n  )\n}\n"
    }
  ]
}