Add stickyHeader prop to table component

This commit is contained in:
jeffvli 2023-07-21 17:53:54 -07:00
parent 92d7560362
commit 9d18384b2d
2 changed files with 93 additions and 67 deletions

View File

@ -1,42 +1,54 @@
import { useEffect, useRef } from 'react';
import { useInView } from 'framer-motion';
import { useEffect, useRef } from 'react';
import { useWindowSettings } from '/@/renderer/store/settings.store';
import { Platform } from '/@/renderer/types';
export const useFixedTableHeader = () => {
const intersectRef = useRef<HTMLDivElement | null>(null);
export const useFixedTableHeader = ({ enabled }: { enabled: boolean }) => {
const tableHeaderRef = useRef<HTMLDivElement | null>(null);
const tableContainerRef = useRef<HTMLDivElement | null>(null);
const { windowBarStyle } = useWindowSettings();
const isNotPastTableIntersection = useInView(intersectRef, {
margin:
windowBarStyle === Platform.WEB || windowBarStyle === Platform.LINUX
? '-68px 0px 0px 0px'
: '-98px 0px 0px 0px',
const topMargin =
windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS
? '-128px'
: '-98px';
const isTableHeaderInView = useInView(tableHeaderRef, {
margin: `${topMargin} 0px 0px 0px`,
});
const tableInView = useInView(tableContainerRef, {
margin: '-128px 0px 0px 0px',
const isTableInView = useInView(tableContainerRef, {
margin: `${topMargin} 0px 0px 0px`,
});
useEffect(() => {
if (!enabled) {
return;
}
const header = document.querySelector('main .ag-header');
const root = document.querySelector('main .ag-root');
if (isNotPastTableIntersection || !tableInView) {
if (windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS) {
header?.classList.remove('window-frame');
}
header?.classList.remove('ag-header-fixed');
root?.classList.remove('ag-header-fixed-margin');
} else {
if (!isTableHeaderInView && isTableInView) {
if (windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS) {
header?.classList.add('window-frame');
}
header?.classList.add('ag-header-fixed');
root?.classList.add('ag-header-fixed-margin');
} else if (!isTableInView) {
if (windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS) {
header?.classList.remove('window-frame');
}
header?.classList.remove('ag-header-fixed');
root?.classList.remove('ag-header-fixed-margin');
} else if (isTableHeaderInView) {
if (windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS) {
header?.classList.remove('window-frame');
}
header?.classList.remove('ag-header-fixed');
root?.classList.remove('ag-header-fixed-margin');
}
}, [isNotPastTableIntersection, tableInView, windowBarStyle]);
}, [enabled, isTableHeaderInView, isTableInView, windowBarStyle]);
return { intersectRef, tableContainerRef };
return { tableContainerRef, tableHeaderRef };
};

View File

@ -35,6 +35,7 @@ import { RatingCell } from '/@/renderer/components/virtual-table/cells/rating-ce
import { TablePagination } from '/@/renderer/components/virtual-table/table-pagination';
import { ActionsCell } from '/@/renderer/components/virtual-table/cells/actions-cell';
import { TitleCell } from '/@/renderer/components/virtual-table/cells/title-cell';
import { useFixedTableHeader } from '/@/renderer/components/virtual-table/hooks/use-fixed-table-header';
export * from './table-config-dropdown';
export * from './table-pagination';
@ -43,12 +44,18 @@ export * from './hooks/use-click-outside-deselect';
export * from './utils';
const TableWrapper = styled.div`
position: relative;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
`;
const DummyHeader = styled.div<{ height?: number }>`
position: absolute;
height: ${({ height }) => height || 36}px};
`;
dayjs.extend(relativeTime);
const tableColumns: { [key: string]: ColDef } = {
@ -371,6 +378,7 @@ export interface VirtualTableProps extends AgGridReactProps {
pagination: TablePaginationType;
setPagination: any;
};
stickyHeader?: boolean;
transparentHeader?: boolean;
}
@ -380,6 +388,7 @@ export const VirtualTable = forwardRef(
autoFitColumns,
deselectOnClickOutside,
autoHeight,
stickyHeader,
transparentHeader,
onColumnMoved,
onNewColumnsLoaded,
@ -467,55 +476,60 @@ export const VirtualTable = forwardRef(
[autoFitColumns],
);
const { tableHeaderRef, tableContainerRef } = useFixedTableHeader({
enabled: stickyHeader || false,
});
const mergedWrapperRef = useMergedRef(deselectRef, tableContainerRef);
return (
<>
<TableWrapper
ref={deselectRef}
className={
transparentHeader
? 'ag-header-transparent ag-theme-alpine-dark'
: 'ag-theme-alpine-dark'
}
>
<AgGridReact
ref={mergedRef}
animateRows
maintainColumnOrder
suppressAsyncEvents
suppressContextMenu
suppressCopyRowsToClipboard
suppressMoveWhenRowDragging
suppressPaginationPanel
suppressScrollOnNewData
blockLoadDebounceMillis={200}
cacheBlockSize={300}
cacheOverflowSize={1}
defaultColDef={defaultColumnDefs}
enableCellChangeFlash={false}
headerHeight={36}
rowBuffer={30}
rowSelection="multiple"
{...rest}
onColumnMoved={handleColumnMoved}
onGridReady={handleGridReady}
onGridSizeChanged={handleGridSizeChanged}
onModelUpdated={handleModelUpdated}
onNewColumnsLoaded={handleNewColumnsLoaded}
/>
{paginationProps && (
<AnimatePresence
presenceAffectsLayout
initial={false}
mode="wait"
>
<TablePagination
{...paginationProps}
tableRef={tableRef}
/>
</AnimatePresence>
)}
</TableWrapper>
</>
<TableWrapper
ref={mergedWrapperRef}
className={
transparentHeader
? 'ag-theme-alpine-dark ag-header-transparent'
: 'ag-theme-alpine-dark'
}
>
<DummyHeader ref={tableHeaderRef} />
<AgGridReact
ref={mergedRef}
animateRows
maintainColumnOrder
suppressAsyncEvents
suppressContextMenu
suppressCopyRowsToClipboard
suppressMoveWhenRowDragging
suppressPaginationPanel
suppressScrollOnNewData
blockLoadDebounceMillis={200}
cacheBlockSize={300}
cacheOverflowSize={1}
defaultColDef={defaultColumnDefs}
enableCellChangeFlash={false}
headerHeight={36}
rowBuffer={30}
rowSelection="multiple"
{...rest}
onColumnMoved={handleColumnMoved}
onGridReady={handleGridReady}
onGridSizeChanged={handleGridSizeChanged}
onModelUpdated={handleModelUpdated}
onNewColumnsLoaded={handleNewColumnsLoaded}
/>
{paginationProps && (
<AnimatePresence
presenceAffectsLayout
initial={false}
mode="wait"
>
<TablePagination
{...paginationProps}
tableRef={tableRef}
/>
</AnimatePresence>
)}
</TableWrapper>
);
},
);