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 }; }