import type { Context } from '../context/grid-context' const ensureVisibleVertical = ( element: HTMLElement, scroller: HTMLDivElement, footerHeight: number, headerHeight: number ) => { const bounds = scroller.getBoundingClientRect() const scrollbarHeight = scroller.offsetHeight - scroller.clientHeight const adjustedTop = bounds.top + headerHeight const adjustedBottom = bounds.bottom - footerHeight - scrollbarHeight const availableHeight = adjustedBottom - adjustedTop const targetBounds = element.getBoundingClientRect() if (availableHeight > 0) { if (targetBounds.top < adjustedTop) { const diff = adjustedTop - targetBounds.top scroller.scrollTop -= diff } else if (targetBounds.bottom > adjustedBottom) { const diff = targetBounds.bottom - adjustedBottom scroller.scrollTop += diff } } } const ensureVisibleHorizontal = ( element: HTMLElement, scroller: HTMLDivElement, stickyWidthLeft: number, stickyWidthRight: number ) => { const bounds = scroller.getBoundingClientRect() const scrollbarWidth = scroller.offsetWidth - scroller.clientWidth const adjustedLeft = bounds.left + stickyWidthLeft const adjustedRight = bounds.right - stickyWidthRight - scrollbarWidth const availableWidth = adjustedRight - adjustedLeft const targetBounds = element.getBoundingClientRect() if (availableWidth <= 0) { return } if (targetBounds.left < adjustedLeft) { /* Regardless of if the cell can fully fit on screen, align the left with the visible area */ const diff = adjustedLeft - targetBounds.left scroller.scrollLeft -= diff } else if (targetBounds.right > adjustedRight) { if (availableWidth > targetBounds.width) { /* Full cell can fit in the available area. Move as little as needed to bring the cell fully into view */ const diff = targetBounds.right - adjustedRight scroller.scrollLeft += diff } else { /* Full cell cannot fit on screen, align the left with the visible area */ const diff = adjustedLeft - targetBounds.left scroller.scrollLeft -= diff } } } export function ensureRowIsVisible( row: HTMLTableRowElement, scroller: HTMLDivElement, grid: Context ) { const state = grid.getState() const area = grid.selectors.selectCurrentFocus(state).area const footerHeight = grid.selectors.selectAggregationEnabled(state) ? grid.selectors.selectRowHeight(state) : 0 const headerHeight = grid.selectors.selectHeaderHeight(state) if (area === 'body') { ensureVisibleVertical(row, scroller, footerHeight, headerHeight) } } export function ensureCellIsVisible( cell: HTMLTableCellElement, scroller: HTMLDivElement, grid: Context ) { /* aria-column indexes are 1 based, so we subtract 1 */ const columnIndex = Number(cell.getAttribute('aria-colindex')) - 1 const state = grid.getState() const area = grid.selectors.selectCurrentFocus(state).area const footerHeight = grid.selectors.selectAggregationEnabled(state) ? grid.selectors.selectRowHeight(state) : 0 const headerHeight = grid.selectors.selectHeaderHeight(state) const sticky = grid.selectors.selectStickyColumnDetails(state) const columnIsSticky = sticky.indexes.has(columnIndex) if (area === 'body') { ensureVisibleVertical(cell, scroller, footerHeight, headerHeight) } if (!columnIsSticky) { ensureVisibleHorizontal( cell, scroller, sticky.left.width, sticky.right.width ) } }