DataTableViewOptions.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { GripVertical, Settings2 } from 'lucide-react'
  2. import { useId, useMemo, useState } from 'react'
  3. import {
  4. Checkbox,
  5. Command,
  6. CommandEmpty,
  7. CommandGroup,
  8. CommandInput,
  9. CommandItem,
  10. CommandList,
  11. Popover,
  12. PopoverContent,
  13. PopoverTrigger,
  14. } from 'ui'
  15. import { ButtonTooltip } from '../ButtonTooltip'
  16. import { Sortable, SortableDragHandle, SortableItem } from './primitives/Sortable'
  17. import { useDataTable } from './providers/DataTableProvider'
  18. export function DataTableViewOptions() {
  19. const { table, enableColumnOrdering } = useDataTable()
  20. const [open, setOpen] = useState(false)
  21. const [drag, setDrag] = useState(false)
  22. const [search, setSearch] = useState('')
  23. const listboxId = useId()
  24. const columnOrder = table.getState().columnOrder
  25. const sortedColumns = useMemo(
  26. () =>
  27. table.getAllColumns().sort((a, b) => {
  28. return columnOrder.indexOf(a.id) - columnOrder.indexOf(b.id)
  29. }),
  30. [columnOrder]
  31. )
  32. return (
  33. <Popover open={open} onOpenChange={setOpen}>
  34. <PopoverTrigger asChild>
  35. <ButtonTooltip
  36. type="default"
  37. size="tiny"
  38. role="combobox"
  39. aria-expanded={open}
  40. aria-controls={listboxId}
  41. className="w-[26px]"
  42. icon={<Settings2 className="text-foreground" />}
  43. tooltip={{ content: { side: 'bottom', text: 'Toggle column visibility' } }}
  44. />
  45. </PopoverTrigger>
  46. <PopoverContent id={listboxId} side="bottom" align="end" className="w-[200px] p-0">
  47. <Command>
  48. <CommandInput
  49. value={search}
  50. onValueChange={setSearch}
  51. placeholder="Search columns..."
  52. className="text-xs"
  53. />
  54. <CommandList>
  55. <CommandEmpty>No option found.</CommandEmpty>
  56. <CommandGroup>
  57. <Sortable
  58. value={sortedColumns.map((c) => ({ id: c.id }))}
  59. onValueChange={(items) => table.setColumnOrder(items.map((c) => c.id))}
  60. overlay={<div className="h-8 w-full rounded-md bg-muted/60" />}
  61. onDragStart={() => setDrag(true)}
  62. onDragEnd={() => setDrag(false)}
  63. onDragCancel={() => setDrag(false)}
  64. >
  65. {sortedColumns
  66. .filter(
  67. (column) => typeof column.accessorFn !== 'undefined' && column.getCanHide()
  68. )
  69. .map((column) => (
  70. <SortableItem key={column.id} value={column.id} asChild>
  71. <CommandItem
  72. value={column.id}
  73. onSelect={() => column.toggleVisibility(!column.getIsVisible())}
  74. className="capitalize p-1"
  75. disabled={drag}
  76. >
  77. <Checkbox checked={column.getIsVisible()} className="mr-2" />
  78. <span>{(column.columnDef.meta as any)?.label || column.id}</span>
  79. {enableColumnOrdering && !search ? (
  80. <SortableDragHandle
  81. type="text"
  82. size="tiny"
  83. className="ml-auto size-5 text-muted-foreground hover:text-foreground focus:bg-muted focus:text-foreground"
  84. >
  85. <GripVertical className="size-4" aria-hidden="true" />
  86. </SortableDragHandle>
  87. ) : null}
  88. </CommandItem>
  89. </SortableItem>
  90. ))}
  91. </Sortable>
  92. </CommandGroup>
  93. </CommandList>
  94. </Command>
  95. </PopoverContent>
  96. </Popover>
  97. )
  98. }