@tanstack/table-core
Version:
Headless UI for building powerful tables & datagrids for TS/JS.
183 lines (181 loc) • 5.33 kB
JavaScript
import { cloneState, hasOwn } from "../../utils.js";
//#region src/features/column-grouping/columnGroupingFeature.utils.ts
/**
* Creates the default grouping state.
*
* The feature default is an empty array, meaning no columns are grouped. Reset
* APIs use this value when `defaultState` is `true`.
*
* @example
* ```ts
* const grouping = getDefaultGroupingState()
* ```
*/
function getDefaultGroupingState() {
return [];
}
/**
* Adds or removes this column id from the grouping state.
*
* Existing grouped columns keep their order. A column already present in
* `state.grouping` is removed; otherwise it is appended.
*
* @example
* ```ts
* column_toggleGrouping(column)
* ```
*/
function column_toggleGrouping(column) {
table_setGrouping(column.table, (old) => {
if (old.includes(column.id)) return old.filter((d) => d !== column.id);
return [...old, column.id];
});
}
/**
* Checks whether this column can be used for grouping.
*
* Grouping must be enabled at the column and table level, and the column must
* either have an accessor or provide `getGroupingValue`.
*
* @example
* ```ts
* const canGroup = column_getCanGroup(column)
* ```
*/
function column_getCanGroup(column) {
return (column.columnDef.enableGrouping ?? true) && (column.table.options.enableGrouping ?? true) && (!!column.accessorFn || !!column.columnDef.getGroupingValue);
}
/**
* Checks whether this column id is present in `state.grouping`.
*
* The result only reflects grouping state, not whether the grouped row model has
* been calculated yet.
*
* @example
* ```ts
* const isGrouped = column_getIsGrouped(column)
* ```
*/
function column_getIsGrouped(column) {
return !!column.table.atoms.grouping?.get()?.includes(column.id);
}
/**
* Finds this column's position in the ordered grouping state.
*
* The result is `-1` when the column is not grouped.
*
* @example
* ```ts
* const index = column_getGroupedIndex(column)
* ```
*/
function column_getGroupedIndex(column) {
return column.table.atoms.grouping?.get()?.indexOf(column.id) ?? -1;
}
/**
* Creates a header/control handler that toggles grouping for this column.
*
* The handler is a no-op when `column_getCanGroup(column)` is false.
*
* @example
* ```ts
* const onClick = column_getToggleGroupingHandler(column)
* ```
*/
function column_getToggleGroupingHandler(column) {
const canGroup = column_getCanGroup(column);
return () => {
if (!canGroup) return;
column_toggleGrouping(column);
};
}
/**
* Routes a grouping updater through the table's grouping change handler.
*
* The updater may be a next `GroupingState` array or a function of the previous
* grouping state, matching the instance `table.setGrouping` behavior.
*
* @example
* ```ts
* table_setGrouping(table, (old) => [...old, 'status'])
* ```
*/
function table_setGrouping(table, updater) {
table.options.onGroupingChange?.(updater);
}
/**
* Resets `grouping` to the configured initial state or feature default.
*
* With no argument, the reset clones `table.initialState.grouping` when it
* exists. Passing `true` ignores initial state and resets to `[]`.
*
* @example
* ```ts
* table_resetGrouping(table)
* table_resetGrouping(table, true)
* ```
*/
function table_resetGrouping(table, defaultState) {
table_setGrouping(table, defaultState ? [] : cloneState(table.initialState.grouping ?? []));
}
/**
* Checks whether this row was created as a grouped row.
*
* Grouped rows carry a `groupingColumnId`; ordinary leaf rows do not.
*
* @example
* ```ts
* const isGrouped = row_getIsGrouped(row)
* ```
*/
function row_getIsGrouped(row) {
return !!row.groupingColumnId;
}
/**
* Reads and caches this row's grouping value for a column.
*
* `columnDef.getGroupingValue` wins when provided; otherwise the normal row
* accessor value is used.
*
* @example
* ```ts
* const groupValue = row_getGroupingValue(row, 'status')
* ```
*/
function row_getGroupingValue(row, columnId) {
if (row._groupingValuesCache && hasOwn(row._groupingValuesCache, columnId)) return row._groupingValuesCache[columnId];
const column = row.table.getColumn(columnId);
if (!column.columnDef.getGroupingValue) return row.getValue(columnId);
if (row._groupingValuesCache) row._groupingValuesCache[columnId] = column.columnDef.getGroupingValue(row.original, row.index, row);
return row._groupingValuesCache?.[columnId];
}
/**
* Checks whether this cell represents the grouped column for a grouped row.
*
* This is the cell that usually renders the grouped value and expansion control.
*
* @example
* ```ts
* const isGroupedCell = cell_getIsGrouped(cell)
* ```
*/
function cell_getIsGrouped(cell) {
const row = cell.row;
return column_getIsGrouped(cell.column) && cell.column.id === row.groupingColumnId;
}
/**
* Checks whether this cell is a placeholder hidden by grouping.
*
* Placeholder cells belong to grouped columns other than the row's active
* grouping column.
*
* @example
* ```ts
* const isPlaceholder = cell_getIsPlaceholder(cell)
* ```
*/
function cell_getIsPlaceholder(cell) {
return !cell_getIsGrouped(cell) && column_getIsGrouped(cell.column);
}
//#endregion
export { cell_getIsGrouped, cell_getIsPlaceholder, column_getCanGroup, column_getGroupedIndex, column_getIsGrouped, column_getToggleGroupingHandler, column_toggleGrouping, getDefaultGroupingState, row_getGroupingValue, row_getIsGrouped, table_resetGrouping, table_setGrouping };