@tanstack/table-core
Version:
Headless UI for building powerful tables & datagrids for TS/JS.
271 lines (252 loc) • 12.2 kB
JavaScript
/**
* table-core
*
* Copyright (c) TanStack
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
;
var utils = require('../utils.js');
const debug = 'debugHeaders';
//
function createHeader(table, column, options) {
var _options$id;
const id = (_options$id = options.id) != null ? _options$id : column.id;
let header = {
id,
column,
index: options.index,
isPlaceholder: !!options.isPlaceholder,
placeholderId: options.placeholderId,
depth: options.depth,
subHeaders: [],
colSpan: 0,
rowSpan: 0,
headerGroup: null,
getLeafHeaders: () => {
const leafHeaders = [];
const recurseHeader = h => {
if (h.subHeaders && h.subHeaders.length) {
h.subHeaders.map(recurseHeader);
}
leafHeaders.push(h);
};
recurseHeader(header);
return leafHeaders;
},
getContext: () => ({
table,
header: header,
column
})
};
table._features.forEach(feature => {
feature.createHeader == null || feature.createHeader(header, table);
});
return header;
}
const Headers = {
createTable: table => {
// Header Groups
table.getHeaderGroups = utils.memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.left, table.getState().columnPinning.right], (allColumns, leafColumns, left, right) => {
var _left$map$filter, _right$map$filter;
const leftColumns = (_left$map$filter = left == null ? void 0 : left.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _left$map$filter : [];
const rightColumns = (_right$map$filter = right == null ? void 0 : right.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _right$map$filter : [];
const centerColumns = leafColumns.filter(column => !(left != null && left.includes(column.id)) && !(right != null && right.includes(column.id)));
const headerGroups = buildHeaderGroups(allColumns, [...leftColumns, ...centerColumns, ...rightColumns], table);
return headerGroups;
}, utils.getMemoOptions(table.options, debug, 'getHeaderGroups'));
table.getCenterHeaderGroups = utils.memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.left, table.getState().columnPinning.right], (allColumns, leafColumns, left, right) => {
leafColumns = leafColumns.filter(column => !(left != null && left.includes(column.id)) && !(right != null && right.includes(column.id)));
return buildHeaderGroups(allColumns, leafColumns, table, 'center');
}, utils.getMemoOptions(table.options, debug, 'getCenterHeaderGroups'));
table.getLeftHeaderGroups = utils.memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.left], (allColumns, leafColumns, left) => {
var _left$map$filter2;
const orderedLeafColumns = (_left$map$filter2 = left == null ? void 0 : left.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _left$map$filter2 : [];
return buildHeaderGroups(allColumns, orderedLeafColumns, table, 'left');
}, utils.getMemoOptions(table.options, debug, 'getLeftHeaderGroups'));
table.getRightHeaderGroups = utils.memo(() => [table.getAllColumns(), table.getVisibleLeafColumns(), table.getState().columnPinning.right], (allColumns, leafColumns, right) => {
var _right$map$filter2;
const orderedLeafColumns = (_right$map$filter2 = right == null ? void 0 : right.map(columnId => leafColumns.find(d => d.id === columnId)).filter(Boolean)) != null ? _right$map$filter2 : [];
return buildHeaderGroups(allColumns, orderedLeafColumns, table, 'right');
}, utils.getMemoOptions(table.options, debug, 'getRightHeaderGroups'));
// Footer Groups
table.getFooterGroups = utils.memo(() => [table.getHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, utils.getMemoOptions(table.options, debug, 'getFooterGroups'));
table.getLeftFooterGroups = utils.memo(() => [table.getLeftHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, utils.getMemoOptions(table.options, debug, 'getLeftFooterGroups'));
table.getCenterFooterGroups = utils.memo(() => [table.getCenterHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, utils.getMemoOptions(table.options, debug, 'getCenterFooterGroups'));
table.getRightFooterGroups = utils.memo(() => [table.getRightHeaderGroups()], headerGroups => {
return [...headerGroups].reverse();
}, utils.getMemoOptions(table.options, debug, 'getRightFooterGroups'));
// Flat Headers
table.getFlatHeaders = utils.memo(() => [table.getHeaderGroups()], headerGroups => {
return headerGroups.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, utils.getMemoOptions(table.options, debug, 'getFlatHeaders'));
table.getLeftFlatHeaders = utils.memo(() => [table.getLeftHeaderGroups()], left => {
return left.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, utils.getMemoOptions(table.options, debug, 'getLeftFlatHeaders'));
table.getCenterFlatHeaders = utils.memo(() => [table.getCenterHeaderGroups()], left => {
return left.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, utils.getMemoOptions(table.options, debug, 'getCenterFlatHeaders'));
table.getRightFlatHeaders = utils.memo(() => [table.getRightHeaderGroups()], left => {
return left.map(headerGroup => {
return headerGroup.headers;
}).flat();
}, utils.getMemoOptions(table.options, debug, 'getRightFlatHeaders'));
// Leaf Headers
table.getCenterLeafHeaders = utils.memo(() => [table.getCenterFlatHeaders()], flatHeaders => {
return flatHeaders.filter(header => {
var _header$subHeaders;
return !((_header$subHeaders = header.subHeaders) != null && _header$subHeaders.length);
});
}, utils.getMemoOptions(table.options, debug, 'getCenterLeafHeaders'));
table.getLeftLeafHeaders = utils.memo(() => [table.getLeftFlatHeaders()], flatHeaders => {
return flatHeaders.filter(header => {
var _header$subHeaders2;
return !((_header$subHeaders2 = header.subHeaders) != null && _header$subHeaders2.length);
});
}, utils.getMemoOptions(table.options, debug, 'getLeftLeafHeaders'));
table.getRightLeafHeaders = utils.memo(() => [table.getRightFlatHeaders()], flatHeaders => {
return flatHeaders.filter(header => {
var _header$subHeaders3;
return !((_header$subHeaders3 = header.subHeaders) != null && _header$subHeaders3.length);
});
}, utils.getMemoOptions(table.options, debug, 'getRightLeafHeaders'));
table.getLeafHeaders = utils.memo(() => [table.getLeftHeaderGroups(), table.getCenterHeaderGroups(), table.getRightHeaderGroups()], (left, center, right) => {
var _left$0$headers, _left$, _center$0$headers, _center$, _right$0$headers, _right$;
return [...((_left$0$headers = (_left$ = left[0]) == null ? void 0 : _left$.headers) != null ? _left$0$headers : []), ...((_center$0$headers = (_center$ = center[0]) == null ? void 0 : _center$.headers) != null ? _center$0$headers : []), ...((_right$0$headers = (_right$ = right[0]) == null ? void 0 : _right$.headers) != null ? _right$0$headers : [])].map(header => {
return header.getLeafHeaders();
}).flat();
}, utils.getMemoOptions(table.options, debug, 'getLeafHeaders'));
}
};
function buildHeaderGroups(allColumns, columnsToGroup, table, headerFamily) {
var _headerGroups$0$heade, _headerGroups$;
// Find the max depth of the columns:
// build the leaf column row
// build each buffer row going up
// placeholder for non-existent level
// real column for existing level
let maxDepth = 0;
const findMaxDepth = function (columns, depth) {
if (depth === void 0) {
depth = 1;
}
maxDepth = Math.max(maxDepth, depth);
columns.filter(column => column.getIsVisible()).forEach(column => {
var _column$columns;
if ((_column$columns = column.columns) != null && _column$columns.length) {
findMaxDepth(column.columns, depth + 1);
}
}, 0);
};
findMaxDepth(allColumns);
let headerGroups = [];
const createHeaderGroup = (headersToGroup, depth) => {
// The header group we are creating
const headerGroup = {
depth,
id: [headerFamily, `${depth}`].filter(Boolean).join('_'),
headers: []
};
// The parent columns we're going to scan next
const pendingParentHeaders = [];
// Scan each column for parents
headersToGroup.forEach(headerToGroup => {
// What is the latest (last) parent column?
const latestPendingParentHeader = [...pendingParentHeaders].reverse()[0];
const isLeafHeader = headerToGroup.column.depth === headerGroup.depth;
let column;
let isPlaceholder = false;
if (isLeafHeader && headerToGroup.column.parent) {
// The parent header is new
column = headerToGroup.column.parent;
} else {
// The parent header is repeated
column = headerToGroup.column;
isPlaceholder = true;
}
if (latestPendingParentHeader && (latestPendingParentHeader == null ? void 0 : latestPendingParentHeader.column) === column) {
// This column is repeated. Add it as a sub header to the next batch
latestPendingParentHeader.subHeaders.push(headerToGroup);
} else {
// This is a new header. Let's create it
const header = createHeader(table, column, {
id: [headerFamily, depth, column.id, headerToGroup == null ? void 0 : headerToGroup.id].filter(Boolean).join('_'),
isPlaceholder,
placeholderId: isPlaceholder ? `${pendingParentHeaders.filter(d => d.column === column).length}` : undefined,
depth,
index: pendingParentHeaders.length
});
// Add the headerToGroup as a subHeader of the new header
header.subHeaders.push(headerToGroup);
// Add the new header to the pendingParentHeaders to get grouped
// in the next batch
pendingParentHeaders.push(header);
}
headerGroup.headers.push(headerToGroup);
headerToGroup.headerGroup = headerGroup;
});
headerGroups.push(headerGroup);
if (depth > 0) {
createHeaderGroup(pendingParentHeaders, depth - 1);
}
};
const bottomHeaders = columnsToGroup.map((column, index) => createHeader(table, column, {
depth: maxDepth,
index
}));
createHeaderGroup(bottomHeaders, maxDepth - 1);
headerGroups.reverse();
// headerGroups = headerGroups.filter(headerGroup => {
// return !headerGroup.headers.every(header => header.isPlaceholder)
// })
const recurseHeadersForSpans = headers => {
const filteredHeaders = headers.filter(header => header.column.getIsVisible());
return filteredHeaders.map(header => {
let colSpan = 0;
let rowSpan = 0;
let childRowSpans = [0];
if (header.subHeaders && header.subHeaders.length) {
childRowSpans = [];
recurseHeadersForSpans(header.subHeaders).forEach(_ref => {
let {
colSpan: childColSpan,
rowSpan: childRowSpan
} = _ref;
colSpan += childColSpan;
childRowSpans.push(childRowSpan);
});
} else {
colSpan = 1;
}
const minChildRowSpan = Math.min(...childRowSpans);
rowSpan = rowSpan + minChildRowSpan;
header.colSpan = colSpan;
header.rowSpan = rowSpan;
return {
colSpan,
rowSpan
};
});
};
recurseHeadersForSpans((_headerGroups$0$heade = (_headerGroups$ = headerGroups[0]) == null ? void 0 : _headerGroups$.headers) != null ? _headerGroups$0$heade : []);
return headerGroups;
}
exports.Headers = Headers;
exports.buildHeaderGroups = buildHeaderGroups;
//# sourceMappingURL=headers.js.map