import React from "react";
/**
* Groups HTML elements by their vertical position (top coordinate)
* and includes bottom position information
*/
export interface NodePosition {
elements: Set;
bottom: number;
top: number;
}
export function groupNodesByTopPosition(nodes: HTMLElement[]): Record {
if (nodes.length === 0) return {};
const result: Record = {};
let lastRowKey: number | undefined;
nodes.forEach((node) => {
const rect = node.getBoundingClientRect();
const top = Math.round(rect.top);
const bottom = Math.round(rect.bottom);
// Check if this element overlaps vertically with the last row
const lastRow = lastRowKey !== undefined ? result[lastRowKey] : undefined;
if (lastRow && top < lastRow.bottom && bottom > lastRow.top) {
lastRow.top = Math.min(lastRow.top, top);
lastRow.bottom = Math.max(lastRow.bottom, bottom);
lastRow.elements.add(node);
} else {
result[top] = {
elements: new Set(),
bottom: bottom,
top: top,
};
result[top].elements.add(node);
lastRowKey = top;
}
});
return result;
}
/**
* Helper function to get row information from container
* Returns itemsSizesMap, rowPositions, and children or null if the container is not available
*/
export function getRowPositionsData(
containerRef: React.RefObject,
overflowRef: React.RefObject,
): {
itemsSizesMap: Record;
rowPositions: number[];
children: HTMLElement[];
} | null {
if (!containerRef.current) return null;
const container = containerRef.current;
const children = Array.from(container.children).filter((child) => overflowRef.current !== child) as HTMLElement[];
if (children.length === 0) return null;
// Group elements by their vertical position (rows)
const itemsSizesMap = groupNodesByTopPosition(children);
// Get all the vertical positions (rows)
const rowPositions = Object.keys(itemsSizesMap).map(Number);
return { itemsSizesMap, rowPositions, children };
}