Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 62 additions & 49 deletions apps/v4/app/(app)/examples/dashboard/components/data-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,22 @@ import {
IconTrendingUp,
} from "@tabler/icons-react"
import {
columnFilteringFeature,
columnVisibilityFeature,
createColumnHelper,
createFilteredRowModel,
createPaginatedRowModel,
createSortedRowModel,
flexRender,
getCoreRowModel,
getFacetedRowModel,
getFacetedUniqueValues,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
type ColumnDef,
rowPaginationFeature,
rowSelectionFeature,
rowSortingFeature,
tableFeatures,
useTable,
type ColumnFiltersState,
type ColumnVisibilityState,
type Row,
type SortingState,
type VisibilityState,
} from "@tanstack/react-table"
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts"
import { toast } from "sonner"
Expand Down Expand Up @@ -117,6 +120,25 @@ export const schema = z.object({
})

// Create a separate component for the drag handle
// Declare the features this table uses (no faceting here — include only what
// you use). Sorting, filtering, pagination, visibility, and row selection are
// enabled below.
const features = tableFeatures({
columnFilteringFeature,
columnVisibilityFeature,
rowPaginationFeature,
rowSelectionFeature,
rowSortingFeature,
filteredRowModel: createFilteredRowModel(),
paginatedRowModel: createPaginatedRowModel(),
sortedRowModel: createSortedRowModel(),
})

const columnHelper = createColumnHelper<
typeof features,
z.infer<typeof schema>
>()

function DragHandle({ id }: { id: number }) {
const { attributes, listeners } = useSortable({
id,
Expand All @@ -136,13 +158,13 @@ function DragHandle({ id }: { id: number }) {
)
}

const columns: ColumnDef<z.infer<typeof schema>>[] = [
{
const columns = columnHelper.columns([
columnHelper.display({
id: "drag",
header: () => null,
cell: ({ row }) => <DragHandle id={row.original.id} />,
},
{
}),
columnHelper.display({
id: "select",
header: ({ table }) => (
<div className="flex items-center justify-center">
Expand All @@ -167,17 +189,15 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
),
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "header",
}),
columnHelper.accessor("header", {
header: "Header",
cell: ({ row }) => {
return <TableCellViewer item={row.original} />
},
enableHiding: false,
},
{
accessorKey: "type",
}),
columnHelper.accessor("type", {
header: "Section Type",
cell: ({ row }) => (
<div className="w-32">
Expand All @@ -186,9 +206,8 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
</Badge>
</div>
),
},
{
accessorKey: "status",
}),
columnHelper.accessor("status", {
header: "Status",
cell: ({ row }) => (
<Badge variant="outline" className="px-1.5 text-muted-foreground">
Expand All @@ -200,9 +219,8 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
{row.original.status}
</Badge>
),
},
{
accessorKey: "target",
}),
columnHelper.accessor("target", {
header: () => <div className="w-full text-right">Target</div>,
cell: ({ row }) => (
<form
Expand All @@ -225,9 +243,8 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
/>
</form>
),
},
{
accessorKey: "limit",
}),
columnHelper.accessor("limit", {
header: () => <div className="w-full text-right">Limit</div>,
cell: ({ row }) => (
<form
Expand All @@ -250,9 +267,8 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
/>
</form>
),
},
{
accessorKey: "reviewer",
}),
columnHelper.accessor("reviewer", {
header: "Reviewer",
cell: ({ row }) => {
const isAssigned = row.original.reviewer !== "Assign reviewer"
Expand Down Expand Up @@ -284,8 +300,8 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
</>
)
},
},
{
}),
columnHelper.display({
id: "actions",
cell: () => (
<DropdownMenu>
Expand All @@ -308,10 +324,14 @@ const columns: ColumnDef<z.infer<typeof schema>>[] = [
</DropdownMenuContent>
</DropdownMenu>
),
},
]
}),
])

function DraggableRow({ row }: { row: Row<z.infer<typeof schema>> }) {
function DraggableRow({
row,
}: {
row: Row<typeof features, z.infer<typeof schema>>
}) {
const { transform, transition, setNodeRef, isDragging } = useSortable({
id: row.original.id,
})
Expand Down Expand Up @@ -344,7 +364,7 @@ export function DataTable({
const [data, setData] = React.useState(() => initialData)
const [rowSelection, setRowSelection] = React.useState({})
const [columnVisibility, setColumnVisibility] =
React.useState<VisibilityState>({})
React.useState<ColumnVisibilityState>({})
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
Expand All @@ -365,7 +385,8 @@ export function DataTable({
[data]
)

const table = useReactTable({
const table = useTable({
features,
data,
columns,
state: {
Expand All @@ -382,12 +403,6 @@ export function DataTable({
onColumnFiltersChange: setColumnFilters,
onColumnVisibilityChange: setColumnVisibility,
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
getFacetedRowModel: getFacetedRowModel(),
getFacetedUniqueValues: getFacetedUniqueValues(),
})

function handleDragEnd(event: DragEndEvent) {
Expand Down Expand Up @@ -541,15 +556,13 @@ export function DataTable({
Rows per page
</Label>
<Select
value={`${table.getState().pagination.pageSize}`}
value={`${table.state.pagination.pageSize}`}
onValueChange={(value) => {
table.setPageSize(Number(value))
}}
>
<SelectTrigger size="sm" className="w-20" id="rows-per-page">
<SelectValue
placeholder={table.getState().pagination.pageSize}
/>
<SelectValue placeholder={table.state.pagination.pageSize} />
</SelectTrigger>
<SelectContent side="top">
{[10, 20, 30, 40, 50].map((pageSize) => (
Expand All @@ -561,7 +574,7 @@ export function DataTable({
</Select>
</div>
<div className="flex w-fit items-center justify-center text-sm font-medium">
Page {table.getState().pagination.pageIndex + 1} of{" "}
Page {table.state.pagination.pageIndex + 1} of{" "}
{table.getPageCount()}
</div>
<div className="ml-auto flex items-center gap-2 lg:ml-0">
Expand Down
40 changes: 21 additions & 19 deletions apps/v4/app/(app)/examples/tasks/components/columns.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
"use client"

import { type ColumnDef } from "@tanstack/react-table"
import { createColumnHelper } from "@tanstack/react-table"

import { Badge } from "@/registry/new-york-v4/ui/badge"
import { Checkbox } from "@/registry/new-york-v4/ui/checkbox"

import { labels, priorities, statuses } from "../data/data"
import { type Task } from "../data/schema"
import { DataTableColumnHeader } from "./data-table-column-header"
import { type TasksTableFeatures } from "./data-table-features"
import { DataTableRowActions } from "./data-table-row-actions"

export const columns: ColumnDef<Task>[] = [
{
// Prefer the column helper over annotating a `ColumnDef[]`: `accessor`/`display`
// infer the value type per column, and `columns()` preserves those types so the
// table, cells, and headers stay fully typed.
const columnHelper = createColumnHelper<TasksTableFeatures, Task>()

export const columns = columnHelper.columns([
columnHelper.display({
id: "select",
header: ({ table }) => (
<Checkbox
Expand All @@ -34,18 +40,16 @@ export const columns: ColumnDef<Task>[] = [
),
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "id",
}),
columnHelper.accessor("id", {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Task" />
),
cell: ({ row }) => <div className="w-[80px]">{row.getValue("id")}</div>,
enableSorting: false,
enableHiding: false,
},
{
accessorKey: "title",
}),
columnHelper.accessor("title", {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Title" />
),
Expand All @@ -61,9 +65,8 @@ export const columns: ColumnDef<Task>[] = [
</div>
)
},
},
{
accessorKey: "status",
}),
columnHelper.accessor("status", {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Status" />
),
Expand All @@ -88,9 +91,8 @@ export const columns: ColumnDef<Task>[] = [
filterFn: (row, id, value) => {
return value.includes(row.getValue(id))
},
},
{
accessorKey: "priority",
}),
columnHelper.accessor("priority", {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Priority" />
),
Expand All @@ -115,9 +117,9 @@ export const columns: ColumnDef<Task>[] = [
filterFn: (row, id, value) => {
return value.includes(row.getValue(id))
},
},
{
}),
columnHelper.display({
id: "actions",
cell: ({ row }) => <DataTableRowActions row={row} />,
},
]
}),
])
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type Column } from "@tanstack/react-table"
import { type Column, type RowData } from "@tanstack/react-table"
import { ArrowDown, ArrowUp, ChevronsUpDown, EyeOff } from "lucide-react"

import { cn } from "@/lib/utils"
Expand All @@ -11,13 +11,15 @@ import {
DropdownMenuTrigger,
} from "@/registry/new-york-v4/ui/dropdown-menu"

interface DataTableColumnHeaderProps<TData, TValue>
import { type TasksTableFeatures } from "./data-table-features"

interface DataTableColumnHeaderProps<TData extends RowData, TValue>
extends React.HTMLAttributes<HTMLDivElement> {
column: Column<TData, TValue>
column: Column<TasksTableFeatures, TData, TValue>
title: string
}

export function DataTableColumnHeader<TData, TValue>({
export function DataTableColumnHeader<TData extends RowData, TValue>({
column,
title,
className,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from "react"
import { type Column } from "@tanstack/react-table"
import { type Column, type RowData } from "@tanstack/react-table"
import { Check, PlusCircle } from "lucide-react"

import { cn } from "@/lib/utils"
Expand All @@ -21,8 +21,10 @@ import {
} from "@/registry/new-york-v4/ui/popover"
import { Separator } from "@/registry/new-york-v4/ui/separator"

interface DataTableFacetedFilterProps<TData, TValue> {
column?: Column<TData, TValue>
import { type TasksTableFeatures } from "./data-table-features"

interface DataTableFacetedFilterProps<TData extends RowData, TValue> {
column?: Column<TasksTableFeatures, TData, TValue>
title?: string
options: {
label: string
Expand All @@ -31,7 +33,7 @@ interface DataTableFacetedFilterProps<TData, TValue> {
}[]
}

export function DataTableFacetedFilter<TData, TValue>({
export function DataTableFacetedFilter<TData extends RowData, TValue>({
column,
title,
options,
Expand Down
Loading
Loading