UNPKG

@tanstack/table-core

Version:

Headless UI for building powerful tables & datagrids for TS/JS.

113 lines (111 loc) 4.05 kB
import { copyInstancePropertiesWithoutMemos, skipFirstRun, tableMemo } from "../../utils.js"; import { table_autoResetPageIndex } from "../row-pagination/rowPaginationFeature.utils.js"; import { column_getCanSort, column_getSortFn } from "./rowSortingFeature.utils.js"; //#region src/features/row-sorting/createSortedRowModel.ts /** * Creates a memoized sorted row model factory. * * The factory reads the relevant table state atoms and options, then returns a row model function used by the table row-model pipeline. * * Register the sorting functions you use with the `sortFns` slot on the * `features` option: * `tableFeatures({ rowSortingFeature, sortedRowModel: createSortedRowModel(), sortFns: { alphanumeric: sortFn_alphanumeric } })`. * Importing individual `sortFn_*` functions keeps unused built-ins out of * your bundle; sorting functions passed directly to the `sortFn` column * option need no registration at all. */ function createSortedRowModel() { return (_table) => { const table = _table; return tableMemo({ feature: "rowSortingFeature", table, fnName: "table.getSortedRowModel", memoDeps: () => [table.atoms.sorting?.get(), table.getPreSortedRowModel()], fn: () => _createSortedRowModel(table), onAfterUpdate: skipFirstRun(() => table_autoResetPageIndex(table)) }); }; } function _createSortedRowModel(table) { const preSortedRowModel = table.getPreSortedRowModel(); const sorting = table.atoms.sorting?.get(); if (!preSortedRowModel.rows.length || !sorting?.length) return preSortedRowModel; const sortedFlatRows = []; const availableSorting = sorting.filter((sort) => { const column = table.getColumn(sort.id); return column ? column_getCanSort(column) : false; }); if (!availableSorting.length) return preSortedRowModel; const resolvedSorting = []; for (let i = 0; i < availableSorting.length; i++) { const sortEntry = availableSorting[i]; const column = table.getColumn(sortEntry.id); if (!column) continue; resolvedSorting.push({ id: sortEntry.id, desc: sortEntry.desc, sortUndefined: column.columnDef.sortUndefined, invertSorting: column.columnDef.invertSorting, sortFn: column_getSortFn(column) }); } const compareRows = (rowA, rowB) => { for (let i = 0; i < resolvedSorting.length; i++) { const sortEntry = resolvedSorting[i]; const sortUndefined = sortEntry.sortUndefined; const isDesc = sortEntry.desc; let sortInt = 0; if (sortUndefined) { const aValue = rowA.getValue(sortEntry.id); const bValue = rowB.getValue(sortEntry.id); const aUndefined = aValue === void 0; const bUndefined = bValue === void 0; if (aUndefined && bUndefined) continue; if (aUndefined || bUndefined) { if (sortUndefined === "first") return aUndefined ? -1 : 1; if (sortUndefined === "last") return aUndefined ? 1 : -1; sortInt = aUndefined ? sortUndefined : -sortUndefined; } } if (sortInt === 0) sortInt = sortEntry.sortFn(rowA, rowB, sortEntry.id); if (sortInt !== 0) { if (isDesc) sortInt *= -1; if (sortEntry.invertSorting) sortInt *= -1; return sortInt; } } return rowA.index - rowB.index; }; const sortData = (rows) => { const sortedData = rows.slice(); sortedData.sort(compareRows); let changed = false; for (let i = 0; i < sortedData.length; i++) { const row = sortedData[i]; if (row !== rows[i]) changed = true; if (row.subRows.length) { const sortedSubRows = sortData(row.subRows); if (sortedSubRows.changed) { const cloned = Object.create(Object.getPrototypeOf(row)); copyInstancePropertiesWithoutMemos(cloned, row); cloned.subRows = sortedSubRows.rows; sortedData[i] = cloned; sortedFlatRows.push(cloned); changed = true; } else sortedFlatRows.push(row); } else sortedFlatRows.push(row); } return { rows: sortedData, changed }; }; return { rows: sortData(preSortedRowModel.rows).rows, flatRows: sortedFlatRows, rowsById: preSortedRowModel.rowsById }; } //#endregion export { createSortedRowModel };