Skip to content

Commit a4f2095

Browse files
authored
IBX-9649: Sticky columns in React table (#1484)
1 parent 0af2eb6 commit a4f2095

File tree

1 file changed

+51
-2
lines changed
  • src/bundle/ui-dev/src/modules/common/table

1 file changed

+51
-2
lines changed

src/bundle/ui-dev/src/modules/common/table/table.js

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,65 @@
1-
import React from 'react';
1+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
22
import PropTypes from 'prop-types';
33

44
import { createCssClassNames } from '../helpers/css.class.names';
55

66
const Table = ({ extraClasses, children, isLastColumnSticky }) => {
7+
const scrollableWrapperRef = useRef(null);
8+
const [hasLastColumnShadow, setHasLastColumnShadow] = useState(false);
79
const className = createCssClassNames({
810
'ibexa-table table': true,
911
'ibexa-table--last-column-sticky': isLastColumnSticky,
12+
'ibexa-table--last-column-shadow': isLastColumnSticky && hasLastColumnShadow,
1013
[extraClasses]: true,
1114
});
15+
const updateLastColumnShadowState = useCallback(() => {
16+
const offsetRoundingCompensator = 0.5;
17+
const shouldShowRightColumnShadow =
18+
scrollableWrapperRef.current.scrollLeft <
19+
scrollableWrapperRef.current.scrollWidth - scrollableWrapperRef.current.offsetWidth - 2 * offsetRoundingCompensator;
1220

13-
return <table className={className}>{children}</table>;
21+
setHasLastColumnShadow(shouldShowRightColumnShadow);
22+
}, [scrollableWrapperRef, setHasLastColumnShadow]);
23+
const scrollableWrapperResizeObserver = useMemo(
24+
() =>
25+
new ResizeObserver(() => {
26+
updateLastColumnShadowState();
27+
}),
28+
[updateLastColumnShadowState],
29+
);
30+
const handleScrollableWrapperRef = (ref) => {
31+
if (!ref || (scrollableWrapperRef.current !== null && scrollableWrapperRef.current !== ref)) {
32+
scrollableWrapperResizeObserver.unobserve(scrollableWrapperRef.current);
33+
}
34+
35+
scrollableWrapperRef.current = ref;
36+
37+
if (ref) {
38+
scrollableWrapperResizeObserver.observe(ref);
39+
40+
if (isLastColumnSticky) {
41+
updateLastColumnShadowState();
42+
ref.addEventListener('scroll', updateLastColumnShadowState, false);
43+
}
44+
}
45+
};
46+
47+
useEffect(() => {
48+
if (isLastColumnSticky) {
49+
updateLastColumnShadowState();
50+
scrollableWrapperRef.current?.addEventListener('scroll', updateLastColumnShadowState, false);
51+
52+
return () => {
53+
scrollableWrapperRef.current?.removeEventListener('scroll', updateLastColumnShadowState, false);
54+
};
55+
}
56+
}, [isLastColumnSticky, updateLastColumnShadowState]);
57+
58+
return (
59+
<div className="ibexa-scrollable-wrapper" ref={handleScrollableWrapperRef}>
60+
<table className={className}>{children}</table>
61+
</div>
62+
);
1463
};
1564

1665
Table.propTypes = {

0 commit comments

Comments
 (0)