import { type Ref, ref, onBeforeUnmount, computed, } from 'vue' export interface ResizableInterface { order: number wasResized?: boolean width: number isResizing: boolean } export default function useResizableColumns(computedColumns: Ref) { const resizedColumn: Ref = ref(undefined) const resizeDirection: Ref<'left'|'right'> = ref('left') const startX = ref(0) const visualOffset = ref(0) const initialWidth = ref(0) const initialCellRight = ref(0) const initialCellLeft = ref(0) const tableContainerLeft = ref(0) const tableContainerRight = ref(0) const isResizing = computed(() => !!resizedColumn.value) const MIN_WIDTH = 100 const startResize = ( column: ResizableInterface, direction: 'left'|'right', event: MouseEvent, cellElement: HTMLElement | null, tableContainer: HTMLElement | null, ) => { column.isResizing = true resizedColumn.value = column resizeDirection.value = direction visualOffset.value = 0 initialWidth.value = column.width startX.value = event.clientX // Сохраняем начальные границы для ограничения смещения if (cellElement && tableContainer) { const cellRect = cellElement.getBoundingClientRect() const tableRect = tableContainer.getBoundingClientRect() initialCellRight.value = cellRect.right initialCellRight.value = cellRect.right initialCellLeft.value = cellRect.left tableContainerLeft.value = tableRect.left tableContainerRight.value = tableRect.right } else { initialCellRight.value = 0 initialCellLeft.value = 0 tableContainerLeft.value = 0 tableContainerRight.value = 0 } // Предотвращаем выделение текста при перетаскивании event.preventDefault() } const stopResize = () => { const currentColumn = resizedColumn.value if (currentColumn && visualOffset.value !== 0) { if (resizeDirection.value === 'right') { const newWidth = initialWidth.value + visualOffset.value currentColumn.width = newWidth < MIN_WIDTH ? MIN_WIDTH : newWidth } else { const prevColumns = computedColumns.value.filter((c) => c.order < currentColumn.order) if (prevColumns.length > 0) { const delta = -visualOffset.value let count = 0 prevColumns.forEach((column) => { const newWidth = column.width - delta / prevColumns.length if (newWidth > 200) { column.width = newWidth count += 1 } }) if (count > 0) { currentColumn.width = initialWidth.value + (delta / prevColumns.length) * count } } } if (typeof (currentColumn?.wasResized) !== 'undefined') { currentColumn.wasResized = true } } if (currentColumn) { currentColumn.isResizing = false } startX.value = 0 visualOffset.value = 0 resizedColumn.value = undefined initialCellRight.value = 0 initialCellLeft.value = 0 tableContainerLeft.value = 0 tableContainerRight.value = 0 } const onMouseMove = (e: MouseEvent) => { if (!resizedColumn.value) return const currentColumn = resizedColumn.value currentColumn.isResizing = true if (resizeDirection.value === 'right') { // при использовании правой границы ячейки расширяем ее и таблицу вправо let delta = -(startX.value - e.clientX) // Ограничиваем смещение границами таблицы // Максимальное смещение вправо - до правой границы таблицы const maxRightOffset = tableContainerRight.value - initialCellRight.value // Минимальное смещение влево - чтобы новая ширина была не меньше 100px const minLeftOffset = MIN_WIDTH - initialWidth.value delta = Math.max(minLeftOffset, Math.min(maxRightOffset, delta)) visualOffset.value = delta } else { // при использовании левой границы ячейки расширяем или сужаем ее за счет изменения размера ячеек слева let delta = startX.value - e.clientX // Ограничиваем смещение границами таблицы // Максимальное смещение влево - до левой границы таблицы const maxLeftOffset = initialCellLeft.value - tableContainerLeft.value // Минимальное смещение вправо - чтобы новая ширина была не меньше 100px const minRightOffset = initialWidth.value - MIN_WIDTH delta = Math.max(-minRightOffset, Math.min(maxLeftOffset, delta)) visualOffset.value = -delta } } const onMouseUp = () => { stopResize() } const handleMouseMove = (e: MouseEvent) => { onMouseMove(e) } const handleMouseUp = () => { onMouseUp() } window.addEventListener('mousemove', handleMouseMove) window.addEventListener('mouseup', handleMouseUp) onBeforeUnmount(() => { window.removeEventListener('mousemove', handleMouseMove) window.removeEventListener('mouseup', handleMouseUp) }) return { startResize, stopResize, resizedColumn, visualOffset, isResizing, } }