@axinom/mosaic-ui
Version:
UI components for building Axinom Mosaic applications
110 lines (94 loc) • 3.11 kB
text/typescript
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { DynamicListColumn } from '../../components';
import { Column } from '../../components/List/List.model';
import { Data } from '../../types';
/**
* Handles the resizing logic of the columns
* @param columns The list of column definitions
* @param onColumnSizesChanged Callback that will be called when the column sizes change
* @returns an object containing the refs to the columns (add these to all column header elements)
* and the mouseDown handler (add this to the element that should be used to resize the column)
*/
export const useResize = <T extends Data>(
columns: Column<T>[] | DynamicListColumn<T>[],
onColumnSizesChanged: (columnSizes: string) => void,
): {
cols: {
ref: React.RefObject<HTMLTableCellElement>;
orgSize: string | undefined;
}[];
mouseDown: (index: number) => void;
} => {
const minCellWidth = 50;
const cols = useMemo(
() =>
[
...columns,
{ size: 'auto' }, // Last column for action buttons and checkbox, etc
].map((col) => ({
ref: React.createRef<HTMLTableCellElement>(),
orgSize: col.size,
})),
[columns],
);
const [activeIndex, setActiveIndex] = useState<number | undefined>(undefined);
const resizeStart = React.useRef<
{ mouse: number; width: number } | undefined
>(undefined);
const mouseMove = useCallback(
(e) => {
if (activeIndex !== undefined) {
const elem = cols[activeIndex].ref.current;
if (!elem) {
return;
}
if (!resizeStart.current) {
resizeStart.current = {
mouse: e.clientX,
width: elem.offsetWidth,
};
}
const start = resizeStart.current;
if (!start) {
return;
}
const gridColumns = cols.map((col, i) => {
if (!col.ref.current) {
return col.orgSize;
}
if (i === activeIndex) {
const width = start.width + e.clientX - start.mouse;
if (width >= minCellWidth) {
return `${width}px`;
}
}
return `${col.ref.current.offsetWidth}px`;
});
onColumnSizesChanged(gridColumns.join(' '));
}
},
[activeIndex, cols, onColumnSizesChanged],
);
const mouseDown = (index: number): void => {
setActiveIndex(index);
};
const removeListeners = useCallback(() => {
window.removeEventListener('mousemove', mouseMove);
window.removeEventListener('mouseup', removeListeners);
}, [mouseMove]);
const mouseUp = useCallback(() => {
setActiveIndex(undefined);
resizeStart.current = undefined;
removeListeners();
}, [setActiveIndex, removeListeners]);
useEffect(() => {
if (activeIndex !== undefined) {
window.addEventListener('mousemove', mouseMove);
window.addEventListener('mouseup', mouseUp);
}
return () => {
removeListeners();
};
}, [activeIndex, mouseMove, mouseUp, removeListeners]);
return { cols, mouseDown };
};