import { Column, Row, VisibilityState } from "@tanstack/react-table" import { ScrollToOptions, Virtualizer } from "@tanstack/react-virtual" import { Dispatch, SetStateAction, useCallback } from "react" import { FieldValues } from "react-hook-form" import { DataGridMatrix, DataGridQueryTool } from "../models" import { DataGridCoordinates } from "../types" type UseDataGridNavigationOptions = { matrix: DataGridMatrix anchor: DataGridCoordinates | null visibleRows: Row[] visibleColumns: Column[] rowVirtualizer: Virtualizer columnVirtualizer: Virtualizer setColumnVisibility: Dispatch> flatColumns: Column[] queryTool: DataGridQueryTool | null setSingleRange: (coords: DataGridCoordinates | null) => void } export const useDataGridNavigation = ({ matrix, anchor, visibleColumns, visibleRows, columnVirtualizer, rowVirtualizer, setColumnVisibility, flatColumns, queryTool, setSingleRange, }: UseDataGridNavigationOptions) => { const scrollToCoordinates = useCallback( ( coords: DataGridCoordinates, direction: "horizontal" | "vertical" | "both" ) => { if (!anchor) { return } const { row, col } = coords const { row: anchorRow, col: anchorCol } = anchor const rowDirection = row >= anchorRow ? "down" : "up" const colDirection = col >= anchorCol ? "right" : "left" let toRow = rowDirection === "down" ? row + 1 : row - 1 if (visibleRows[toRow] === undefined) { toRow = row } let toCol = colDirection === "right" ? col + 1 : col - 1 if (visibleColumns[toCol] === undefined) { toCol = col } const scrollOptions: ScrollToOptions = { align: "auto", behavior: "auto" } if (direction === "horizontal" || direction === "both") { columnVirtualizer.scrollToIndex(toCol, scrollOptions) } if (direction === "vertical" || direction === "both") { rowVirtualizer.scrollToIndex(toRow, scrollOptions) } }, [anchor, columnVirtualizer, visibleRows, rowVirtualizer, visibleColumns] ) const navigateToField = useCallback( (field: string) => { const coords = matrix.getCoordinatesByField(field) if (!coords) { return } const column = flatColumns[coords.col] // Ensure that the column is visible setColumnVisibility((prev) => { return { ...prev, [column.id]: true, } }) requestAnimationFrame(() => { scrollToCoordinates(coords, "both") setSingleRange(coords) }) requestAnimationFrame(() => { const input = queryTool?.getInput(coords) if (input) { input.focus() } }) }, [ matrix, flatColumns, setColumnVisibility, scrollToCoordinates, setSingleRange, queryTool, ] ) return { scrollToCoordinates, navigateToField, } }