Skip to content

Commit 0c024f4

Browse files
committed
refactor(flat-table): re-build using internal foundation components
rebuilds flat-table-row-draggable, flat-table-body-draggable and changes logic within flat-table-row BREAKING CHANGE: consumers will now have to pass their own cells with draggable icons to indicate draggable behaviour. This is no longer done as standard
1 parent a0bd26f commit 0c024f4

13 files changed

+550
-368
lines changed

src/components/flat-table/components.test-pw.tsx

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import FlatTableCheckbox, {
1717
import FlatTableBodyDraggable, {
1818
FlatTableBodyDraggableProps,
1919
} from "./flat-table-body-draggable/flat-table-body-draggable.component";
20+
import DrawerSidebarContext from "../drawer/__internal__/drawer-sidebar.context";
2021
import Sort from "./sort/sort.component";
2122
import Box from "../box";
2223
import Pager from "../pager";
@@ -2521,6 +2522,9 @@ export const FlatTableDraggableComponent = (
25212522
<FlatTableBodyDraggable {...props}>
25222523
{rows.map((row) => (
25232524
<FlatTableRow key={row.id} id={row.id}>
2525+
<FlatTableCell key={row.id}>
2526+
<Icon type="drag" />
2527+
</FlatTableCell>
25242528
<FlatTableCell>{row.name}</FlatTableCell>
25252529
</FlatTableRow>
25262530
))}
@@ -2529,6 +2533,102 @@ export const FlatTableDraggableComponent = (
25292533
);
25302534
};
25312535

2536+
export const FlatTableDraggingRowsWithSidebarContext = (
2537+
props: Partial<FlatTableBodyDraggableProps> & {
2538+
"data-drag-state": string;
2539+
},
2540+
) => {
2541+
const { "data-drag-state": dataDragState } = props;
2542+
const rows = [
2543+
{
2544+
id: "0",
2545+
name: "UK",
2546+
},
2547+
{
2548+
id: "1",
2549+
name: "Germany",
2550+
},
2551+
{
2552+
id: "2",
2553+
name: "China",
2554+
},
2555+
{
2556+
id: "3",
2557+
name: "US",
2558+
},
2559+
];
2560+
return (
2561+
<DrawerSidebarContext.Provider value={{ isInSidebar: true }}>
2562+
<FlatTable>
2563+
<FlatTableHead>
2564+
<FlatTableRow>
2565+
<FlatTableHeader>Click to Drag</FlatTableHeader>
2566+
<FlatTableHeader>Country</FlatTableHeader>
2567+
</FlatTableRow>
2568+
</FlatTableHead>
2569+
<FlatTableBodyDraggable {...props}>
2570+
{/* data-drag-state has to be manually applied due to issues issues asserting against styling triggered by the attribute */}
2571+
{rows.map((row) => (
2572+
<tr data-drag-state={dataDragState} key={row.id} id={row.id}>
2573+
<FlatTableCell key={row.id}>
2574+
<Icon type="drag" />
2575+
</FlatTableCell>
2576+
<FlatTableCell>{row.name}</FlatTableCell>
2577+
</tr>
2578+
))}
2579+
</FlatTableBodyDraggable>
2580+
</FlatTable>
2581+
</DrawerSidebarContext.Provider>
2582+
);
2583+
};
2584+
2585+
export const FlatTableDraggingRows = (
2586+
props: Partial<FlatTableBodyDraggableProps> & {
2587+
"data-drag-state": string;
2588+
},
2589+
) => {
2590+
const { "data-drag-state": dataDragState } = props;
2591+
const rows = [
2592+
{
2593+
id: "0",
2594+
name: "UK",
2595+
},
2596+
{
2597+
id: "1",
2598+
name: "Germany",
2599+
},
2600+
{
2601+
id: "2",
2602+
name: "China",
2603+
},
2604+
{
2605+
id: "3",
2606+
name: "US",
2607+
},
2608+
];
2609+
return (
2610+
<FlatTable>
2611+
<FlatTableHead>
2612+
<FlatTableRow>
2613+
<FlatTableHeader>Click to Drag</FlatTableHeader>
2614+
<FlatTableHeader>Country</FlatTableHeader>
2615+
</FlatTableRow>
2616+
</FlatTableHead>
2617+
<FlatTableBodyDraggable {...props}>
2618+
{/* data-drag-state has to be manually applied due to issues issues asserting against styling triggered by the attribute */}
2619+
{rows.map((row) => (
2620+
<tr data-drag-state={dataDragState} key={row.id} id={row.id}>
2621+
<FlatTableCell key={row.id}>
2622+
<Icon type="drag" />
2623+
</FlatTableCell>
2624+
<FlatTableCell>{row.name}</FlatTableCell>
2625+
</tr>
2626+
))}
2627+
</FlatTableBodyDraggable>
2628+
</FlatTable>
2629+
);
2630+
};
2631+
25322632
export const FlatTablePagerStickyHeaderComponent = () => {
25332633
const [placementUp, setPlacementUp] = useState(true);
25342634
const rows = [
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { createContext } from "react";
2+
3+
interface FlatTableBodyDraggableContextType {
4+
isInFlatTableBodyDraggable: boolean;
5+
}
6+
7+
const FlatTableBodyDraggableContext =
8+
createContext<FlatTableBodyDraggableContextType>({
9+
isInFlatTableBodyDraggable: false,
10+
});
11+
12+
export default FlatTableBodyDraggableContext;
Lines changed: 32 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,48 @@
1-
import React, { useEffect, useState, useRef } from "react";
2-
import { useDrop, DndProvider } from "react-dnd";
3-
import { HTML5Backend } from "react-dnd-html5-backend";
4-
1+
import React, { useContext, forwardRef } from "react";
52
import { TagProps } from "../../../__internal__/utils/helpers/tags";
6-
import StyledIcon from "../../icon/icon.style";
3+
import DraggableContainer from "../../../__internal__/draggable/draggable-container";
4+
import { FlatTableBodyDraggableHandle } from "..";
75
import StyledFlatTableBodyDraggable from "./flat-table-body-draggable.style";
8-
import FlatTableCell from "../flat-table-cell/flat-table-cell.component";
6+
import FlatTableBodyDraggableContext from "./flat-table-body-draggable-context";
7+
import DrawerSidebarContext from "../../drawer/__internal__/drawer-sidebar.context";
98

109
export interface FlatTableBodyDraggableProps extends TagProps {
1110
/** Array of FlatTableRow. */
1211
children: React.ReactNode;
1312
/** Callback fired when order is changed */
14-
getOrder?: (draggableItemIds?: number[]) => void;
13+
getOrder?: (
14+
draggableItemIds?: (string | number | undefined)[],
15+
movedItemId?: string | number | undefined,
16+
) => void;
1517
}
1618

17-
const DropTarget = ({
18-
children,
19-
getOrder,
20-
...rest
21-
}: FlatTableBodyDraggableProps) => {
22-
const [isDragging, setIsDragging] = useState(false);
23-
24-
const [, drop] = useDrop({
25-
accept: "flatTableRow",
26-
hover: (_, monitor) => {
27-
if (!isDragging && monitor.isOver()) setIsDragging(true);
28-
},
29-
drop() {
30-
setIsDragging(false);
31-
getOrder?.();
32-
},
33-
});
19+
const FlatTableBodyDraggable = forwardRef<
20+
FlatTableBodyDraggableHandle,
21+
FlatTableBodyDraggableProps
22+
>(({ children, getOrder, ...rest }, ref) => {
23+
const { isInSidebar } = useContext(DrawerSidebarContext);
3424

3525
return (
36-
<StyledFlatTableBodyDraggable
37-
data-component="flat-table-body-draggable"
38-
data-role="flat-table-body-draggable"
39-
ref={drop}
40-
isDragging={isDragging}
41-
{...rest}
26+
<FlatTableBodyDraggableContext.Provider
27+
value={{ isInFlatTableBodyDraggable: true }}
4228
>
43-
{children}
44-
</StyledFlatTableBodyDraggable>
45-
);
46-
};
47-
48-
export const FlatTableBodyDraggable = ({
49-
children,
50-
getOrder,
51-
...rest
52-
}: FlatTableBodyDraggableProps) => {
53-
const [draggableItems, setDraggableItems] = useState(
54-
React.Children.toArray(children),
29+
<DraggableContainer
30+
ref={ref}
31+
containerNode={StyledFlatTableBodyDraggable}
32+
getOrder={getOrder}
33+
containerProps={{
34+
"data-component": "flat-table-body-draggable",
35+
"data-role": "flat-table-body-draggable",
36+
isInSidebar,
37+
...rest,
38+
}}
39+
>
40+
{children}
41+
</DraggableContainer>
42+
</FlatTableBodyDraggableContext.Provider>
5543
);
56-
const isFirstRender = useRef(true);
57-
58-
useEffect(() => {
59-
if (!isFirstRender.current) {
60-
setDraggableItems(React.Children.toArray(children));
61-
} else {
62-
isFirstRender.current = false;
63-
}
64-
}, [children]);
65-
66-
const findItem = (id: string | number) => {
67-
const draggableItem = draggableItems.filter(
68-
(item) => React.isValidElement(item) && `${item.props.id}` === id,
69-
)[0];
70-
71-
return {
72-
draggableItem,
73-
index: draggableItems.indexOf(draggableItem),
74-
};
75-
};
44+
});
7645

77-
const moveItem = (id: string | number, atIndex: number) => {
78-
const { draggableItem, index } = findItem(id);
79-
if (!draggableItem) return;
80-
81-
const copyOfDraggableItems = [...draggableItems];
82-
copyOfDraggableItems.splice(index, 1);
83-
copyOfDraggableItems.splice(atIndex, 0, draggableItem);
84-
setDraggableItems(copyOfDraggableItems);
85-
};
86-
87-
const getItemsId = () => {
88-
if (!getOrder) {
89-
return;
90-
}
91-
92-
const draggableItemIds = draggableItems.map(
93-
(draggableItem) =>
94-
React.isValidElement(draggableItem) && draggableItem.props.id,
95-
);
96-
97-
getOrder(draggableItemIds);
98-
};
99-
100-
return (
101-
<DndProvider backend={HTML5Backend}>
102-
<DropTarget getOrder={getItemsId} {...rest}>
103-
{draggableItems.map(
104-
(item) =>
105-
React.isValidElement(item) &&
106-
React.cloneElement(
107-
item as React.ReactElement,
108-
{
109-
id: `${item.props.id}`,
110-
moveItem,
111-
findItem,
112-
draggable: true,
113-
},
114-
[
115-
<FlatTableCell key={item.props.id}>
116-
<StyledIcon type="drag" />
117-
</FlatTableCell>,
118-
item.props.children,
119-
],
120-
),
121-
)}
122-
</DropTarget>
123-
</DndProvider>
124-
);
125-
};
46+
FlatTableBodyDraggable.displayName = "FlatTableBodyDraggable";
12647

12748
export default FlatTableBodyDraggable;
Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,31 @@
1-
import styled, { css } from "styled-components";
2-
3-
const StyledFlatTableBodyDraggable = styled.tbody<{ isDragging: boolean }>`
4-
${({ isDragging }) =>
5-
isDragging &&
6-
css`
7-
cursor: grabbing;
8-
`}
1+
import styled from "styled-components";
2+
import { StyledFlatTableRowHeader } from "../flat-table-row-header/flat-table-row-header.style";
3+
import StyledFlatTableCheckbox from "../flat-table-checkbox/flat-table-checkbox.style";
4+
import { StyledFlatTableCell } from "../flat-table-cell/flat-table-cell.style";
5+
6+
const allCellTypes = `${StyledFlatTableRowHeader}, ${StyledFlatTableCell}, ${StyledFlatTableCheckbox}`;
7+
8+
const StyledFlatTableBodyDraggable = styled.tbody<{
9+
isInSidebar: boolean;
10+
}>`
11+
& tr[draggable="true"] {
12+
cursor: grab;
13+
}
14+
15+
& tr[data-drag-state="is-dragging"] {
16+
cursor: grabbing;
17+
}
18+
19+
& tr[data-drag-state="is-being-dragged-over"],
20+
& tr[data-drag-state="is-dragging"] {
21+
${allCellTypes} {
22+
background-color: ${({ isInSidebar }) =>
23+
/* istanbul ignore next - PW test added to cover due to difficulty testing */
24+
isInSidebar
25+
? "var(--colorsUtilityMajor200)"
26+
: "var(--colorsUtilityMajor150)"};
27+
}
28+
}
929
`;
1030

1131
export default StyledFlatTableBodyDraggable;

0 commit comments

Comments
 (0)