@cloakui/utils
Version:
Shared utilities for all CloakUI component packages.
42 lines (41 loc) • 2.88 kB
JavaScript
/**
* getGridLayoutFromColumnWidths
*
* @description -- given an array of numbers representing the percentage widths of columns in a grid, this function returns an object with two properties: `gridCols` (the number of grid-template-columns to use) and `colSpans` (an array of the percentage values represented as corresponding column span values). All the `colSpans` values add up to the `gridCols` value. The maximum `gridCols` value is `12`. The function should optimize for finding the smallest possible number of `gridCols` to use given the percentages provided.
*
* @examples -- the following examples illustrate the expected return values:
* getGridLayoutFromColumnWidths([50, 50]); // ==> { gridCols: 2, colSpans: [1, 1] }
* getGridLayoutFromColumnWidths([33, 33, 33]); // ==> { gridCols: 3, colSpans: [1, 1, 1] }
* getGridLayoutFromColumnWidths([50, 25, 25]); // ==> { gridCols: 4, colSpans: [2, 1, 1] }
* getGridLayoutFromColumnWidths([46, 8, 12, 34]); // ==> { gridCols: 10, colSpans: [5, 1, 1, 3] }
* getGridLayoutFromColumnWidths([40, 60]); // ==> { gridCols: 5, colSpans: [2, 3] }
*
* When the %s don't add up to 100, we adjust them proportionally so they add up to 100 before converting to colSpans:
* --> getGridLayoutFromColumnWidths([50, 70]); // ==> { gridCols: 5, colSpans: [2, 3] }
*/
export const getGridLayoutFromColumnWidths = (percentages, maxGridCols = 12) => {
// Normalize percentages if they don't sum to 100
const total = percentages.reduce((sum, current) => sum + current, 0);
percentages = percentages.map((p) => (p / total) * 100);
// Function to find "Greatest Common Divisor" (GCD) of two numbers
const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
// Utility to find GCD for an array of numbers
const gcdArray = (arr) => arr.reduce((a, b) => gcd(a, b));
// Scale percentages to avoid large numbers and find GCD
const scaledPercentages = percentages.map((p) => Math.round(p * 100));
const commonDivisor = gcdArray(scaledPercentages);
// Calculate colSpans based on GCD, ensuring they're integers and maintain the ratio
let colSpans = scaledPercentages.map((p) => p / commonDivisor);
let gridCols = colSpans.reduce((a, b) => a + b, 0);
// Reduce gridCols and colSpans if gridCols is greater than maxGridCols
if (gridCols > maxGridCols) {
const reductionFactor = Math.ceil(gridCols / maxGridCols);
colSpans = colSpans.map((span) => Math.round(span / reductionFactor));
gridCols = colSpans.reduce((a, b) => a + b, 0);
}
// Further adjust colSpans and gridCols to ensure the lowest possible consistent ratio
const finalCommonDivisor = gcdArray(colSpans);
colSpans = colSpans.map((span) => span / finalCommonDivisor);
gridCols = colSpans.reduce((a, b) => a + b, 0);
return { gridCols, colSpans };
};