import type { ColumnDef, ColumnFiltersState, PaginationState, RowData, RowSelectionState, SortingState, TableOptions, Updater, } from '@tanstack/vue-table' import { getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useVueTable, } from '@tanstack/vue-table' import type { MaybeRefOrGetter } from 'vue' import { computed, reactive, ref, toValue, type Ref } from 'vue' export interface UseDataTableOptions { data: MaybeRefOrGetter columns: MaybeRefOrGetter[]> pageSize?: number manualPagination?: boolean manualSorting?: boolean getRowId?: TableOptions['getRowId'] } export interface UseDataTableReturn { table: ReturnType> sorting: Ref columnFilters: Ref rowSelection: Ref pagination: Ref setSorting: (updater: Updater) => void setColumnFilters: (updater: Updater) => void setRowSelection: (updater: Updater) => void setPagination: (updater: Updater) => void resetSorting: () => void resetFilters: () => void resetRowSelection: () => void } const applyUpdater = (updater: Updater, previous: TState): TState => { return typeof updater === 'function' ? (updater as (old: TState) => TState)(previous) : updater } export function useDataTable( options: UseDataTableOptions ): UseDataTableReturn { const sorting = ref([]) const columnFilters = ref([]) const rowSelection = ref({}) const pagination = ref({ pageIndex: 0, pageSize: options.pageSize ?? 10, }) const dataRef = computed(() => toValue(options.data)) const columnsRef = computed(() => toValue(options.columns)) const table = useVueTable({ data: dataRef, columns: columnsRef.value, state: reactive({ get sorting() { return sorting.value }, get columnFilters() { return columnFilters.value }, get rowSelection() { return rowSelection.value }, get pagination() { return pagination.value }, }), enableSorting: !options.manualSorting, manualSorting: options.manualSorting ?? false, manualPagination: options.manualPagination ?? false, getRowId: options.getRowId, onSortingChange: updater => { sorting.value = applyUpdater(updater, sorting.value) }, onColumnFiltersChange: updater => { columnFilters.value = applyUpdater(updater, columnFilters.value) }, onRowSelectionChange: updater => { rowSelection.value = applyUpdater(updater, rowSelection.value) }, onPaginationChange: updater => { pagination.value = applyUpdater(updater, pagination.value) }, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: options.manualPagination ? undefined : getPaginationRowModel(), }) return { table, sorting, columnFilters, rowSelection, pagination, setSorting: updater => { sorting.value = applyUpdater(updater, sorting.value) }, setColumnFilters: updater => { columnFilters.value = applyUpdater(updater, columnFilters.value) }, setRowSelection: updater => { rowSelection.value = applyUpdater(updater, rowSelection.value) }, setPagination: updater => { pagination.value = applyUpdater(updater, pagination.value) }, resetSorting: () => { sorting.value = [] }, resetFilters: () => { columnFilters.value = [] }, resetRowSelection: () => { rowSelection.value = {} }, } }