export function useExtendSelectionNextAvailable()

in frontend/libs/canvasSpreadsheet/src/lib/hooks/useExtendSelectionNextAvailable.ts [9:190]


export function useExtendSelectionNextAvailable() {
  const {
    gridSizes,
    selectionEdges,
    getCell,
    tableStructure,
    setSelectionEdges,
  } = useContext(GridStateContext);

  const createSingleSelectionFromRangeSelection = useCallback(
    (
      selection: Edges,
      direction: HorizontalDirection | VerticalDirection
    ): Edges => {
      const { startRow, endRow, startCol, endCol } = selection;
      let cell;

      switch (direction) {
        case 'up':
          return {
            startRow: Math.min(startRow, endRow),
            endRow: Math.min(startRow, endRow),
            startCol: startCol,
            endCol: startCol,
          };
        case 'down':
          return {
            startRow: endRow,
            startCol: endCol,
            endRow: endRow,
            endCol: endCol,
          };
        case 'left':
          cell = getCell(endCol, startRow);

          return {
            startCol: cell?.startCol || endCol,
            endCol: cell?.startCol || endCol,
            startRow: startRow,
            endRow: startRow,
          };
        case 'right':
          return {
            startCol: Math.max(startCol, endCol),
            endCol: Math.max(startCol, endCol),
            startRow: startRow,
            endRow: startRow,
          };
      }
    },
    [getCell]
  );

  const checkIsNavigateInsideTable = useCallback(
    (
      selection: Edges,
      direction: HorizontalDirection | VerticalDirection
    ): Edges | null => {
      for (const table of tableStructure) {
        const { startRow, endRow, startCol, endCol } = table;
        let col = undefined;
        let row = undefined;

        const isInsideTable =
          selection.startRow >= startRow &&
          selection.startRow <= endRow &&
          selection.startCol >= startCol &&
          selection.startCol <= endCol;

        const cell = getCell(selection.startCol, selection.startRow);
        const isTableHeader = cell?.isTableHeader;

        const isNotOnTableEdge =
          (direction === 'right' && selection.startCol < endCol) ||
          (direction === 'left' && selection.startCol > startCol) ||
          (direction === 'up' && selection.startRow > startRow) ||
          (direction === 'down' && selection.startRow < endRow);

        if (isInsideTable && isNotOnTableEdge && !isTableHeader) {
          if (direction === 'right') {
            col = endCol;
            row = selection.startRow;
          }

          if (direction === 'left') {
            col = startCol;
            row = selection.startRow;
          }

          if (direction === 'up') {
            col = selection.startCol;
            row = startRow;
          }

          if (direction === 'down') {
            col = selection.startCol;
            row = Math.min(gridSizes.edges.row, endRow) - 1;
          }

          if (col !== undefined && row !== undefined) {
            return {
              startCol: col,
              endCol: col,
              startRow: row,
              endRow: row,
            };
          }
        }
      }

      return null;
    },
    [getCell, gridSizes, tableStructure]
  );

  const extendSelectionNextAvailable = useCallback(
    (direction: HorizontalDirection | VerticalDirection) => {
      if (!selectionEdges) return;

      const singleSelection = createSingleSelectionFromRangeSelection(
        selectionEdges,
        direction
      );

      if (!singleSelection) return null;

      const updatedSelection = checkIsNavigateInsideTable(
        singleSelection,
        direction
      );

      if (updatedSelection) {
        setSelectionEdges(
          convertSingleSelectionToRange(
            selectionEdges,
            updatedSelection,
            direction
          )
        );

        return;
      }

      const nextTable = findNextTableToNavigate(
        tableStructure,
        singleSelection,
        direction
      );

      if (!nextTable) {
        const { edges } = gridSizes;

        setSelectionEdges(
          extendSelectionToSheet(
            selectionEdges,
            direction,
            edges.row,
            edges.col
          )
        );

        return;
      }

      return setSelectionEdges(
        extendSelectionToTable(selectionEdges, nextTable, direction)
      );
    },
    [
      checkIsNavigateInsideTable,
      createSingleSelectionFromRangeSelection,
      gridSizes,
      selectionEdges,
      setSelectionEdges,
      tableStructure,
    ]
  );

  return {
    extendSelectionNextAvailable,
  };
}