Skip to content

Commit

Permalink
feat: add column resizing
Browse files Browse the repository at this point in the history
Closes #817
  • Loading branch information
thaisguigon committed Jul 28, 2023
1 parent 44a9c26 commit d4acd35
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 6 deletions.
9 changes: 8 additions & 1 deletion front/src/modules/ui/table/components/ColumnHead.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,25 @@ const StyledTitle = styled.div`
font-weight: ${({ theme }) => theme.font.weight.medium};
height: ${({ theme }) => theme.spacing(8)};
padding-left: ${({ theme }) => theme.spacing(2)};
padding-right: ${({ theme }) => theme.spacing(2)};
`;

const StyledIcon = styled.div`
display: flex;
margin-right: ${({ theme }) => theme.spacing(1)};
`;

const StyledText = styled.span`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;

export function ColumnHead({ viewName, viewIcon }: OwnProps) {
return (
<StyledTitle>
<StyledIcon>{viewIcon}</StyledIcon>
{viewName}
<StyledText>{viewName}</StyledText>
</StyledTitle>
);
}
100 changes: 95 additions & 5 deletions front/src/modules/ui/table/components/EntityTableHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,91 @@
import { DragEvent, useCallback, useRef, useState } from 'react';
import styled from '@emotion/styled';

import { TableColumn } from '@/people/table/components/peopleColumns';

import { ColumnHead } from './ColumnHead';
import { SelectAllCheckbox } from './SelectAllCheckbox';

const COLUMN_MIN_WIDTH = 75;

const StyledColumnHeaderCell = styled.th<{ isResizing?: boolean }>`
min-width: ${COLUMN_MIN_WIDTH}px;
position: relative;
${(props) =>
props.isResizing
? `&:after {
background-color: ${props.theme.color.blue};
bottom: 0;
content: '';
display: block;
position: absolute;
right: -1.5px;
top: 0;
width: 2px;
}`
: ''}
`;

const StyledResizeHandler = styled.div`
bottom: 0;
cursor: col-resize;
padding: 0 ${({ theme }) => theme.spacing(2)};
position: absolute;
right: -9px;
top: 0;
width: 1px;
z-index: 1;
`;

export function EntityTableHeader({
columns,
}: {
columns: Array<TableColumn>;
}) {
const [columnWidths, setColumnWidths] = useState(
columns.reduce<Record<string, number>>(
(result, column) => ({ ...result, [column.id]: column.size }),
{},
),
);
const [offset, setOffset] = useState(0);
const resizedColumnId = useRef('');
const initialHandlerPosition = useRef(-1);

const handleResizeHandlerDragStart = useCallback(
(event: DragEvent<HTMLDivElement>, columnId: string) => {
resizedColumnId.current = columnId;
initialHandlerPosition.current = event.clientX;
},
[],
);

const handleResizeHandlerDrag = useCallback(
(event: DragEvent<HTMLDivElement>) => {
// @see https://stackoverflow.com/q/36308460
// `event.screenX === 0` allows to detect the last "drag" event
// which is emitted on mouse release.
// On this last "drag" event, `event.clientX` is reset to an incorrect value
// which does not reflect the handler's position, so we ignore it.
if (event.screenX === 0) return;

setOffset(event.clientX - initialHandlerPosition.current);
},
[],
);

const handleResizeHandlerDragEnd = useCallback(() => {
setColumnWidths((previousColumnWidths) => ({
...previousColumnWidths,
[resizedColumnId.current]: Math.max(
previousColumnWidths[resizedColumnId.current] + offset,
COLUMN_MIN_WIDTH,
),
}));
resizedColumnId.current = '';
}, [offset]);

return (
<thead>
<tr>
Expand All @@ -21,16 +99,28 @@ export function EntityTableHeader({
<SelectAllCheckbox />
</th>
{columns.map((column) => (
<th
<StyledColumnHeaderCell
key={column.id.toString()}
isResizing={resizedColumnId.current === column.id}
style={{
width: column.size,
minWidth: column.size,
maxWidth: column.size,
width: Math.max(
columnWidths[column.id] +
(resizedColumnId.current === column.id ? offset : 0),
COLUMN_MIN_WIDTH,
),
}}
>
<ColumnHead viewName={column.title} viewIcon={column.icon} />
</th>
<StyledResizeHandler
draggable
role="separator"
onDragStart={(event) =>
handleResizeHandlerDragStart(event, column.id)
}
onDrag={handleResizeHandlerDrag}
onDragEnd={handleResizeHandlerDragEnd}
/>
</StyledColumnHeaderCell>
))}
<th></th>
</tr>
Expand Down

0 comments on commit d4acd35

Please sign in to comment.