UNPKG

react-native-flexible-grid

Version:

React Native Flexible Grid is an advanced grid layout system inspired by CSS Grid, designed to facilitate responsive, customizable, and dynamic grid layouts in React Native applications. It supports both responsive and fixed layouts, enabling the creation

126 lines (104 loc) 3.63 kB
import type { GridItem, TileItem } from './types'; export const calcResponsiveGrid = ( data: TileItem[], maxItemsPerColumn: number, containerWidth: number, itemUnitHeight?: number, autoAdjustItemWidth: boolean = true ): { gridItems: GridItem[]; gridViewHeight: number; } => { const gridItems: GridItem[] = []; const itemSizeUnit = containerWidth / maxItemsPerColumn; let columnHeights: number[] = new Array(maxItemsPerColumn).fill(0); const findAvailableWidth = ( startColumn: number, currentTop: number ): number => { // Check each column from the start position let availableWidth = 0; for (let i = startColumn; i < maxItemsPerColumn; i++) { // Check if there's any item from above rows protruding into this space const hasProtrudingItem = gridItems.some((item) => { const itemBottom = item.top + item.height; const itemRight = item.left + item.width; return ( item.top < currentTop && // Item starts above current row itemBottom > currentTop && // Item extends into current row item.left <= i * itemSizeUnit && // Item starts at or before this column itemRight > i * itemSizeUnit // Item extends into this column ); }); if (hasProtrudingItem) { break; // Stop counting available width when we hit a protruding item } availableWidth++; } return availableWidth; }; data.forEach((item) => { let widthRatio = item.widthRatio || 1; const heightRatio = item.heightRatio || 1; let columnIndex = findColumnForItem( columnHeights, widthRatio, maxItemsPerColumn ); if (autoAdjustItemWidth) { // Get current row's height at the column index const currentTop = columnHeights[columnIndex]; // Calculate available width considering both row end and protruding items const availableWidth = findAvailableWidth(columnIndex, currentTop!); // If widthRatio exceeds available space, adjust it if (widthRatio > availableWidth) { widthRatio = Math.max(1, availableWidth); } } const itemWidth = widthRatio * itemSizeUnit; const itemHeight = itemUnitHeight ? itemUnitHeight * heightRatio : heightRatio * itemSizeUnit; const top = columnHeights[columnIndex]!; const left = columnIndex * itemSizeUnit; gridItems.push({ ...item, top, left, width: itemWidth, height: itemHeight, }); // Update the column heights for (let i = columnIndex; i < columnIndex + widthRatio; i++) { columnHeights[i] = top + itemHeight; } }); return { gridItems, gridViewHeight: Math.max(...columnHeights), }; }; const findColumnForItem = ( columnHeights: number[], widthRatio: number, maxItemsPerColumn: number ) => { // If the item spans only one column, find the shortest column. if (widthRatio === 1) { return columnHeights.indexOf(Math.min(...columnHeights)); } // If the item spans multiple columns, find the first place it can fit. let minHeight = Math.min(...columnHeights); let columnIndex = columnHeights.indexOf(minHeight); for (let i = 0; i <= maxItemsPerColumn - widthRatio; i++) { // Check if the item can fit in the next 'widthRatio' columns. const columnsToCheck = columnHeights.slice(i, i + widthRatio); if (columnsToCheck.every((height) => height === minHeight)) { columnIndex = i; break; } // Find the next set of columns where the item can fit. minHeight = Math.min(...columnsToCheck); } return columnIndex; };