UNPKG

@tanstack/table-core

Version:

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

213 lines (211 loc) 6.38 kB
import { callMemoOrStaticFn, cloneState } from "../../utils.js"; import { row_getIsAllParentsExpanded } from "../row-expanding/rowExpandingFeature.utils.js"; //#region src/features/row-pinning/rowPinningFeature.utils.ts /** * Creates the default row pinning state. * * Both pinning regions start empty. Reset APIs use this value when * `defaultState` is `true`. * * @example * ```ts * const pinning = getDefaultRowPinningState() * ``` */ function getDefaultRowPinningState() { return { top: [], bottom: [] }; } /** * Routes a row pinning updater through the table's row-pinning change handler. * * The updater may be a next `{ top, bottom }` state or a function of the * previous state, matching the instance `table.setRowPinning` behavior. * * @example * ```ts * table_setRowPinning(table, (old) => ({ ...old, top: [rowId] })) * ``` */ function table_setRowPinning(table, updater) { table.options.onRowPinningChange?.(updater); } /** * Resets `rowPinning` to the configured initial state or feature default. * * With no argument, the reset clones `table.initialState.rowPinning` when it * exists. Passing `true` ignores initial state and resets to empty top/bottom * arrays. * * @example * ```ts * table_resetRowPinning(table) * table_resetRowPinning(table, true) * ``` */ function table_resetRowPinning(table, defaultState) { table_setRowPinning(table, defaultState ? getDefaultRowPinningState() : cloneState(table.initialState.rowPinning ?? getDefaultRowPinningState())); } /** * Checks whether any rows are pinned. * * Omit `position` to check both regions, or pass `'top'`/`'bottom'` to inspect * one region. * * @example * ```ts * const hasPinnedRows = table_getIsSomeRowsPinned(table) * ``` */ function table_getIsSomeRowsPinned(table, position) { const rowPinning = table.atoms.rowPinning?.get(); if (!position) return Boolean(rowPinning?.top.length || rowPinning?.bottom.length); return Boolean(rowPinning?.[position].length); } function table_getPinnedRows(table, position) { const visibleRows = table.getRowModel().rows; const pinnedRowIds = table.atoms.rowPinning?.get()?.[position] ?? []; const keepPinnedRows = table.options.keepPinnedRows ?? true; const result = []; for (let i = 0; i < pinnedRowIds.length; i++) { const rowId = pinnedRowIds[i]; let row; if (keepPinnedRows) { const fullRow = table.getPrePaginatedRowModel().rowsById[rowId] ?? table.getCoreRowModel().rowsById[rowId]; if (fullRow && row_getIsAllParentsExpanded(fullRow)) row = fullRow; } else row = visibleRows.find((r) => r.id === rowId); if (!row) continue; row.position = position; result.push(row); } return result; } /** * Resolves the visible rows pinned to the top region. * * The result follows `state.rowPinning.top` order and marks each row with * `position = 'top'`. * * @example * ```ts * const rows = table_getTopRows(table) * ``` */ function table_getTopRows(table) { return table_getPinnedRows(table, "top"); } /** * Resolves the visible rows pinned to the bottom region. * * The result follows `state.rowPinning.bottom` order and marks each row with * `position = 'bottom'`. * * @example * ```ts * const rows = table_getBottomRows(table) * ``` */ function table_getBottomRows(table) { return table_getPinnedRows(table, "bottom"); } /** * Resolves rows that are not pinned to top or bottom. * * The current row model is filtered by `state.rowPinning.top` and * `state.rowPinning.bottom`. * * @example * ```ts * const rows = table_getCenterRows(table) * ``` */ function table_getCenterRows(table) { const { top, bottom } = table.atoms.rowPinning?.get() ?? getDefaultRowPinningState(); const allRows = table.getRowModel().rows; const topAndBottom = /* @__PURE__ */ new Set([...top, ...bottom]); return allRows.filter((d) => !topAndBottom.has(d.id)); } /** * Checks whether this row can be pinned. * * `options.enableRowPinning` may be a boolean or a row predicate; it defaults * to `true`. * * @example * ```ts * const canPin = row_getCanPin(row) * ``` */ function row_getCanPin(row) { const { enableRowPinning } = row.table.options; if (typeof enableRowPinning === "function") return enableRowPinning(row); return enableRowPinning ?? true; } /** * Reads this row's current pinning region. * * Rows listed in `state.rowPinning.top` return `'top'`, rows listed in * `bottom` return `'bottom'`, and unpinned rows return `false`. * * @example * ```ts * const position = row_getIsPinned(row) * ``` */ function row_getIsPinned(row) { const { top, bottom } = row.table.atoms.rowPinning?.get() ?? getDefaultRowPinningState(); return top.includes(row.id) ? "top" : bottom.includes(row.id) ? "bottom" : false; } /** * Finds this row's visible index within its pinned region. * * Unpinned rows return `-1`. * * @example * ```ts * const index = row_getPinnedIndex(row) * ``` */ function row_getPinnedIndex(row) { const position = row_getIsPinned(row); if (!position) return -1; return (position === "top" ? callMemoOrStaticFn(row.table, "getTopRows", table_getTopRows) : callMemoOrStaticFn(row.table, "getBottomRows", table_getBottomRows)).map(({ id }) => id).indexOf(row.id); } /** * Pins or unpins a row. * * Optional flags let callers include parent rows or leaf rows when updating * the row pinning state. * * @example * ```ts * row_pin(row, 'top') * ``` */ function row_pin(row, position, includeLeafRows, includeParentRows) { const leafRowIds = includeLeafRows ? row.getLeafRows().map(({ id }) => id) : []; const parentRowIds = includeParentRows ? row.getParentRows().map(({ id }) => id) : []; const rowIds = /* @__PURE__ */ new Set([ ...parentRowIds, row.id, ...leafRowIds ]); table_setRowPinning(row.table, (old) => { if (position === "bottom") return { top: old.top.filter((d) => !rowIds.has(d)), bottom: [...old.bottom.filter((d) => !rowIds.has(d)), ...Array.from(rowIds)] }; if (position === "top") return { top: [...old.top.filter((d) => !rowIds.has(d)), ...Array.from(rowIds)], bottom: old.bottom.filter((d) => !rowIds.has(d)) }; return { top: old.top.filter((d) => !rowIds.has(d)), bottom: old.bottom.filter((d) => !rowIds.has(d)) }; }); } //#endregion export { getDefaultRowPinningState, row_getCanPin, row_getIsPinned, row_getPinnedIndex, row_pin, table_getBottomRows, table_getCenterRows, table_getIsSomeRowsPinned, table_getTopRows, table_resetRowPinning, table_setRowPinning };