{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-table-3",
  "type": "registry:component",
  "title": "DataTable 3",
  "description": "DataTable 3. A component for displaying and managing tabular data.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "checkbox",
    "dropdown-menu",
    "input",
    "table"
  ],
  "files": [
    {
      "path": "components/watermelon/data-table-3.tsx",
      "type": "registry:component",
      "content": "'use client'\n\nimport { useMemo, useState } from 'react'\n\nimport { ChevronDownIcon, Columns3Icon, RefreshCcwIcon, SearchIcon } from 'lucide-react'\n\nimport { Checkbox } from '@/components/base-ui/checkbox'\nimport {\n  DropdownMenu,\n  DropdownMenuCheckboxItem,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuSeparator,\n  DropdownMenuTrigger\n} from '@/components/base-ui/dropdown-menu'\nimport { Input } from '@/components/base-ui/input'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/base-ui/table'\n\ntype InvoiceStatus = 'failed' | 'paid' | 'processing' | 'review'\n\ntype ClientInvoice = {\n  amount: number\n  email: string\n  id: string\n  name: string\n  status: InvoiceStatus\n}\n\ntype ColumnKey = 'amount' | 'email' | 'name' | 'status'\n\ntype ColumnOption = {\n  key: ColumnKey\n  label: string\n}\n\nconst data: readonly ClientInvoice[] = [\n  {\n    id: 'INV-201',\n    name: 'Harbor Studio',\n    amount: 699,\n    status: 'paid',\n    email: 'hello@harborstudio.co'\n  },\n  {\n    id: 'INV-202',\n    name: 'Bright Matter',\n    amount: 242,\n    status: 'paid',\n    email: 'team@brightmatter.io'\n  },\n  {\n    id: 'INV-203',\n    name: 'Grain Works',\n    amount: 655,\n    status: 'processing',\n    email: 'ops@grainworks.design'\n  },\n  {\n    id: 'INV-204',\n    name: 'North Track',\n    amount: 874,\n    status: 'review',\n    email: 'finance@northtrack.app'\n  },\n  {\n    id: 'INV-205',\n    name: 'Common Unit',\n    amount: 541,\n    status: 'failed',\n    email: 'billing@commonunit.dev'\n  }\n] as const\n\nconst columnOptions: readonly ColumnOption[] = [\n  { key: 'name', label: 'Name' },\n  { key: 'status', label: 'Status' },\n  { key: 'email', label: 'Email' },\n  { key: 'amount', label: 'Amount' }\n] as const\n\nconst defaultVisibility: Record<ColumnKey, boolean> = {\n  name: true,\n  status: true,\n  email: true,\n  amount: true\n}\n\nconst formatCurrency = (amount: number) =>\n  new Intl.NumberFormat('en-US', {\n    style: 'currency',\n    currency: 'USD'\n  }).format(amount)\n\nconst DataTable3 = () => {\n  const [searchQuery, setSearchQuery] = useState('')\n  const [selectedIds, setSelectedIds] = useState<string[]>([])\n  const [visibleColumns, setVisibleColumns] = useState<Record<ColumnKey, boolean>>(defaultVisibility)\n\n  const selectedIdSet = useMemo(() => new Set(selectedIds), [selectedIds])\n  const allSelected = selectedIds.length === data.length\n  const someSelected = selectedIds.length > 0 && !allSelected\n\n  const filteredColumnOptions = useMemo(\n    () =>\n      columnOptions.filter((column) =>\n        column.label.toLowerCase().includes(searchQuery.trim().toLowerCase())\n      ),\n    [searchQuery]\n  )\n\n  const toggleAll = (checked: boolean) => {\n    setSelectedIds(checked ? data.map((item) => item.id) : [])\n  }\n\n  const toggleRow = (id: string, checked: boolean) => {\n    setSelectedIds((current) => {\n      if (checked) {\n        return current.includes(id) ? current : [...current, id]\n      }\n\n      return current.filter((item) => item !== id)\n    })\n  }\n\n  const toggleColumn = (key: ColumnKey, checked: boolean) => {\n    setVisibleColumns((current) => ({\n      ...current,\n      [key]: checked\n    }))\n  }\n\n  const resetColumns = () => {\n    setVisibleColumns(defaultVisibility)\n    setSearchQuery('')\n  }\n\n  return (\n    <div className='w-60 sm:w-100 md:w-120 lg:w-160 2xl:w-220 mx-auto'>\n      <div className='py-4'>\n        <DropdownMenu>\n          <DropdownMenuTrigger className='inline-flex w-full max-w-44 items-center justify-between gap-2 rounded-lg border border-border/60 bg-background px-4 py-2 text-sm font-medium text-foreground outline-none transition-colors hover:bg-muted/20'>\n            <span className='flex items-center gap-2'>\n              <Columns3Icon className='size-4 text-muted-foreground' />\n              Columns\n            </span>\n            <ChevronDownIcon className='size-4 text-muted-foreground' />\n          </DropdownMenuTrigger>\n          <DropdownMenuContent align='start' className='w-56 rounded-lg border border-border/60 bg-background p-1 shadow-sm'>\n            <div className='relative px-0.5 py-0.5'>\n              <Input\n                value={searchQuery}\n                onChange={(e) => setSearchQuery(e.target.value)}\n                className='rounded-md border-border/60 bg-background pl-8'\n                placeholder='Search columns'\n                onKeyDown={(e) => e.stopPropagation()}\n              />\n              <SearchIcon className='absolute inset-y-0 left-3 my-auto size-4 text-muted-foreground' />\n            </div>\n            <DropdownMenuSeparator />\n            {filteredColumnOptions.length > 0 ? (\n              filteredColumnOptions.map((column) => (\n                <DropdownMenuCheckboxItem\n                  key={column.key}\n                  checked={visibleColumns[column.key]}\n                  onCheckedChange={(value) => toggleColumn(column.key, !!value)}\n                  onSelect={(e) => e.preventDefault()}\n                >\n                  {column.label}\n                </DropdownMenuCheckboxItem>\n              ))\n            ) : (\n              <DropdownMenuItem disabled>No columns found</DropdownMenuItem>\n            )}\n            <DropdownMenuSeparator />\n            <DropdownMenuItem onClick={resetColumns}>\n              <RefreshCcwIcon className='size-4' />\n              Reset\n            </DropdownMenuItem>\n          </DropdownMenuContent>\n        </DropdownMenu>\n      </div>\n\n      <div className='overflow-hidden rounded-xl border border-border/60 bg-background'>\n        <Table className='w-60 sm:w-100 md:w-120 lg:w-160 2xl:w-220 mx-auto'>\n          <TableHeader>\n            <TableRow>\n              <TableHead className='h-12 w-10 border-b border-border/60 bg-transparent text-[13px] font-medium tracking-[0.08em] text-muted-foreground uppercase'>\n                <Checkbox\n                  checked={allSelected}\n                  aria-checked={someSelected ? 'mixed' : allSelected}\n                  onCheckedChange={(value) => toggleAll(!!value)}\n                  aria-label='Select all invoices'\n                  className='after:hidden data-checked:border-sky-600 data-checked:bg-sky-600 data-checked:text-white dark:data-checked:border-sky-500 dark:data-checked:bg-sky-500 dark:data-checked:text-white'\n                />\n              </TableHead>\n              {visibleColumns.name ? (\n                <TableHead className='h-12 border-b border-border/60 bg-transparent text-[13px] font-medium tracking-[0.08em] text-muted-foreground'>\n                  Name\n                </TableHead>\n              ) : null}\n              {visibleColumns.status ? (\n                <TableHead className='h-12 border-b border-border/60 bg-transparent text-[13px] font-medium tracking-[0.08em] text-muted-foreground'>\n                  Status\n                </TableHead>\n              ) : null}\n              {visibleColumns.email ? (\n                <TableHead className='h-12 border-b border-border/60 bg-transparent text-[13px] font-medium tracking-[0.08em] text-muted-foreground'>\n                  Email\n                </TableHead>\n              ) : null}\n              {visibleColumns.amount ? (\n                <TableHead className='h-12 border-b border-border/60 bg-transparent text-right text-[13px] font-medium tracking-[0.08em] text-muted-foreground'>\n                  Amount\n                </TableHead>\n              ) : null}\n            </TableRow>\n          </TableHeader>\n          <TableBody>\n            {data.map((row) => {\n              const isSelected = selectedIdSet.has(row.id)\n\n              return (\n                <TableRow\n                  key={row.id}\n                  data-state={isSelected ? 'selected' : undefined}\n                  className='transition-colors hover:bg-muted/20 data-[state=selected]:bg-muted/25'\n                >\n                  <TableCell className='py-3'>\n                    <Checkbox\n                      checked={isSelected}\n                      onCheckedChange={(value) => toggleRow(row.id, !!value)}\n                      aria-label={`Select ${row.name}`}\n                      className='after:hidden data-checked:border-sky-600 data-checked:bg-sky-600 data-checked:text-white dark:data-checked:border-sky-500 dark:data-checked:bg-sky-500 dark:data-checked:text-white'\n                    />\n                  </TableCell>\n                  {visibleColumns.name ? (\n                    <TableCell className='py-3'>\n                      <div className='font-medium'>{row.name}</div>\n                    </TableCell>\n                  ) : null}\n                  {visibleColumns.status ? (\n                    <TableCell className='py-3'>\n                      <div className='capitalize text-sm text-muted-foreground'>{row.status}</div>\n                    </TableCell>\n                  ) : null}\n                  {visibleColumns.email ? (\n                    <TableCell className='py-3'>\n                      <div className='text-sm text-muted-foreground'>{row.email}</div>\n                    </TableCell>\n                  ) : null}\n                  {visibleColumns.amount ? (\n                    <TableCell className='py-3'>\n                      <div className='text-right font-medium'>{formatCurrency(row.amount)}</div>\n                    </TableCell>\n                  ) : null}\n                </TableRow>\n              )\n            })}\n          </TableBody>\n        </Table>\n      </div>\n    </div>\n  )\n}\n\nexport default DataTable3\n"
    }
  ]
}
