UNPKG

@axinom/mosaic-ui

Version:

UI components for building Axinom Mosaic applications

110 lines (94 loc) 3.11 kB
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 }; };