Skip to content

Commit

Permalink
Merge pull request #6220 from Sage/FE-6050-refactor-ft
Browse files Browse the repository at this point in the history
feat(flat-table, flat-table-row): components can now be wrapped, subRows no longer need to be arrays FE-6050
  • Loading branch information
edleeks87 authored Aug 30, 2023
2 parents 99e29c0 + ea27a57 commit 01e625d
Show file tree
Hide file tree
Showing 26 changed files with 1,116 additions and 1,081 deletions.
21 changes: 19 additions & 2 deletions cypress/components/flat-table/flat-table.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
import * as stories from "../../../src/components/flat-table/flat-table-test.stories";
import { FlatTableProps } from "../../../src/components/flat-table/flat-table.component";
import { FlatTableRowProps } from "../../../src/components/flat-table/flat-table-row/flat-table-row.component";
import { FlatTableCellProps } from "../../../src/components/flat-table/flat-table-cell/flat-table-cell.component";
import Icon from "../../../src/components/icon";
import CypressMountWithProviders from "../../support/component-helper/cypress-mount";
import { getDataElementByValue, cyRoot } from "../../locators";
Expand Down Expand Up @@ -60,6 +59,7 @@ import {
positionOfElement,
getRotationAngle,
} from "../../support/helper";
import { FlatTableRowContextProps } from "../../../src/components/flat-table/flat-table-row/__internal__/flat-table-row-context";

const sizes = [
["compact", "8px", "13px", 24],
Expand Down Expand Up @@ -299,6 +299,21 @@ context("Tests for Flat Table component", () => {
}
});

it("should render Flat Table with sticky header and multiple rows", () => {
CypressMountWithProviders(
<div style={{ height: "150px" }}>
<stories.FlatTableWithMultipleStickyHeaderRows />
</div>
);

flatTableHeaderRowByPosition(0)
.find("th")
.should("have.css", "top", "0px");
flatTableHeaderRowByPosition(1)
.find("th")
.should("have.css", "top", "40px");
});

it("should render Flat Table with sticky footer", () => {
CypressMountWithProviders(
<stories.FlatTableFooterComponent hasStickyFooter />
Expand Down Expand Up @@ -2670,7 +2685,9 @@ context("Tests for Flat Table component", () => {
});

it("should call onClick when first Flat Table column is sorted", () => {
const callback: FlatTableCellProps["onClick"] = cy.stub().as("onClick");
const callback: FlatTableRowContextProps["onClick"] = cy
.stub()
.as("onClick");
CypressMountWithProviders(
<stories.FlatTableSortingComponent onClick={callback} />
);
Expand Down
18 changes: 18 additions & 0 deletions src/components/flat-table/__internal__/build-position-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default (
array: HTMLElement[],
propertyName: "offsetWidth" | "offsetHeight"
) =>
array.reduce((acc: Record<string, number>, _, index) => {
const currentId = array[index].getAttribute("id");
if (currentId) {
if (index === 0) {
acc[currentId] = 0;
} else {
const previousId = array[index - 1].getAttribute("id");
if (previousId) {
acc[currentId] = acc[previousId] + array[index - 1][propertyName];
}
}
}
return acc;
}, {});
2 changes: 2 additions & 0 deletions src/components/flat-table/__internal__/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as useCalculateStickyCells } from "./use-calculate-sticky-cells";
export { default as buildPositionMap } from "./build-position-map";
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useContext } from "react";
import FlatTableRowContext from "../flat-table-row/__internal__/flat-table-row-context";

export default (id: string) => {
const {
expandable,
firstCellId,
firstColumnExpandable,
leftPositions,
rightPositions,
onClick,
onKeyDown,
} = useContext(FlatTableRowContext);

const leftPosition = leftPositions[id];
const rightPosition = rightPositions[id];
const makeCellSticky =
leftPosition !== undefined || rightPosition !== undefined;
const isFirstCell = id === firstCellId;
const isExpandableCell = expandable && isFirstCell && firstColumnExpandable;

return {
expandable,
leftPosition,
rightPosition,
makeCellSticky,
onClick,
onKeyDown,
isFirstCell,
isExpandableCell,
};
};
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import React, {
useLayoutEffect,
useRef,
useState,
useEffect,
useContext,
} from "react";
import React, { useRef, useState, useEffect, useContext } from "react";
import { PaddingProps } from "styled-system";
import { TableBorderSize, TableCellAlign } from "..";

Expand All @@ -15,6 +9,7 @@ import {
import Icon from "../../icon";
import { FlatTableThemeContext } from "../flat-table.component";
import guid from "../../../__internal__/utils/helpers/guid";
import useCalculateStickyCells from "../__internal__/use-calculate-sticky-cells";

export interface FlatTableCellProps extends PaddingProps {
/** Content alignment */
Expand All @@ -35,110 +30,69 @@ export interface FlatTableCellProps extends PaddingProps {
verticalBorder?: TableBorderSize;
/** Sets the color of the right border */
verticalBorderColor?: string;
/** Sets an id string on the DOM element */
/** Sets an id string on the element */
id?: string;
/**
* @private
* @ignore
*/
expandable?: boolean;
/**
* @private
* @ignore
*/
onClick?: () => void;
/**
* @private
* @ignore
*/
onKeyDown?: () => void;
/**
* @private
* @ignore
* Sets the left position when sticky column found
*/
leftPosition?: number;
/**
* @private
* @ignore
* Sets the right position when sticky column found
*/
rightPosition?: number;
/**
* @private
* @ignore
* Index of cell within row
*/
cellIndex?: number;
/**
* @private
* @ignore
* Callback to report the offsetWidth
*/
reportCellWidth?: (offset: number, index?: number) => void;
}

export const FlatTableCell = ({
align = "left",
children,
pl,
expandable = false,
onClick,
onKeyDown,
reportCellWidth,
cellIndex,
leftPosition,
rightPosition,
width,
truncate = false,
title,
colspan,
rowspan,
id,
...rest
}: FlatTableCellProps) => {
const ref = useRef<HTMLTableCellElement>(null);
const id = useRef(guid());
const internalId = useRef(id || guid());
const [tabIndex, setTabIndex] = useState(-1);
const { selectedId } = useContext(FlatTableThemeContext);

useLayoutEffect(() => {
if (ref.current && reportCellWidth) {
reportCellWidth(ref.current.offsetWidth, cellIndex);
}
}, [reportCellWidth, cellIndex]);
const {
leftPosition,
rightPosition,
expandable,
onClick,
onKeyDown,
isFirstCell,
isExpandableCell,
makeCellSticky,
} = useCalculateStickyCells(internalId.current);

useEffect(() => {
setTabIndex(selectedId === id.current ? 0 : -1);
}, [selectedId]);
setTabIndex(isExpandableCell && selectedId === internalId.current ? 0 : -1);
}, [selectedId, isExpandableCell]);

return (
<StyledFlatTableCell
leftPosition={leftPosition}
rightPosition={rightPosition}
makeCellSticky={!!reportCellWidth}
className={reportCellWidth ? "isSticky" : undefined}
makeCellSticky={makeCellSticky}
className={makeCellSticky ? "isSticky" : undefined}
ref={ref}
align={align}
data-element="flat-table-cell"
pl={pl}
onClick={expandable && onClick ? onClick : undefined}
tabIndex={expandable && onClick ? tabIndex : undefined}
onKeyDown={expandable && onKeyDown ? onKeyDown : undefined}
onClick={isExpandableCell ? onClick : undefined}
tabIndex={isExpandableCell ? tabIndex : undefined}
onKeyDown={isExpandableCell ? onKeyDown : undefined}
colWidth={width}
isTruncated={truncate}
expandable={expandable}
id={id.current}
{...(colspan !== undefined && { colSpan: Number(colspan) })}
{...(rowspan !== undefined && { rowSpan: Number(rowspan) })}
{...rest}
id={internalId.current}
>
<StyledCellContent
title={
truncate && !title && typeof children === "string" ? children : title
}
expandable={expandable}
>
{expandable && (
{expandable && isFirstCell && (
<Icon type="chevron_down_thick" bgSize="extra-small" mr="8px" />
)}
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,15 @@ const verticalBorderSizes = {
interface StyledFlatTableCellProps
extends Pick<
FlatTableCellProps,
| "align"
| "leftPosition"
| "rightPosition"
| "expandable"
| "verticalBorder"
| "verticalBorderColor"
"align" | "verticalBorder" | "verticalBorderColor"
>,
PaddingProps {
makeCellSticky: boolean;
colWidth?: number;
isTruncated: boolean;
leftPosition: number;
rightPosition: number;
expandable?: boolean;
}

const StyledFlatTableCell = styled.td<StyledFlatTableCellProps>`
Expand Down Expand Up @@ -112,7 +110,7 @@ const StyledFlatTableCell = styled.td<StyledFlatTableCellProps>`
`}
`;

const StyledCellContent = styled.div<Pick<FlatTableCellProps, "expandable">>`
const StyledCellContent = styled.div<{ expandable?: boolean }>`
${({ expandable }) =>
expandable &&
css`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import React, { useLayoutEffect, useRef } from "react";
import React, { useContext, useRef } from "react";
import StyledFlatTableCheckbox from "./flat-table-checkbox.style";
import { Checkbox } from "../../checkbox";
import Events from "../../../__internal__/utils/helpers/events/events";
import { TagProps } from "../../../__internal__/utils/helpers/tags";
import tagComponent, {
TagProps,
} from "../../../__internal__/utils/helpers/tags";
import guid from "../../../__internal__/utils/helpers/guid";
import FlatTableRowContext from "../flat-table-row/__internal__/flat-table-row-context";

export interface FlatTableCheckboxProps extends TagProps {
/** Prop to polymorphically render either a 'th' or 'td' element */
Expand All @@ -17,30 +21,8 @@ export interface FlatTableCheckboxProps extends TagProps {
onClick?: (ev: React.MouseEvent<HTMLElement>) => void;
/** The id of the element that labels the input */
ariaLabelledBy?: string;
/**
* @private
* @ignore
* Sets the left position when sticky column found
*/
leftPosition?: number;
/**
* @private
* @ignore
* Sets the right position when sticky column found
*/
rightPosition?: number;
/**
* @private
* @ignore
* Index of cell within row
*/
cellIndex?: number;
/**
* @private
* @ignore
* Callback to report the offsetWidth
*/
reportCellWidth?: (offset: number, index?: number) => void;
/** Sets an id string on the element */
id?: string;
}

export const FlatTableCheckbox = ({
Expand All @@ -49,20 +31,18 @@ export const FlatTableCheckbox = ({
onChange,
selectable = true,
onClick,
leftPosition,
rightPosition,
cellIndex,
reportCellWidth,
ariaLabelledBy,
id,
...rest
}: FlatTableCheckboxProps) => {
const ref = useRef<HTMLTableCellElement>(null);
const internalId = useRef(id || guid());
const { leftPositions, rightPositions } = useContext(FlatTableRowContext);

useLayoutEffect(() => {
if (ref.current && reportCellWidth) {
reportCellWidth(ref.current.offsetWidth, cellIndex);
}
}, [reportCellWidth, cellIndex]);
const leftPosition = leftPositions[internalId.current];
const rightPosition = rightPositions[internalId.current];
const makeCellSticky =
leftPosition !== undefined || rightPosition !== undefined;

const dataElement = `flat-table-checkbox-${as === "td" ? "cell" : "header"}`;

Expand All @@ -80,13 +60,16 @@ export const FlatTableCheckbox = ({
return (
<StyledFlatTableCheckbox
ref={ref}
makeCellSticky={!!reportCellWidth}
className={reportCellWidth ? "isSticky" : undefined}
makeCellSticky={makeCellSticky}
className={makeCellSticky ? "isSticky" : undefined}
leftPosition={leftPosition}
rightPosition={rightPosition}
data-element={dataElement}
as={as}
{...rest}
{...tagComponent("flat-table-checkbox", {
"data-element": dataElement,
...rest,
})}
id={internalId.current}
>
{selectable && (
<Checkbox
Expand Down
Loading

0 comments on commit 01e625d

Please sign in to comment.