fix table not re-rendering on column configuration change

This commit is contained in:
jeffvli
2025-12-04 04:07:24 -08:00
parent 7c5dc5bb39
commit b66530f8fd
2 changed files with 420 additions and 457 deletions
@@ -130,312 +130,432 @@ interface VirtualizedTableGridProps {
totalRowCount: number; totalRowCount: number;
} }
const VirtualizedTableGrid = React.memo( const VirtualizedTableGrid = ({
({ activeRowId,
activeRowId, calculatedColumnWidths,
calculatedColumnWidths, CellComponent,
CellComponent, cellPadding,
cellPadding, controls,
controls, data,
data, enableAlternateRowColors,
enableAlternateRowColors, enableColumnReorder,
enableColumnReorder, enableColumnResize,
enableColumnResize, enableDrag,
enableDrag, enableExpansion,
enableExpansion, enableHeader,
enableHeader, enableHorizontalBorders,
enableHorizontalBorders, enableRowHoverHighlight,
enableRowHoverHighlight, enableSelection,
enableSelection, enableVerticalBorders,
enableVerticalBorders, getRowHeight,
getRowHeight, groups,
groups, headerHeight,
headerHeight, internalState,
internalState, itemType,
itemType, mergedRowRef,
mergedRowRef, onRangeChanged,
onRangeChanged, parsedColumns,
parsedColumns, pinnedLeftColumnCount,
pinnedLeftColumnCount, pinnedLeftColumnRef,
pinnedLeftColumnRef, pinnedRightColumnCount,
pinnedRightColumnCount, pinnedRightColumnRef,
pinnedRightColumnRef, pinnedRowCount,
pinnedRowCount, pinnedRowRef,
pinnedRowRef, playerContext,
playerContext, showLeftShadow,
showLeftShadow, showRightShadow,
showRightShadow, showTopShadow,
showTopShadow, size,
size, startRowIndex,
startRowIndex, tableId,
tableId, totalColumnCount,
totalColumnCount, totalRowCount,
totalRowCount, }: VirtualizedTableGridProps) => {
}: VirtualizedTableGridProps) => { const columnWidth = useCallback(
const columnWidth = useCallback( (index: number) => calculatedColumnWidths[index],
(index: number) => calculatedColumnWidths[index], [calculatedColumnWidths],
[calculatedColumnWidths], );
// Calculate pinned column widths for group header positioning
const pinnedLeftColumnWidths = useMemo(() => {
return Array.from({ length: pinnedLeftColumnCount }, (_, i) => columnWidth(i));
}, [pinnedLeftColumnCount, columnWidth]);
const pinnedRightColumnWidths = useMemo(() => {
return Array.from({ length: pinnedRightColumnCount }, (_, i) =>
columnWidth(i + pinnedLeftColumnCount + totalColumnCount),
); );
}, [pinnedRightColumnCount, pinnedLeftColumnCount, totalColumnCount, columnWidth]);
// Calculate pinned column widths for group header positioning // Create data array with group headers inserted as null values
const pinnedLeftColumnWidths = useMemo(() => { // Groups are defined by itemCount, so we calculate indexes based on cumulative item counts
return Array.from({ length: pinnedLeftColumnCount }, (_, i) => columnWidth(i)); const dataWithGroups = useMemo(() => {
}, [pinnedLeftColumnCount, columnWidth]); const result: (null | unknown)[] = enableHeader ? [null] : [];
const pinnedRightColumnWidths = useMemo(() => { if (!groups || groups.length === 0) {
return Array.from({ length: pinnedRightColumnCount }, (_, i) => // No groups, just add all data
columnWidth(i + pinnedLeftColumnCount + totalColumnCount), result.push(...data);
);
}, [pinnedRightColumnCount, pinnedLeftColumnCount, totalColumnCount, columnWidth]);
// Create data array with group headers inserted as null values
// Groups are defined by itemCount, so we calculate indexes based on cumulative item counts
const dataWithGroups = useMemo(() => {
const result: (null | unknown)[] = enableHeader ? [null] : [];
if (!groups || groups.length === 0) {
// No groups, just add all data
result.push(...data);
return result;
}
// Calculate group header indexes based on itemCounts
const groupIndexes: number[] = [];
let cumulativeDataIndex = 0;
const headerOffset = enableHeader ? 1 : 0;
groups.forEach((group, groupIndex) => {
// Group header appears before its items
// Index = header offset + cumulative data index + number of previous group headers
const groupHeaderIndex = headerOffset + cumulativeDataIndex + groupIndex;
groupIndexes.push(groupHeaderIndex);
cumulativeDataIndex += group.itemCount;
});
let dataIndex = 0;
const startIndex = enableHeader ? 1 : 0;
let groupHeaderCount = 0;
// Iterate through the expanded row space (data + group headers)
for (
let rowIndex = startIndex;
rowIndex < startIndex + data.length + groupIndexes.length;
rowIndex++
) {
// Check if this row should have a group header
const expectedGroupIndex = groupIndexes[groupHeaderCount];
if (expectedGroupIndex !== undefined && rowIndex === expectedGroupIndex) {
result.push(null); // Group header row
groupHeaderCount++;
} else if (dataIndex < data.length) {
result.push(data[dataIndex]);
dataIndex++;
}
}
return result; return result;
}, [data, enableHeader, groups]); }
const adjustedRowIndexMap = useMemo(() => { // Calculate group header indexes based on itemCounts
const map = new Map<number, number>(); const groupIndexes: number[] = [];
let cumulativeDataIndex = 0;
const headerOffset = enableHeader ? 1 : 0;
if (!groups || groups.length === 0) { groups.forEach((group, groupIndex) => {
const startIndex = enableHeader ? 1 : 0; // Group header appears before its items
const endIndex = enableHeader ? dataWithGroups.length : dataWithGroups.length; // Index = header offset + cumulative data index + number of previous group headers
for (let rowIndex = startIndex; rowIndex < endIndex; rowIndex++) { const groupHeaderIndex = headerOffset + cumulativeDataIndex + groupIndex;
map.set(rowIndex, enableHeader ? rowIndex : rowIndex + 1); groupIndexes.push(groupHeaderIndex);
} cumulativeDataIndex += group.itemCount;
return map; });
let dataIndex = 0;
const startIndex = enableHeader ? 1 : 0;
let groupHeaderCount = 0;
// Iterate through the expanded row space (data + group headers)
for (
let rowIndex = startIndex;
rowIndex < startIndex + data.length + groupIndexes.length;
rowIndex++
) {
// Check if this row should have a group header
const expectedGroupIndex = groupIndexes[groupHeaderCount];
if (expectedGroupIndex !== undefined && rowIndex === expectedGroupIndex) {
result.push(null); // Group header row
groupHeaderCount++;
} else if (dataIndex < data.length) {
result.push(data[dataIndex]);
dataIndex++;
} }
}
return result;
}, [data, enableHeader, groups]);
const groupIndexes: number[] = []; const adjustedRowIndexMap = useMemo(() => {
let cumulativeDataIndex = 0; const map = new Map<number, number>();
const headerOffset = enableHeader ? 1 : 0;
groups.forEach((group, groupIndex) => {
const groupHeaderIndex = headerOffset + cumulativeDataIndex + groupIndex;
groupIndexes.push(groupHeaderIndex);
cumulativeDataIndex += group.itemCount;
});
let adjustedIndex = 1;
const startIndex = enableHeader ? 0 : 0;
const endIndex = dataWithGroups.length;
if (!groups || groups.length === 0) {
const startIndex = enableHeader ? 1 : 0;
const endIndex = enableHeader ? dataWithGroups.length : dataWithGroups.length;
for (let rowIndex = startIndex; rowIndex < endIndex; rowIndex++) { for (let rowIndex = startIndex; rowIndex < endIndex; rowIndex++) {
if (enableHeader && rowIndex === 0) { map.set(rowIndex, enableHeader ? rowIndex : rowIndex + 1);
// Header row
map.set(rowIndex, 0);
} else if (groupIndexes.includes(rowIndex)) {
// Group header row - don't increment adjustedIndex
map.set(rowIndex, 0);
} else {
// Data row
map.set(rowIndex, adjustedIndex);
adjustedIndex++;
}
} }
return map; return map;
}, [dataWithGroups, enableHeader, groups]); }
const itemProps: TableItemProps = useMemo( const groupIndexes: number[] = [];
() => ({ let cumulativeDataIndex = 0;
activeRowId, const headerOffset = enableHeader ? 1 : 0;
adjustedRowIndexMap,
calculatedColumnWidths,
cellPadding,
columns: parsedColumns,
controls,
data: dataWithGroups,
enableAlternateRowColors,
enableColumnReorder,
enableColumnResize,
enableDrag,
enableExpansion,
enableHeader,
enableHorizontalBorders,
enableRowHoverHighlight,
enableSelection,
enableVerticalBorders,
getRowHeight,
groups,
internalState,
itemType,
pinnedLeftColumnCount,
pinnedLeftColumnWidths,
pinnedRightColumnCount,
pinnedRightColumnWidths,
playerContext,
size,
startRowIndex,
tableId,
}),
[
activeRowId,
adjustedRowIndexMap,
calculatedColumnWidths,
cellPadding,
parsedColumns,
controls,
dataWithGroups,
enableAlternateRowColors,
enableColumnReorder,
enableColumnResize,
enableDrag,
enableExpansion,
enableHeader,
enableHorizontalBorders,
enableRowHoverHighlight,
enableSelection,
enableVerticalBorders,
getRowHeight,
groups,
internalState,
itemType,
pinnedLeftColumnCount,
pinnedLeftColumnWidths,
pinnedRightColumnCount,
pinnedRightColumnWidths,
playerContext,
size,
startRowIndex,
tableId,
],
);
const PinnedRowCell = useCallback( groups.forEach((group, groupIndex) => {
(cellProps: CellComponentProps & TableItemProps) => { const groupHeaderIndex = headerOffset + cumulativeDataIndex + groupIndex;
return ( groupIndexes.push(groupHeaderIndex);
<CellComponent cumulativeDataIndex += group.itemCount;
{...cellProps} });
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount}
/>
);
},
[pinnedLeftColumnCount, CellComponent],
);
const PinnedColumnCell = useCallback( let adjustedIndex = 1;
(cellProps: CellComponentProps & TableItemProps) => { const startIndex = enableHeader ? 0 : 0;
return ( const endIndex = dataWithGroups.length;
<CellComponent {...cellProps} rowIndex={cellProps.rowIndex + pinnedRowCount} />
);
},
[pinnedRowCount, CellComponent],
);
const PinnedRightColumnCell = useCallback( for (let rowIndex = startIndex; rowIndex < endIndex; rowIndex++) {
(cellProps: CellComponentProps & TableItemProps) => { if (enableHeader && rowIndex === 0) {
return ( // Header row
<CellComponent map.set(rowIndex, 0);
{...cellProps} } else if (groupIndexes.includes(rowIndex)) {
columnIndex={ // Group header row - don't increment adjustedIndex
cellProps.columnIndex + pinnedLeftColumnCount + totalColumnCount map.set(rowIndex, 0);
} else {
// Data row
map.set(rowIndex, adjustedIndex);
adjustedIndex++;
}
}
return map;
}, [dataWithGroups, enableHeader, groups]);
const itemProps: TableItemProps = useMemo(
() => ({
activeRowId,
adjustedRowIndexMap,
calculatedColumnWidths,
cellPadding,
columns: parsedColumns,
controls,
data: dataWithGroups,
enableAlternateRowColors,
enableColumnReorder,
enableColumnResize,
enableDrag,
enableExpansion,
enableHeader,
enableHorizontalBorders,
enableRowHoverHighlight,
enableSelection,
enableVerticalBorders,
getRowHeight,
groups,
internalState,
itemType,
pinnedLeftColumnCount,
pinnedLeftColumnWidths,
pinnedRightColumnCount,
pinnedRightColumnWidths,
playerContext,
size,
startRowIndex,
tableId,
}),
[
activeRowId,
adjustedRowIndexMap,
calculatedColumnWidths,
cellPadding,
parsedColumns,
controls,
dataWithGroups,
enableAlternateRowColors,
enableColumnReorder,
enableColumnResize,
enableDrag,
enableExpansion,
enableHeader,
enableHorizontalBorders,
enableRowHoverHighlight,
enableSelection,
enableVerticalBorders,
getRowHeight,
groups,
internalState,
itemType,
pinnedLeftColumnCount,
pinnedLeftColumnWidths,
pinnedRightColumnCount,
pinnedRightColumnWidths,
playerContext,
size,
startRowIndex,
tableId,
],
);
const PinnedRowCell = useCallback(
(cellProps: CellComponentProps & TableItemProps) => {
return (
<CellComponent
{...cellProps}
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount}
/>
);
},
[pinnedLeftColumnCount, CellComponent],
);
const PinnedColumnCell = useCallback(
(cellProps: CellComponentProps & TableItemProps) => {
return <CellComponent {...cellProps} rowIndex={cellProps.rowIndex + pinnedRowCount} />;
},
[pinnedRowCount, CellComponent],
);
const PinnedRightColumnCell = useCallback(
(cellProps: CellComponentProps & TableItemProps) => {
return (
<CellComponent
{...cellProps}
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount + totalColumnCount}
rowIndex={cellProps.rowIndex + pinnedRowCount}
/>
);
},
[pinnedLeftColumnCount, pinnedRowCount, totalColumnCount, CellComponent],
);
const PinnedRightIntersectionCell = useCallback(
(cellProps: CellComponentProps & TableItemProps) => {
return (
<CellComponent
{...cellProps}
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount + totalColumnCount}
/>
);
},
[pinnedLeftColumnCount, totalColumnCount, CellComponent],
);
const RowCell = useCallback(
(cellProps: CellComponentProps<TableItemProps>) => {
return (
<CellComponent
{...cellProps}
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount}
rowIndex={cellProps.rowIndex + pinnedRowCount}
/>
);
},
[pinnedLeftColumnCount, pinnedRowCount, CellComponent],
);
const handleOnCellsRendered = useCallback(
(items: {
columnStartIndex: number;
columnStopIndex: number;
rowStartIndex: number;
rowStopIndex: number;
}) => {
onRangeChanged?.({
startIndex: items.rowStartIndex,
stopIndex: items.rowStopIndex,
});
},
[onRangeChanged],
);
return (
<div className={styles.itemTableContainer}>
<div
className={styles.itemTablePinnedColumnsGridContainer}
style={
{
'--header-height': `${headerHeight}px`,
minWidth: `${Array.from({ length: pinnedLeftColumnCount }, () => 0).reduce(
(a, _, i) => a + columnWidth(i),
0,
)}px`,
} as React.CSSProperties
}
>
{!!(pinnedLeftColumnCount || pinnedRowCount) && (
<div
className={clsx(styles.itemTablePinnedIntersectionGridContainer, {
[styles.withHeader]: enableHeader,
})}
style={{
minHeight: `${Array.from({ length: pinnedRowCount }, () => 0).reduce(
(a, _, i) => a + getRowHeight(i, itemProps),
0,
)}px`,
overflow: 'hidden',
}}
>
<Grid
cellComponent={CellComponent as any}
cellProps={itemProps}
className={styles.noScrollbar}
columnCount={pinnedLeftColumnCount}
columnWidth={columnWidth}
rowCount={pinnedRowCount}
rowHeight={getRowHeight}
/>
</div>
)}
{enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} />
)}
{!!pinnedLeftColumnCount && (
<div
className={styles.itemTablePinnedColumnsContainer}
ref={pinnedLeftColumnRef}
>
<Grid
cellComponent={PinnedColumnCell}
cellProps={itemProps}
className={clsx(styles.noScrollbar, styles.height100)}
columnCount={pinnedLeftColumnCount}
columnWidth={columnWidth}
rowCount={totalRowCount}
rowHeight={(index, cellProps) => {
return getRowHeight(index + pinnedRowCount, cellProps);
}}
/>
</div>
)}
</div>
<div
className={styles.itemTablePinnedRowsContainer}
style={
{
'--header-height': `${headerHeight}px`,
} as React.CSSProperties
}
>
{!!pinnedRowCount && (
<div
className={clsx(styles.itemTablePinnedRowsGridContainer, {
[styles.withHeader]: enableHeader,
})}
ref={pinnedRowRef}
style={
{
'--header-height': `${headerHeight}px`,
minHeight: `${Array.from(
{ length: pinnedRowCount },
() => 0,
).reduce((a, _, i) => a + getRowHeight(i, itemProps), 0)}px`,
overflow: 'hidden',
} as React.CSSProperties
} }
rowIndex={cellProps.rowIndex + pinnedRowCount} >
<Grid
cellComponent={PinnedRowCell}
cellProps={itemProps}
className={styles.noScrollbar}
columnCount={totalColumnCount}
columnWidth={(index) => {
return columnWidth(index + pinnedLeftColumnCount);
}}
rowCount={Array.from({ length: pinnedRowCount }, () => 0).length}
rowHeight={getRowHeight}
/>
</div>
)}
{enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} />
)}
<div className={styles.itemTableGridContainer} ref={mergedRowRef}>
<Grid
cellComponent={RowCell}
cellProps={itemProps}
className={styles.height100}
columnCount={totalColumnCount}
columnWidth={(index) => {
return columnWidth(index + pinnedLeftColumnCount);
}}
onCellsRendered={handleOnCellsRendered}
rowCount={totalRowCount}
rowHeight={(index, cellProps) => {
return getRowHeight(index + pinnedRowCount, cellProps);
}}
/> />
); {pinnedLeftColumnCount > 0 && showLeftShadow && (
}, <div className={styles.itemTableLeftScrollShadow} />
[pinnedLeftColumnCount, pinnedRowCount, totalColumnCount, CellComponent], )}
); {pinnedRightColumnCount > 0 && showRightShadow && (
<div className={styles.itemTableRightScrollShadow} />
const PinnedRightIntersectionCell = useCallback( )}
(cellProps: CellComponentProps & TableItemProps) => { </div>
return ( </div>
<CellComponent {!!pinnedRightColumnCount && (
{...cellProps}
columnIndex={
cellProps.columnIndex + pinnedLeftColumnCount + totalColumnCount
}
/>
);
},
[pinnedLeftColumnCount, totalColumnCount, CellComponent],
);
const RowCell = useCallback(
(cellProps: CellComponentProps<TableItemProps>) => {
return (
<CellComponent
{...cellProps}
columnIndex={cellProps.columnIndex + pinnedLeftColumnCount}
rowIndex={cellProps.rowIndex + pinnedRowCount}
/>
);
},
[pinnedLeftColumnCount, pinnedRowCount, CellComponent],
);
const handleOnCellsRendered = useCallback(
(items: {
columnStartIndex: number;
columnStopIndex: number;
rowStartIndex: number;
rowStopIndex: number;
}) => {
onRangeChanged?.({
startIndex: items.rowStartIndex,
stopIndex: items.rowStopIndex,
});
},
[onRangeChanged],
);
return (
<div className={styles.itemTableContainer}>
<div <div
className={styles.itemTablePinnedColumnsGridContainer} className={styles.itemTablePinnedColumnsGridContainer}
style={ style={
{ {
'--header-height': `${headerHeight}px`, '--header-height': `${headerHeight}px`,
minWidth: `${Array.from( minWidth: `${Array.from(
{ length: pinnedLeftColumnCount }, { length: pinnedRightColumnCount },
() => 0, () => 0,
).reduce((a, _, i) => a + columnWidth(i), 0)}px`, ).reduce(
(a, _, i) =>
a + columnWidth(i + pinnedLeftColumnCount + totalColumnCount),
0,
)}px`,
} as React.CSSProperties } as React.CSSProperties
} }
> >
{!!(pinnedLeftColumnCount || pinnedRowCount) && ( {!!(pinnedRightColumnCount || pinnedRowCount) && (
<div <div
className={clsx(styles.itemTablePinnedIntersectionGridContainer, { className={clsx(styles.itemTablePinnedIntersectionGridContainer, {
[styles.withHeader]: enableHeader, [styles.withHeader]: enableHeader,
@@ -449,11 +569,15 @@ const VirtualizedTableGrid = React.memo(
}} }}
> >
<Grid <Grid
cellComponent={CellComponent as any} cellComponent={PinnedRightIntersectionCell}
cellProps={itemProps} cellProps={itemProps}
className={styles.noScrollbar} className={styles.noScrollbar}
columnCount={pinnedLeftColumnCount} columnCount={pinnedRightColumnCount}
columnWidth={columnWidth} columnWidth={(index) => {
return columnWidth(
index + pinnedLeftColumnCount + totalColumnCount,
);
}}
rowCount={pinnedRowCount} rowCount={pinnedRowCount}
rowHeight={getRowHeight} rowHeight={getRowHeight}
/> />
@@ -462,192 +586,31 @@ const VirtualizedTableGrid = React.memo(
{enableHeader && showTopShadow && ( {enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} /> <div className={styles.itemTableTopScrollShadow} />
)} )}
{!!pinnedLeftColumnCount && ( <div
<div className={styles.itemTablePinnedRightColumnsContainer}
className={styles.itemTablePinnedColumnsContainer} ref={pinnedRightColumnRef}
ref={pinnedLeftColumnRef} >
>
<Grid
cellComponent={PinnedColumnCell}
cellProps={itemProps}
className={clsx(styles.noScrollbar, styles.height100)}
columnCount={pinnedLeftColumnCount}
columnWidth={columnWidth}
rowCount={totalRowCount}
rowHeight={(index, cellProps) => {
return getRowHeight(index + pinnedRowCount, cellProps);
}}
/>
</div>
)}
</div>
<div
className={styles.itemTablePinnedRowsContainer}
style={
{
'--header-height': `${headerHeight}px`,
} as React.CSSProperties
}
>
{!!pinnedRowCount && (
<div
className={clsx(styles.itemTablePinnedRowsGridContainer, {
[styles.withHeader]: enableHeader,
})}
ref={pinnedRowRef}
style={
{
'--header-height': `${headerHeight}px`,
minHeight: `${Array.from(
{ length: pinnedRowCount },
() => 0,
).reduce((a, _, i) => a + getRowHeight(i, itemProps), 0)}px`,
overflow: 'hidden',
} as React.CSSProperties
}
>
<Grid
cellComponent={PinnedRowCell}
cellProps={itemProps}
className={styles.noScrollbar}
columnCount={totalColumnCount}
columnWidth={(index) => {
return columnWidth(index + pinnedLeftColumnCount);
}}
rowCount={Array.from({ length: pinnedRowCount }, () => 0).length}
rowHeight={getRowHeight}
/>
</div>
)}
{enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} />
)}
<div className={styles.itemTableGridContainer} ref={mergedRowRef}>
<Grid <Grid
cellComponent={RowCell} cellComponent={PinnedRightColumnCell}
cellProps={itemProps} cellProps={itemProps}
className={styles.height100} className={clsx(styles.noScrollbar, styles.height100)}
columnCount={totalColumnCount} columnCount={pinnedRightColumnCount}
columnWidth={(index) => { columnWidth={(index) => {
return columnWidth(index + pinnedLeftColumnCount); return columnWidth(
index + pinnedLeftColumnCount + totalColumnCount,
);
}} }}
onCellsRendered={handleOnCellsRendered}
rowCount={totalRowCount} rowCount={totalRowCount}
rowHeight={(index, cellProps) => { rowHeight={(index, cellProps) => {
return getRowHeight(index + pinnedRowCount, cellProps); return getRowHeight(index + pinnedRowCount, cellProps);
}} }}
/> />
{pinnedLeftColumnCount > 0 && showLeftShadow && (
<div className={styles.itemTableLeftScrollShadow} />
)}
{pinnedRightColumnCount > 0 && showRightShadow && (
<div className={styles.itemTableRightScrollShadow} />
)}
</div> </div>
</div> </div>
{!!pinnedRightColumnCount && ( )}
<div </div>
className={styles.itemTablePinnedColumnsGridContainer} );
style={ };
{
'--header-height': `${headerHeight}px`,
minWidth: `${Array.from(
{ length: pinnedRightColumnCount },
() => 0,
).reduce(
(a, _, i) =>
a +
columnWidth(i + pinnedLeftColumnCount + totalColumnCount),
0,
)}px`,
} as React.CSSProperties
}
>
{!!(pinnedRightColumnCount || pinnedRowCount) && (
<div
className={clsx(styles.itemTablePinnedIntersectionGridContainer, {
[styles.withHeader]: enableHeader,
})}
style={{
minHeight: `${Array.from(
{ length: pinnedRowCount },
() => 0,
).reduce((a, _, i) => a + getRowHeight(i, itemProps), 0)}px`,
overflow: 'hidden',
}}
>
<Grid
cellComponent={PinnedRightIntersectionCell}
cellProps={itemProps}
className={styles.noScrollbar}
columnCount={pinnedRightColumnCount}
columnWidth={(index) => {
return columnWidth(
index + pinnedLeftColumnCount + totalColumnCount,
);
}}
rowCount={pinnedRowCount}
rowHeight={getRowHeight}
/>
</div>
)}
{enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} />
)}
<div
className={styles.itemTablePinnedRightColumnsContainer}
ref={pinnedRightColumnRef}
>
<Grid
cellComponent={PinnedRightColumnCell}
cellProps={itemProps}
className={clsx(styles.noScrollbar, styles.height100)}
columnCount={pinnedRightColumnCount}
columnWidth={(index) => {
return columnWidth(
index + pinnedLeftColumnCount + totalColumnCount,
);
}}
rowCount={totalRowCount}
rowHeight={(index, cellProps) => {
return getRowHeight(index + pinnedRowCount, cellProps);
}}
/>
</div>
</div>
)}
</div>
);
},
(prevProps, nextProps) => {
const prevColumnIds = prevProps.parsedColumns.map((col) => col.id).join(',');
const nextColumnIds = nextProps.parsedColumns.map((col) => col.id).join(',');
const columnWidthsEqual = prevProps.calculatedColumnWidths.every(
(width, index) => width === nextProps.calculatedColumnWidths[index],
);
if (prevColumnIds !== nextColumnIds) {
return false;
}
return (
columnWidthsEqual &&
prevProps.activeRowId === nextProps.activeRowId &&
prevProps.data === nextProps.data &&
prevProps.size === nextProps.size &&
prevProps.startRowIndex === nextProps.startRowIndex &&
prevProps.enableVerticalBorders === nextProps.enableVerticalBorders &&
prevProps.enableHorizontalBorders === nextProps.enableHorizontalBorders &&
prevProps.enableRowHoverHighlight === nextProps.enableRowHoverHighlight &&
prevProps.enableAlternateRowColors === nextProps.enableAlternateRowColors &&
prevProps.pinnedLeftColumnCount === nextProps.pinnedLeftColumnCount &&
prevProps.pinnedRightColumnCount === nextProps.pinnedRightColumnCount &&
prevProps.totalColumnCount === nextProps.totalColumnCount &&
prevProps.totalRowCount === nextProps.totalRowCount
);
},
);
VirtualizedTableGrid.displayName = 'VirtualizedTableGrid'; VirtualizedTableGrid.displayName = 'VirtualizedTableGrid';
@@ -774,7 +774,7 @@ const TableColumnItem = memo(
postProcess: 'sentenceCase', postProcess: 'sentenceCase',
}), }),
}} }}
variant={item.align === 'end' ? 'filled' : 'subtle'} variant={item.align === 'end' ? 'outline' : 'subtle'}
/> />
</ActionIconGroup> </ActionIconGroup>
<NumberInput <NumberInput