{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "data-table-4",
  "type": "registry:component",
  "title": "DataTable 4",
  "description": "DataTable 4. A component for displaying and managing tabular data.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "avatar",
    "badge",
    "checkbox",
    "input",
    "label",
    "select",
    "table"
  ],
  "files": [
    {
      "path": "components/watermelon/data-table-4.tsx",
      "type": "registry:component",
      "content": "'use client'\n\nimport { useMemo, useState } from 'react'\n\nimport { SearchIcon } from 'lucide-react'\n\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/base-ui/avatar'\nimport { Badge } from '@/components/base-ui/badge'\nimport { Checkbox } from '@/components/base-ui/checkbox'\nimport { Input } from '@/components/base-ui/input'\nimport { Label } from '@/components/base-ui/label'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/base-ui/select'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/base-ui/table'\n\ntype Availability = 'In Stock' | 'Limited' | 'Out of Stock'\n\ntype ProductItem = {\n  availability: Availability\n  fallback: string\n  id: string\n  price: number\n  product: string\n  productImage: string\n  rating: number\n}\n\ntype FilterState = {\n  availability: Availability | 'all'\n  maxPrice: string\n  maxRating: string\n  minPrice: string\n  minRating: string\n  product: string\n}\n\nconst items: readonly ProductItem[] = [\n  {\n    id: '1',\n    product: 'Ash Lounge Chair',\n    productImage: 'https://picsum.photos/seed/ash-lounge-chair/160/160',\n    fallback: 'AL',\n    price: 159,\n    availability: 'In Stock',\n    rating: 3.9\n  },\n  {\n    id: '2',\n    product: 'Velocity Runner',\n    productImage: 'https://picsum.photos/seed/velocity-runner/160/160',\n    fallback: 'VR',\n    price: 599,\n    availability: 'Limited',\n    rating: 4.4\n  },\n  {\n    id: '3',\n    product: 'Orbit Phone X',\n    productImage: 'https://picsum.photos/seed/orbit-phone-x/160/160',\n    fallback: 'OP',\n    price: 1299,\n    availability: 'Out of Stock',\n    rating: 3.5\n  },\n  {\n    id: '4',\n    product: 'Switch Dock Set',\n    productImage: 'https://picsum.photos/seed/switch-dock-set/160/160',\n    fallback: 'SD',\n    price: 499,\n    availability: 'In Stock',\n    rating: 4.9\n  },\n  {\n    id: '5',\n    product: 'Magic Pointer',\n    productImage: 'https://picsum.photos/seed/magic-pointer/160/160',\n    fallback: 'MP',\n    price: 970,\n    availability: 'Limited',\n    rating: 4.1\n  },\n  {\n    id: '6',\n    product: 'Pulse Watch',\n    productImage: 'https://picsum.photos/seed/pulse-watch/160/160',\n    fallback: 'PW',\n    price: 1500,\n    availability: 'Limited',\n    rating: 3.1\n  },\n  {\n    id: '7',\n    product: 'Terrain Watch',\n    productImage: 'https://picsum.photos/seed/terrain-watch/160/160',\n    fallback: 'TW',\n    price: 194,\n    availability: 'Out of Stock',\n    rating: 1.5\n  },\n  {\n    id: '8',\n    product: 'North Shade Glasses',\n    productImage: 'https://picsum.photos/seed/north-shade-glasses/160/160',\n    fallback: 'NS',\n    price: 199,\n    availability: 'Out of Stock',\n    rating: 2.4\n  }\n] as const\n\nconst defaultFilters: FilterState = {\n  product: '',\n  minPrice: '',\n  maxPrice: '',\n  availability: 'all',\n  minRating: '',\n  maxRating: ''\n}\n\nconst availabilityBadgeClass: Record<Availability, string> = {\n  'In Stock': 'border-none bg-green-600/10 text-green-600 dark:bg-green-400/10 dark:text-green-400',\n  'Out of Stock': 'border-none bg-destructive/10 text-destructive dark:bg-destructive/20',\n  Limited: 'border-none bg-amber-600/10 text-amber-600 dark:bg-amber-400/10 dark:text-amber-400'\n}\n\nconst toNumber = (value: string) => (value.trim() ? Number(value) : undefined)\n\nconst DataTable4 = () => {\n  const [filters, setFilters] = useState<FilterState>(defaultFilters)\n  const [selectedIds, setSelectedIds] = useState<string[]>([])\n\n  const filteredItems = useMemo(() => {\n    const productQuery = filters.product.trim().toLowerCase()\n    const minPrice = toNumber(filters.minPrice)\n    const maxPrice = toNumber(filters.maxPrice)\n    const minRating = toNumber(filters.minRating)\n    const maxRating = toNumber(filters.maxRating)\n\n    return items.filter((item) => {\n      const matchesProduct = productQuery ? item.product.toLowerCase().includes(productQuery) : true\n      const matchesAvailability =\n        filters.availability === 'all' ? true : item.availability === filters.availability\n      const matchesMinPrice = minPrice !== undefined ? item.price >= minPrice : true\n      const matchesMaxPrice = maxPrice !== undefined ? item.price <= maxPrice : true\n      const matchesMinRating = minRating !== undefined ? item.rating >= minRating : true\n      const matchesMaxRating = maxRating !== undefined ? item.rating <= maxRating : true\n\n      return (\n        matchesProduct &&\n        matchesAvailability &&\n        matchesMinPrice &&\n        matchesMaxPrice &&\n        matchesMinRating &&\n        matchesMaxRating\n      )\n    })\n  }, [filters])\n\n  const selectedIdSet = useMemo(() => new Set(selectedIds), [selectedIds])\n  const visibleIds = filteredItems.map((item) => item.id)\n  const allSelected = visibleIds.length > 0 && visibleIds.every((id) => selectedIdSet.has(id))\n  const someSelected = visibleIds.some((id) => selectedIdSet.has(id)) && !allSelected\n\n  const updateFilter = <K extends keyof FilterState>(key: K, value: FilterState[K]) => {\n    setFilters((current) => ({\n      ...current,\n      [key]: value\n    }))\n  }\n\n  const toggleAll = (checked: boolean) => {\n    if (checked) {\n      setSelectedIds((current) => Array.from(new Set([...current, ...visibleIds])))\n      return\n    }\n\n    setSelectedIds((current) => current.filter((id) => !visibleIds.includes(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  return (\n    <div className='w-60 sm:w-100 md:w-120 lg:w-160 2xl:w-220 mx-auto'>\n      <div className='overflow-hidden rounded-xl border border-border/60 bg-background shadow-sm'>\n        <div className='grid gap-3 border-b border-dashed border-border/60 px-4 py-5 md:grid-cols-[minmax(0,1.4fr)_repeat(3,minmax(0,1fr))]'>\n          <div className='space-y-2'>\n            <Label htmlFor='product-filter'>Product</Label>\n            <div className='relative'>\n              <Input\n                id='product-filter'\n                className='h-10 rounded-md border-border/60 pl-9'\n                value={filters.product}\n                onChange={(e) => updateFilter('product', e.target.value)}\n                placeholder='Search product'\n                type='text'\n              />\n              <div className='pointer-events-none absolute inset-y-0 left-0 flex items-center pl-3 text-muted-foreground'>\n                <SearchIcon size={16} />\n              </div>\n            </div>\n          </div>\n\n          <div className='space-y-2'>\n            <Label>Price</Label>\n            <div className='flex'>\n              <Input\n                className='h-10 rounded-r-none border-border/60'\n                value={filters.minPrice}\n                onChange={(e) => updateFilter('minPrice', e.target.value)}\n                placeholder='Min'\n                type='number'\n              />\n              <Input\n                className='-ms-px h-10 rounded-l-none border-border/60'\n                value={filters.maxPrice}\n                onChange={(e) => updateFilter('maxPrice', e.target.value)}\n                placeholder='Max'\n                type='number'\n              />\n            </div>\n          </div>\n\n          <div className='space-y-2'>\n            <Label htmlFor='availability-filter' >Availability</Label>\n            <Select\n              value={filters.availability}\n              onValueChange={(value) => updateFilter('availability', value as FilterState['availability'])}\n            >\n              <SelectTrigger id='availability-filter' className='h-10 w-full rounded-lg border-border/60 py-[19px]'>\n                <SelectValue />\n              </SelectTrigger>\n              <SelectContent>\n                <SelectItem value='all'>All</SelectItem>\n                <SelectItem value='In Stock'>In Stock</SelectItem>\n                <SelectItem value='Limited'>Limited</SelectItem>\n                <SelectItem value='Out of Stock'>Out of Stock</SelectItem>\n              </SelectContent>\n            </Select>\n          </div>\n\n          <div className='space-y-2'>\n            <Label>Rating</Label>\n            <div className='flex'>\n              <Input\n                className='h-10 rounded-r-none border-border/60'\n                value={filters.minRating}\n                onChange={(e) => updateFilter('minRating', e.target.value)}\n                placeholder='Min'\n                type='number'\n                step='0.1'\n              />\n              <Input\n                className='-ms-px h-10 rounded-l-none border-border/60'\n                value={filters.maxRating}\n                onChange={(e) => updateFilter('maxRating', e.target.value)}\n                placeholder='Max'\n                type='number'\n                step='0.1'\n              />\n            </div>\n          </div>\n        </div>\n\n        <Table className='w-60 sm:w-100 md:w-120 lg:w-160 2xl:w-220 mx-auto [&_td]:align-top'>\n          <TableHeader>\n            <TableRow>\n              <TableHead className='h-12 w-10 border-b border-dashed border-border/60 bg-transparent font-medium'>\n                <Checkbox\n                  checked={allSelected}\n                  aria-checked={someSelected ? 'mixed' : allSelected}\n                  onCheckedChange={(value) => toggleAll(!!value)}\n                  aria-label='Select all products'\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              <TableHead className='h-12 border-b border-dashed border-border/60 bg-transparent text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground'>\n                Sr. No\n              </TableHead>\n              <TableHead className='h-12 border-b border-dashed border-border/60 bg-transparent text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground'>\n                Product\n              </TableHead>\n              <TableHead className='h-12 border-b border-dashed border-border/60 bg-transparent text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground'>\n                Price\n              </TableHead>\n              <TableHead className='h-12 border-b border-dashed border-border/60 bg-transparent text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground'>\n                Availability\n              </TableHead>\n              <TableHead className='h-12 border-b border-dashed border-border/60 bg-transparent text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground'>\n                Rating\n              </TableHead>\n            </TableRow>\n          </TableHeader>\n          <TableBody>\n            {filteredItems.length > 0 ? (\n              filteredItems.map((item) => {\n                const isSelected = selectedIdSet.has(item.id)\n\n                return (\n                <TableRow\n                  key={item.id}\n                  data-state={isSelected ? 'selected' : undefined}\n                  className='transition-colors hover:bg-muted/10 data-[state=selected]:bg-muted/15'\n                >\n                    <TableCell className='py-3.5'>\n                      <Checkbox\n                        checked={isSelected}\n                        onCheckedChange={(value) => toggleRow(item.id, !!value)}\n                        aria-label={`Select ${item.product}`}\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                    <TableCell className='py-3.5'>\n                      <div className='text-sm text-muted-foreground'>{item.id}</div>\n                    </TableCell>\n                    <TableCell className='py-3.5'>\n                      <div className='flex items-center gap-3'>\n                        <Avatar className='rounded-sm'>\n                          <AvatarImage src={item.productImage} alt={item.product} />\n                          <AvatarFallback className='text-xs'>{item.fallback}</AvatarFallback>\n                        </Avatar>\n                        <div className='font-medium'>{item.product}</div>\n                      </div>\n                    </TableCell>\n                    <TableCell className='py-3.5 font-medium'>${item.price}</TableCell>\n                    <TableCell className='py-3.5'>\n                      <Badge className={availabilityBadgeClass[item.availability]}>{item.availability}</Badge>\n                    </TableCell>\n                    <TableCell className='py-3.5 text-muted-foreground'>{item.rating.toFixed(1)}</TableCell>\n                  </TableRow>\n                )\n              })\n            ) : (\n              <TableRow>\n                <TableCell colSpan={6} className='h-24 text-center text-muted-foreground'>\n                  No results.\n                </TableCell>\n              </TableRow>\n            )}\n          </TableBody>\n        </Table>\n      </div>\n    </div>\n  )\n}\n\nexport default DataTable4\n"
    }
  ]
}
