UNPKG

material-react-table

Version:

A fully featured Material UI V6 implementation of TanStack React Table V8, written from the ground up in TypeScript.

261 lines (234 loc) 7.18 kB
import { type ChangeEvent, type MouseEvent } from 'react'; import { rankGlobalFuzzy } from '../fns/sortingFns'; import { type MRT_Row, type MRT_RowData, type MRT_TableInstance, } from '../types'; import { parseFromValuesOrFunc } from './utils'; export const getMRT_Rows = <TData extends MRT_RowData>( table: MRT_TableInstance<TData>, all?: boolean, ): MRT_Row<TData>[] => { const { getCenterRows, getPrePaginationRowModel, getRowModel, getState, getTopRows, options: { createDisplayMode, enablePagination, enableRowPinning, manualPagination, positionCreatingRow, rowPinningDisplayMode, }, } = table; const { creatingRow, pagination } = getState(); const isRankingRows = getIsRankingRows(table); let rows: MRT_Row<TData>[] = []; if (!isRankingRows) { rows = !enableRowPinning || rowPinningDisplayMode?.includes('sticky') ? all ? getPrePaginationRowModel().rows : getRowModel().rows : getCenterRows(); } else { // fuzzy ranking adjustments rows = getPrePaginationRowModel().rows.sort((a, b) => rankGlobalFuzzy(a, b), ); if (enablePagination && !manualPagination && !all) { const start = pagination.pageIndex * pagination.pageSize; rows = rows.slice(start, start + pagination.pageSize); } if (enableRowPinning && !rowPinningDisplayMode?.includes('sticky')) { // "re-center-ize" the rows (no top or bottom pinned rows unless sticky) rows = rows.filter((row) => !row.getIsPinned()); } } // row pinning adjustments if (enableRowPinning && rowPinningDisplayMode?.includes('sticky')) { const centerPinnedRowIds = rows .filter((row) => row.getIsPinned()) .map((r) => r.id); rows = [ ...getTopRows().filter((row) => !centerPinnedRowIds.includes(row.id)), ...rows, ]; } // blank inserted creating row adjustments if ( positionCreatingRow !== undefined && creatingRow && createDisplayMode === 'row' ) { const creatingRowIndex = !isNaN(+positionCreatingRow) ? +positionCreatingRow : positionCreatingRow === 'top' ? 0 : rows.length; rows = [ ...rows.slice(0, creatingRowIndex), creatingRow, ...rows.slice(creatingRowIndex), ]; } return rows; }; export const getCanRankRows = <TData extends MRT_RowData>( table: MRT_TableInstance<TData>, ) => { const { getState, options: { enableGlobalFilterRankedResults, manualExpanding, manualFiltering, manualGrouping, manualSorting, }, } = table; const { expanded, globalFilterFn } = getState(); return ( !manualExpanding && !manualFiltering && !manualGrouping && !manualSorting && enableGlobalFilterRankedResults && globalFilterFn === 'fuzzy' && expanded !== true && !Object.values(expanded).some(Boolean) ); }; export const getIsRankingRows = <TData extends MRT_RowData>( table: MRT_TableInstance<TData>, ) => { const { globalFilter, sorting } = table.getState(); return ( getCanRankRows(table) && globalFilter && !Object.values(sorting).some(Boolean) ); }; export const getIsRowSelected = <TData extends MRT_RowData>({ row, table, }: { row: MRT_Row<TData>; table: MRT_TableInstance<TData>; }) => { const { options: { enableRowSelection }, } = table; return ( row.getIsSelected() || (parseFromValuesOrFunc(enableRowSelection, row) && row.getCanSelectSubRows() && row.getIsAllSubRowsSelected()) ); }; export const getMRT_RowSelectionHandler = <TData extends MRT_RowData>({ row, staticRowIndex = 0, table, }: { row: MRT_Row<TData>; staticRowIndex?: number; table: MRT_TableInstance<TData>; }) => ( event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLTableRowElement>, value?: boolean, ) => { const { getState, options: { enableBatchRowSelection, enableMultiRowSelection, enableRowPinning, manualPagination, rowPinningDisplayMode, }, refs: { lastSelectedRowId: lastSelectedRowId }, } = table; const { pagination: { pageIndex, pageSize }, } = getState(); const paginationOffset = manualPagination ? 0 : pageSize * pageIndex; const wasCurrentRowChecked = getIsRowSelected({ row, table }); // toggle selection of this row row.toggleSelected(value ?? !wasCurrentRowChecked); const changedRowIds = new Set<string>([row.id]); // if shift key is pressed, select all rows between last selected and this one if ( enableBatchRowSelection && enableMultiRowSelection && (event as any).nativeEvent.shiftKey && lastSelectedRowId.current !== null ) { const rows = getMRT_Rows(table, true); const lastIndex = rows.findIndex( (r) => r.id === lastSelectedRowId.current, ); if (lastIndex !== -1) { const isLastIndexChecked = getIsRowSelected({ row: rows?.[lastIndex], table, }); const currentIndex = staticRowIndex + paginationOffset; const [start, end] = lastIndex < currentIndex ? [lastIndex, currentIndex] : [currentIndex, lastIndex]; // toggle selection of all rows between last selected and this one // but only if the last selected row is not the same as the current one if (wasCurrentRowChecked !== isLastIndexChecked) { for (let i = start; i <= end; i++) { rows[i].toggleSelected(!wasCurrentRowChecked); changedRowIds.add(rows[i].id); } } } } // record the last selected row id lastSelectedRowId.current = row.id; // if all sub rows were selected, unselect them if (row.getCanSelectSubRows() && row.getIsAllSubRowsSelected()) { row.subRows?.forEach((r) => r.toggleSelected(false)); } if (enableRowPinning && rowPinningDisplayMode?.includes('select')) { changedRowIds.forEach((rowId) => { const rowToTogglePin = table.getRow(rowId); rowToTogglePin.pin( !wasCurrentRowChecked //was not previously pinned or selected ? rowPinningDisplayMode?.includes('bottom') ? 'bottom' : 'top' : false, ); }); } }; export const getMRT_SelectAllHandler = <TData extends MRT_RowData>({ table }: { table: MRT_TableInstance<TData> }) => ( event: ChangeEvent<HTMLInputElement> | MouseEvent<HTMLButtonElement>, value?: boolean, forceAll?: boolean, ) => { const { options: { enableRowPinning, rowPinningDisplayMode, selectAllMode }, refs: { lastSelectedRowId }, } = table; selectAllMode === 'all' || forceAll ? table.toggleAllRowsSelected(value ?? (event as any).target.checked) : table.toggleAllPageRowsSelected(value ?? (event as any).target.checked); if (enableRowPinning && rowPinningDisplayMode?.includes('select')) { table.setRowPinning({ bottom: [], top: [] }); } lastSelectedRowId.current = null; };