Skip to content

Commit

Permalink
Merge pull request #3961 from Sage/FE-4023_flat_table_multiple_sticky…
Browse files Browse the repository at this point in the history
…_headers

fix(flat-table): allow multiple header rows to be sticky
  • Loading branch information
samtjo committed May 7, 2021
2 parents afb9664 + f63ae26 commit f64ad90
Show file tree
Hide file tree
Showing 7 changed files with 728 additions and 403 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ const StyledFlatTableCell = styled.td`
${makeCellSticky &&
css`
top: auto;
left: ${leftPosition}px;
position: sticky;
`}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,35 @@
import React from "react";
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import StyledFlatTableHead from "./flat-table-head.style";

const getRefs = (length) => Array.from({ length }, () => React.createRef());

const FlatTableHead = ({ children }) => {
return <StyledFlatTableHead>{children}</StyledFlatTableHead>;
const [rowHeights, setRowHeights] = useState([]);
const refs = getRefs(React.Children.count(children));

useEffect(() => {
if (React.Children.count(children) > 1) {
setRowHeights(refs.map((ref) => ref.current.clientHeight));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

if (React.Children.count(children) === 1) {
return <StyledFlatTableHead>{children}</StyledFlatTableHead>;
}

return (
<StyledFlatTableHead>
{React.Children.map(children, (child, index) =>
React.cloneElement(child, {
...child.props,
stickyOffset: rowHeights.slice(0, index).reduce((a, b) => a + b, 0),
ref: refs[index],
})
)}
</StyledFlatTableHead>
);
};

FlatTableHead.propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ const StyledFlatTableHeader = styled.th`
${makeCellSticky &&
css`
top: auto;
left: ${leftPosition}px;
position: sticky;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const FlatTableRow = React.forwardRef(
expanded = false,
isSubRow,
isFirstSubRow,
stickyOffset,
highlighted,
selected,
subRows,
Expand Down Expand Up @@ -140,6 +141,7 @@ const FlatTableRow = React.forwardRef(
ref={rowRef}
rowHeaderIndex={rowHeaderIndex}
colorTheme={colorTheme}
stickyOffset={stickyOffset}
{...interactiveRowProps}
>
{React.Children.map(children, (child, index) => {
Expand Down Expand Up @@ -208,6 +210,8 @@ FlatTableRow.propTypes = {
isSubRow: PropTypes.bool,
/** @ignore @private */
isFirstSubRow: PropTypes.bool,
/** @ignore @private position in header if multiple rows */
stickyOffset: PropTypes.number,
};

export default FlatTableRow;
17 changes: 11 additions & 6 deletions src/components/flat-table/flat-table-row/flat-table-row.style.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ const StyledFlatTableRow = styled.tr`
table-layout: fixed;
width: auto;
${({ stickyOffset }) =>
stickyOffset > 0 &&
css`
&& th {
top: ${stickyOffset}px;
}
`}
${({ isRowInteractive, theme, rowHeaderIndex }) =>
isRowInteractive &&
css`
Expand Down Expand Up @@ -87,8 +95,7 @@ const StyledFlatTableRow = styled.tr`
}
}
`}
${({ isFirstColumnInteractive, firstCellIndex, theme }) =>
${({ isFirstColumnInteractive, firstCellIndex, theme }) =>
isFirstColumnInteractive &&
css`
td:nth-child(${firstCellIndex + 1}),
Expand All @@ -105,7 +112,6 @@ const StyledFlatTableRow = styled.tr`
}
}
`}
${({ colorTheme, rowHeaderIndex, theme }) =>
![-1, 0].includes(rowHeaderIndex) &&
css`
Expand All @@ -117,8 +123,7 @@ const StyledFlatTableRow = styled.tr`
border-left: 1px solid ${borderColor(colorTheme, theme)};
}
`}
${({
${({
expandable,
selected,
highlighted,
Expand Down Expand Up @@ -237,7 +242,7 @@ const StyledFlatTableRow = styled.tr`
}
`}
`;
}}
}};
`;

StyledFlatTableRow.defaultProps = {
Expand Down
74 changes: 74 additions & 0 deletions src/components/flat-table/flat-table.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React from "react";
import { mount } from "enzyme";
import { act } from "react-dom/test-utils";
import TestRenderer from "react-test-renderer";

import FlatTable from "./flat-table.component";
import FlatTableHead from "./flat-table-head/flat-table-head.component";
import FlatTableBody from "./flat-table-body/flat-table-body.component";
Expand Down Expand Up @@ -138,6 +140,78 @@ describe("FlatTable", () => {
});
});

describe("when it has a sticky header with multiple rows", () => {
let wrapper;

const render = () => {
wrapper = mount(
<div style={{ height: "200px" }}>
<FlatTable hasStickyHead>
<FlatTableHead>
<FlatTableRow>
<FlatTableHeader>header1</FlatTableHeader>
<FlatTableHeader>header2</FlatTableHeader>
<FlatTableHeader>header3</FlatTableHeader>
<FlatTableHeader>header4</FlatTableHeader>
</FlatTableRow>
<FlatTableRow>
<FlatTableHeader>header1</FlatTableHeader>
<FlatTableHeader>header2</FlatTableHeader>
<FlatTableHeader>header3</FlatTableHeader>
<FlatTableHeader>header4</FlatTableHeader>
</FlatTableRow>
</FlatTableHead>
<FlatTableBody>
<FlatTableRow>
<FlatTableRowHeader>row header</FlatTableRowHeader>
<FlatTableCell>cell1</FlatTableCell>
<FlatTableCell>cell2</FlatTableCell>
<FlatTableCell rowspan="2">cell3</FlatTableCell>
</FlatTableRow>
<FlatTableRow>
<FlatTableRowHeader>row header</FlatTableRowHeader>
<FlatTableCell colspan="2">cell1</FlatTableCell>
</FlatTableRow>
</FlatTableBody>
</FlatTable>
</div>
);

jest
.spyOn(
wrapper.find(StyledFlatTableRow).at(0).getDOMNode(),
"clientHeight",
"get"
)
.mockImplementation(() => 40);
};

beforeEach(() => {
render();
});

afterEach(() => {
wrapper.unmount();
});

it("should set the correct 'top' css on each row", () => {
act(() => render());
wrapper.update();

expect(
wrapper.find(StyledFlatTableRow).at(1).props().stickyOffset
).toEqual(40);

assertStyleMatch(
{
top: "40px",
},
wrapper.find(StyledFlatTableHead).find(StyledFlatTableRow).at(1),
{ modifier: `&& th` }
);
});
});

describe("when FlatTable is a child of Sidebar", () => {
let wrapper;
beforeEach(() => {
Expand Down
Loading

0 comments on commit f64ad90

Please sign in to comment.