add shadow to table header

This commit is contained in:
jeffvli
2025-11-14 11:51:04 -08:00
parent a03ea3b4d8
commit 3f4148258f
2 changed files with 108 additions and 25 deletions
@@ -27,6 +27,7 @@
}
.item-table-pinned-rows-container {
position: relative;
display: flex;
flex: 1 1 auto;
flex-direction: column;
@@ -41,10 +42,21 @@
}
.item-table-pinned-rows-grid-container.with-header {
border-bottom: 1px solid var(--theme-colors-border);
position: relative;
}
.item-table-pinned-rows-grid-container.with-header::after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 1px;
content: '';
background-color: var(--theme-colors-border);
}
.item-table-pinned-columns-grid-container {
position: relative;
display: flex;
flex: 0 1 auto;
flex-direction: column;
@@ -58,7 +70,17 @@
}
.item-table-pinned-intersection-grid-container.with-header {
border-bottom: 1px solid var(--theme-colors-border);
position: relative;
}
.item-table-pinned-intersection-grid-container.with-header::after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 1px;
content: '';
background-color: var(--theme-colors-border);
}
.item-table-pinned-columns-container {
@@ -130,3 +152,19 @@
transparent 100%
);
}
.item-table-top-scroll-shadow {
position: absolute;
top: var(--header-height, 40px);
right: 0;
left: 0;
z-index: 1;
height: 8px;
pointer-events: none;
background: linear-gradient(
to bottom,
rgb(0 0 0 / 50%) 0%,
rgb(0 0 0 / 5%) 50%,
transparent 100%
);
}
@@ -115,6 +115,7 @@ interface VirtualizedTableGridProps {
playerContext: PlayerContext;
showLeftShadow: boolean;
showRightShadow: boolean;
showTopShadow: boolean;
size: 'compact' | 'default' | 'large';
tableId: string;
totalColumnCount: number;
@@ -154,6 +155,7 @@ const VirtualizedTableGrid = React.memo(
playerContext,
showLeftShadow,
showRightShadow,
showTopShadow,
size,
tableId,
totalColumnCount,
@@ -293,12 +295,15 @@ const VirtualizedTableGrid = React.memo(
<div className={styles.itemTableContainer}>
<div
className={styles.itemTablePinnedColumnsGridContainer}
style={{
minWidth: `${Array.from({ length: pinnedLeftColumnCount }, () => 0).reduce(
(a, _, i) => a + columnWidth(i),
0,
)}px`,
}}
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
@@ -322,9 +327,11 @@ const VirtualizedTableGrid = React.memo(
rowCount={pinnedRowCount}
rowHeight={getRowHeight}
/>
{enableHeader && <div className={styles.itemTablePinnedHeaderShadow} />}
</div>
)}
{enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} />
)}
{!!pinnedLeftColumnCount && (
<div
className={styles.itemTablePinnedColumnsContainer}
@@ -344,7 +351,14 @@ const VirtualizedTableGrid = React.memo(
</div>
)}
</div>
<div className={styles.itemTablePinnedRowsContainer}>
<div
className={styles.itemTablePinnedRowsContainer}
style={
{
'--header-height': `${headerHeight}px`,
} as React.CSSProperties
}
>
{!!pinnedRowCount && (
<div
className={clsx(styles.itemTablePinnedRowsGridContainer, {
@@ -373,9 +387,11 @@ const VirtualizedTableGrid = React.memo(
rowCount={Array.from({ length: pinnedRowCount }, () => 0).length}
rowHeight={getRowHeight}
/>
{enableHeader && <div className={styles.itemTablePinnedHeaderShadow} />}
</div>
)}
{enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} />
)}
<div className={styles.itemTableGridContainer} ref={mergedRowRef}>
<Grid
cellComponent={RowCell}
@@ -402,16 +418,20 @@ const VirtualizedTableGrid = React.memo(
{!!pinnedRightColumnCount && (
<div
className={styles.itemTablePinnedColumnsGridContainer}
style={{
minWidth: `${Array.from(
{ length: pinnedRightColumnCount },
() => 0,
).reduce(
(a, _, i) =>
a + columnWidth(i + pinnedLeftColumnCount + totalColumnCount),
0,
)}px`,
}}
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
@@ -439,11 +459,11 @@ const VirtualizedTableGrid = React.memo(
rowCount={pinnedRowCount}
rowHeight={getRowHeight}
/>
{enableHeader && (
<div className={styles.itemTablePinnedHeaderShadow} />
)}
</div>
)}
{enableHeader && showTopShadow && (
<div className={styles.itemTableTopScrollShadow} />
)}
<div
className={styles.itemTablePinnedRightColumnsContainer}
ref={pinnedRightColumnRef}
@@ -523,7 +543,7 @@ interface ItemTableListProps {
onColumnReordered?: (
columnIdFrom: TableColumn,
columnIdTo: TableColumn,
edge: 'top' | 'bottom' | 'left' | 'right' | null,
edge: 'bottom' | 'left' | 'right' | 'top' | null,
) => void;
onColumnResized?: (columnId: TableColumn, width: number) => void;
onRangeChanged?: (range: { startIndex: number; stopIndex: number }) => void;
@@ -659,6 +679,7 @@ export const ItemTableList = ({
const mergedRowRef = useMergedRef(rowRef, scrollContainerRef);
const [showLeftShadow, setShowLeftShadow] = useState(false);
const [showRightShadow, setShowRightShadow] = useState(false);
const [showTopShadow, setShowTopShadow] = useState(false);
const handleRef = useRef<ItemListHandle | null>(null);
const containerFocusRef = useRef<HTMLDivElement | null>(null);
@@ -1181,6 +1202,29 @@ export const ItemTableList = ({
};
}, [pinnedLeftColumnCount, pinnedRightColumnCount]);
// Handle top shadow visibility based on vertical scroll
useEffect(() => {
const row = rowRef.current?.childNodes[0] as HTMLDivElement;
if (!row || !enableHeader) {
setShowTopShadow(false);
return;
}
const checkScrollPosition = () => {
const scrollTop = row.scrollTop;
setShowTopShadow(scrollTop > 0);
};
checkScrollPosition();
row.addEventListener('scroll', checkScrollPosition);
return () => {
row.removeEventListener('scroll', checkScrollPosition);
};
}, [enableHeader]);
const getRowHeight = useCallback(
(index: number, cellProps: TableItemProps) => {
const height = size === 'compact' ? 40 : size === 'large' ? 88 : 64;
@@ -1427,6 +1471,7 @@ export const ItemTableList = ({
playerContext={playerContext}
showLeftShadow={showLeftShadow}
showRightShadow={showRightShadow}
showTopShadow={showTopShadow}
size={size}
tableId={tableId}
totalColumnCount={totalColumnCount}