Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
256 changes: 128 additions & 128 deletions src/FixedHolder/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useContext } from '@rc-component/context';
import classNames from 'classnames';
import { fillRef } from 'rc-util/lib/ref';
import * as React from 'react';
import { useMemo } from 'react';
import ColGroup from '../ColGroup';
import TableContext from '../context/TableContext';
import { useContext } from '@rc-component/context';
import type { HeaderProps } from '../Header/Header';
import useRenderTimes from '../hooks/useRenderTimes';
import type { ColumnsType, ColumnType } from '../interface';

function useColumnWidth(colWidths: readonly number[], columCount: number) {
Expand Down Expand Up @@ -38,138 +39,137 @@ export interface FixedHeaderProps<RecordType> extends HeaderProps<RecordType> {
children: (info: HeaderProps<RecordType>) => React.ReactNode;
}

const FixedHolder = React.forwardRef<HTMLDivElement, FixedHeaderProps<unknown>>(
(
{
className,
noData,
columns,
flattenColumns,
colWidths,
columCount,
stickyOffsets,
direction,
fixHeader,
stickyTopOffset,
stickyBottomOffset,
stickyClassName,
onScroll,
maxContentScroll,
children,
...props
},
ref,
) => {
const { prefixCls, scrollbarSize, isSticky } = useContext(TableContext, [
'prefixCls',
'scrollbarSize',
'isSticky',
]);

const combinationScrollBarSize = isSticky && !fixHeader ? 0 : scrollbarSize;

// Pass wheel to scroll event
const scrollRef = React.useRef<HTMLDivElement>(null);

const setScrollRef = React.useCallback((element: HTMLElement) => {
fillRef(ref, element);
fillRef(scrollRef, element);
}, []);

React.useEffect(() => {
function onWheel(e: WheelEvent) {
const { currentTarget, deltaX } = e as unknown as React.WheelEvent<HTMLDivElement>;
if (deltaX) {
onScroll({ currentTarget, scrollLeft: currentTarget.scrollLeft + deltaX });
e.preventDefault();
}
const FixedHolder = React.forwardRef<HTMLDivElement, FixedHeaderProps<unknown>>((props, ref) => {
useRenderTimes(props);

const {
className,
noData,
columns,
flattenColumns,
colWidths,
columCount,
stickyOffsets,
direction,
fixHeader,
stickyTopOffset,
stickyBottomOffset,
stickyClassName,
onScroll,
maxContentScroll,
children,
...restProps
} = props;

const { prefixCls, scrollbarSize, isSticky } = useContext(TableContext, [
'prefixCls',
'scrollbarSize',
'isSticky',
]);

const combinationScrollBarSize = isSticky && !fixHeader ? 0 : scrollbarSize;

// Pass wheel to scroll event
const scrollRef = React.useRef<HTMLDivElement>(null);

const setScrollRef = React.useCallback((element: HTMLElement) => {
fillRef(ref, element);
fillRef(scrollRef, element);
}, []);

React.useEffect(() => {
function onWheel(e: WheelEvent) {
const { currentTarget, deltaX } = e as unknown as React.WheelEvent<HTMLDivElement>;
if (deltaX) {
onScroll({ currentTarget, scrollLeft: currentTarget.scrollLeft + deltaX });
e.preventDefault();
}
scrollRef.current?.addEventListener('wheel', onWheel);

return () => {
scrollRef.current?.removeEventListener('wheel', onWheel);
};
}, []);

// Check if all flattenColumns has width
const allFlattenColumnsWithWidth = React.useMemo(
() => flattenColumns.every(column => column.width >= 0),
[flattenColumns],
);

// Add scrollbar column
const lastColumn = flattenColumns[flattenColumns.length - 1];
const ScrollBarColumn: ColumnType<unknown> & { scrollbar: true } = {
fixed: lastColumn ? lastColumn.fixed : null,
scrollbar: true,
onHeaderCell: () => ({
className: `${prefixCls}-cell-scrollbar`,
}),
};
}
scrollRef.current?.addEventListener('wheel', onWheel);

const columnsWithScrollbar = useMemo<ColumnsType<unknown>>(
() => (combinationScrollBarSize ? [...columns, ScrollBarColumn] : columns),
[combinationScrollBarSize, columns],
);

const flattenColumnsWithScrollbar = useMemo(
() => (combinationScrollBarSize ? [...flattenColumns, ScrollBarColumn] : flattenColumns),
[combinationScrollBarSize, flattenColumns],
);

// Calculate the sticky offsets
const headerStickyOffsets = useMemo(() => {
const { right, left } = stickyOffsets;
return {
...stickyOffsets,
left:
direction === 'rtl' ? [...left.map(width => width + combinationScrollBarSize), 0] : left,
right:
direction === 'rtl'
? right
: [...right.map(width => width + combinationScrollBarSize), 0],
isSticky,
};
}, [combinationScrollBarSize, stickyOffsets, isSticky]);

const mergedColumnWidth = useColumnWidth(colWidths, columCount);

return (
<div
return () => {
scrollRef.current?.removeEventListener('wheel', onWheel);
};
}, []);

// Check if all flattenColumns has width
const allFlattenColumnsWithWidth = React.useMemo(
() => flattenColumns.every(column => column.width >= 0),
[flattenColumns],
);

// Add scrollbar column
const lastColumn = flattenColumns[flattenColumns.length - 1];
const ScrollBarColumn: ColumnType<unknown> & { scrollbar: true } = {
fixed: lastColumn ? lastColumn.fixed : null,
scrollbar: true,
onHeaderCell: () => ({
className: `${prefixCls}-cell-scrollbar`,
}),
};

const columnsWithScrollbar = useMemo<ColumnsType<unknown>>(
() => (combinationScrollBarSize ? [...columns, ScrollBarColumn] : columns),
[combinationScrollBarSize, columns],
);

const flattenColumnsWithScrollbar = useMemo(
() => (combinationScrollBarSize ? [...flattenColumns, ScrollBarColumn] : flattenColumns),
[combinationScrollBarSize, flattenColumns],
);

// Calculate the sticky offsets
const headerStickyOffsets = useMemo(() => {
const { right, left } = stickyOffsets;
return {
...stickyOffsets,
left:
direction === 'rtl' ? [...left.map(width => width + combinationScrollBarSize), 0] : left,
right:
direction === 'rtl' ? right : [...right.map(width => width + combinationScrollBarSize), 0],
isSticky,
};
}, [combinationScrollBarSize, stickyOffsets, isSticky]);

const mergedColumnWidth = useColumnWidth(colWidths, columCount);

return (
<div
style={{
overflow: 'hidden',
...(isSticky ? { top: stickyTopOffset, bottom: stickyBottomOffset } : {}),
}}
ref={setScrollRef}
className={classNames(className, {
[stickyClassName]: !!stickyClassName,
})}
>
<table
style={{
overflow: 'hidden',
...(isSticky ? { top: stickyTopOffset, bottom: stickyBottomOffset } : {}),
tableLayout: 'fixed',
visibility: noData || mergedColumnWidth ? null : 'hidden',
}}
ref={setScrollRef}
className={classNames(className, {
[stickyClassName]: !!stickyClassName,
})}
>
<table
style={{
tableLayout: 'fixed',
visibility: noData || mergedColumnWidth ? null : 'hidden',
}}
>
{(!noData || !maxContentScroll || allFlattenColumnsWithWidth) && (
<ColGroup
colWidths={mergedColumnWidth ? [...mergedColumnWidth, combinationScrollBarSize] : []}
columCount={columCount + 1}
columns={flattenColumnsWithScrollbar}
/>
)}
{children({
...props,
stickyOffsets: headerStickyOffsets,
columns: columnsWithScrollbar,
flattenColumns: flattenColumnsWithScrollbar,
})}
</table>
</div>
);
},
);
{(!noData || !maxContentScroll || allFlattenColumnsWithWidth) && (
<ColGroup
colWidths={mergedColumnWidth ? [...mergedColumnWidth, combinationScrollBarSize] : []}
columCount={columCount + 1}
columns={flattenColumnsWithScrollbar}
/>
)}
{children({
...restProps,
stickyOffsets: headerStickyOffsets,
columns: columnsWithScrollbar,
flattenColumns: flattenColumnsWithScrollbar,
})}
</table>
</div>
);
});

FixedHolder.displayName = 'FixedHolder';

export default FixedHolder;
/** Return a table in div as fixed element which contains sticky info */
// export default responseImmutable(FixedHolder);
export default React.memo(FixedHolder);
Loading