@tanstack/table-core
Version:
Headless UI for building powerful tables & datagrids for TS/JS.
183 lines (181 loc) • 5.99 kB
JavaScript
import { callMemoOrStaticFn, cloneState, makeObjectMap } from "../../utils.js";
import { table_getPinnedVisibleLeafColumns } from "../column-pinning/columnPinningFeature.utils.js";
//#region src/features/column-ordering/columnOrderingFeature.utils.ts
/**
* Creates the default column order state.
*
* The feature default is an empty array, meaning leaf columns keep their natural
* definition order. Reset APIs use this value when `defaultState` is `true`.
*
* @example
* ```ts
* const order = getDefaultColumnOrderState()
* ```
*/
function getDefaultColumnOrderState() {
return [];
}
/**
* Builds column-id to index records for each visible pinning region.
*
* All four regions are built in one pass so a single memo entry serves every
* `column_getIndex` lookup without per-column scans.
*
* @example
* ```ts
* const indexes = table_getColumnIndexes(table)
* ```
*/
function table_getColumnIndexes(table) {
const buildIndexes = (columns) => {
const indexes = makeObjectMap();
for (let i = 0; i < columns.length; i++) indexes[columns[i].id] = i;
return indexes;
};
return {
all: buildIndexes(table_getPinnedVisibleLeafColumns(table)),
center: buildIndexes(table_getPinnedVisibleLeafColumns(table, "center")),
start: buildIndexes(table_getPinnedVisibleLeafColumns(table, "start")),
end: buildIndexes(table_getPinnedVisibleLeafColumns(table, "end"))
};
}
/**
* Finds this column's index within a visible pinning region.
*
* Pass `'start'`, `'center'`, or `'end'` to search that region; omit the
* position to search the full visible leaf column list.
*
* @example
* ```ts
* const index = column_getIndex(column, 'center')
* ```
*/
function column_getIndex(column, position) {
return callMemoOrStaticFn(column.table, "getColumnIndexes", table_getColumnIndexes)[position === "start" ? "start" : position === "end" ? "end" : position === "center" ? "center" : "all"][column.id] ?? -1;
}
/**
* Checks whether this column is the first visible column in a pinning region.
*
* The same `position` semantics as `column_getIndex` apply.
*
* @example
* ```ts
* const isFirst = column_getIsFirstColumn(column, 'start')
* ```
*/
function column_getIsFirstColumn(column, position) {
return table_getPinnedVisibleLeafColumns(column.table, position)[0]?.id === column.id;
}
/**
* Checks whether this column is the last visible column in a pinning region.
*
* The same `position` semantics as `column_getIndex` apply.
*
* @example
* ```ts
* const isLast = column_getIsLastColumn(column, 'end')
* ```
*/
function column_getIsLastColumn(column, position) {
const columns = table_getPinnedVisibleLeafColumns(column.table, position);
return columns[columns.length - 1]?.id === column.id;
}
/**
* Routes a column order updater through the table's column-order change handler.
*
* The updater may be a next ordered id array or a function of the previous
* array, matching the instance `table.setColumnOrder` behavior.
*
* @example
* ```ts
* table_setColumnOrder(table, ['firstName', 'lastName', 'age'])
* ```
*/
function table_setColumnOrder(table, updater) {
table.options.onColumnOrderChange?.(updater);
}
/**
* Resets `columnOrder` to the configured initial state or feature default.
*
* With no argument, the reset clones `table.initialState.columnOrder` when it
* exists. Passing `true` ignores initial state and resets to `[]`.
*
* @example
* ```ts
* table_resetColumnOrder(table)
* table_resetColumnOrder(table, true)
* ```
*/
function table_resetColumnOrder(table, defaultState) {
table_setColumnOrder(table, defaultState ? [] : cloneState(table.initialState.columnOrder ?? []));
}
/**
* Creates the ordering function used to arrange leaf columns.
*
* The returned function applies `state.columnOrder`, preserves unspecified
* columns in their original order, then delegates to grouping rules.
*
* @example
* ```ts
* const orderColumnsForTable = table_getOrderColumnsFn(table)
* ```
*/
function table_getOrderColumnsFn(table) {
const columnOrder = table.atoms.columnOrder?.get();
return (columns) => {
let orderedColumns = [];
if (!columnOrder?.length) orderedColumns = columns;
else {
const remaining = /* @__PURE__ */ new Map();
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
remaining.set(column.id, column);
}
for (let i = 0; i < columnOrder.length; i++) {
const id = columnOrder[i];
const column = remaining.get(id);
if (column) {
orderedColumns.push(column);
remaining.delete(id);
}
}
for (let i = 0; i < columns.length; i++) {
const column = columns[i];
if (remaining.has(column.id)) orderedColumns.push(column);
}
}
return orderColumns(table, orderedColumns);
};
}
/**
* Applies grouped-column placement rules to an already ordered leaf-column list.
*
* `groupedColumnMode: 'remove'` drops grouped columns from the list.
* `groupedColumnMode: 'reorder'` moves grouped columns to the front in grouping
* state order.
*
* @example
* ```ts
* const orderedColumns = orderColumns(table, leafColumns)
* ```
*/
function orderColumns(table, leafColumns) {
const grouping = table.atoms.grouping?.get() ?? [];
const { groupedColumnMode } = table.options;
if (!grouping.length || !groupedColumnMode) return leafColumns;
const nonGroupingColumns = leafColumns.filter((col) => !grouping.includes(col.id));
if (groupedColumnMode === "remove") return nonGroupingColumns;
const leafColumnsById = /* @__PURE__ */ new Map();
for (let i = 0; i < leafColumns.length; i++) {
const col = leafColumns[i];
leafColumnsById.set(col.id, col);
}
const groupingColumns = [];
for (let i = 0; i < grouping.length; i++) {
const col = leafColumnsById.get(grouping[i]);
if (col) groupingColumns.push(col);
}
return [...groupingColumns, ...nonGroupingColumns];
}
//#endregion
export { column_getIndex, column_getIsFirstColumn, column_getIsLastColumn, getDefaultColumnOrderState, orderColumns, table_getColumnIndexes, table_getOrderColumnsFn, table_resetColumnOrder, table_setColumnOrder };