@wordpress/block-library
Version:
Block library for the WordPress editor.
179 lines (157 loc) • 5.4 kB
JavaScript
/**
* WordPress dependencies
*/
import {
ALIGNMENT_BREAKPOINTS,
convertUnitToMobile,
} from '@wordpress/components';
/**
* Internal dependencies
*/
import { getColumnWidths, getWidths } from './utils';
import styles from './editor.scss';
/**
* Maximum number of columns in a row
*
* @type {number}
*/
const MAX_COLUMNS_NUM_IN_ROW = 3;
/**
* Minimum width of column
*
* @type {number}
*/
const MIN_WIDTH = styles.columnsContainer?.minWidth;
/**
* Container margin value
*
* @type {number}
*/
const MARGIN = styles.columnsContainer?.marginLeft;
export const getColumnsInRow = ( width, columnCount ) => {
if ( width ) {
if ( width < ALIGNMENT_BREAKPOINTS.mobile ) {
// show only 1 Column in row for mobile breakpoint container width
return 1;
} else if ( width <= ALIGNMENT_BREAKPOINTS.medium ) {
// show the maximum number of columns in a row for large breakpoint container width
return Math.min(
Math.max( 1, columnCount ),
MAX_COLUMNS_NUM_IN_ROW
);
}
// Show all Column in one row.
return columnCount;
}
};
export const calculateContainerWidth = ( containerWidth, columnsInRow ) =>
2 * MARGIN + containerWidth - columnsInRow * 2 * MARGIN;
export const getContentWidths = (
columnsInRow,
width,
columnCount,
innerColumns,
globalStyles
) => {
const widths = {};
const columnWidthsWithUnits = getWidths( innerColumns, false );
const columnWidths = getColumnWidths( innerColumns, columnCount );
// Array of column width attribute values
const columnWidthsValues = columnWidthsWithUnits.map( ( v ) =>
convertUnitToMobile( { width }, globalStyles, v )
);
// The sum of column width attribute values
const columnWidthsSum = columnWidthsValues.reduce(
( acc, curr ) => acc + curr,
0
);
// Array of ratios of each column width attribute value to their sum
const columnRatios = columnWidthsValues.map(
( colWidth ) => colWidth / columnWidthsSum
);
// Array of calculated column width for its ratio
const columnWidthsPerRatio = columnRatios.map(
( columnRatio ) =>
columnRatio * calculateContainerWidth( width, columnsInRow )
);
// Array of columns whose calculated width is lower than minimum width value
const filteredColumnWidthsPerRatio = columnWidthsPerRatio.filter(
( columnWidthPerRatio ) => columnWidthPerRatio <= MIN_WIDTH
);
// Container width to be divided. If there are some results within `filteredColumnWidthsPerRatio`
// there is a need to reduce the main width by multiplying number
// of results in `filteredColumnWidthsPerRatio` and minimum width value
const baseContainerWidth =
width - filteredColumnWidthsPerRatio.length * MIN_WIDTH;
// The minimum percentage ratio for which column width is equal minimum width value
const minPercentageRatio =
MIN_WIDTH / calculateContainerWidth( width, columnsInRow );
// The sum of column widths which ratio is higher than `minPercentageRatio`
const largeColumnsWidthsSum = columnRatios
.map( ( ratio, index ) => {
if ( ratio > minPercentageRatio ) {
return columnWidthsValues[ index ];
}
return 0;
} )
.reduce( ( acc, curr ) => acc + curr, 0 );
const containerWidth = calculateContainerWidth(
baseContainerWidth,
columnsInRow
);
let columnWidth =
calculateContainerWidth( width, columnsInRow ) / columnsInRow;
let maxColumnWidth = columnWidth;
innerColumns.forEach(
( { attributes: innerColumnAttributes, clientId } ) => {
const attributeWidth = convertUnitToMobile(
{ width },
globalStyles,
innerColumnAttributes.width || columnWidths[ clientId ]
);
const proportionalRatio = attributeWidth / columnWidthsSum;
const percentageRatio = attributeWidth / width;
const initialColumnWidth = proportionalRatio * containerWidth;
if ( columnCount === 1 && width > ALIGNMENT_BREAKPOINTS.medium ) {
// Exactly one column inside columns on the breakpoint higher than medium
// has to take a percentage of the full width
columnWidth = percentageRatio * containerWidth;
} else if ( columnsInRow > 1 ) {
if ( width > ALIGNMENT_BREAKPOINTS.medium ) {
if ( initialColumnWidth <= MIN_WIDTH ) {
// Column width cannot be lower than minimum 32px
columnWidth = MIN_WIDTH;
} else if ( initialColumnWidth > MIN_WIDTH ) {
// Column width has to be the result of multiplying the container width and
// the ratio of attribute and the sum of widths of columns wider than 32px
columnWidth =
( attributeWidth / largeColumnsWidthsSum ) *
containerWidth;
}
maxColumnWidth = columnWidth;
if ( Math.round( columnWidthsSum ) < width ) {
// In case that column width attribute values does not exceed 100, each column
// should have attribute percentage of container width
const newColumnWidth = percentageRatio * containerWidth;
if ( newColumnWidth <= MIN_WIDTH ) {
columnWidth = MIN_WIDTH;
} else {
columnWidth = newColumnWidth;
}
}
} else if ( width < ALIGNMENT_BREAKPOINTS.medium ) {
// On the breakpoint lower than medium each column inside columns
// has to take equal part of container width
columnWidth =
calculateContainerWidth( width, columnsInRow ) /
columnsInRow;
}
}
widths[ clientId ] = {
width: Math.floor( columnWidth ),
maxWidth: Math.floor( maxColumnWidth ),
};
}
);
return widths;
};