/** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import { parseQuantityAndUnitFromRawValue } from '../unit-control/utils'; export const CUSTOM_VALUE_SETTINGS = { px: { max: 300, step: 1 }, '%': { max: 100, step: 1 }, vw: { max: 100, step: 1 }, vh: { max: 100, step: 1 }, em: { max: 10, step: 0.1 }, rm: { max: 10, step: 0.1 }, svw: { max: 100, step: 1 }, lvw: { max: 100, step: 1 }, dvw: { max: 100, step: 1 }, svh: { max: 100, step: 1 }, lvh: { max: 100, step: 1 }, dvh: { max: 100, step: 1 }, vi: { max: 100, step: 1 }, svi: { max: 100, step: 1 }, lvi: { max: 100, step: 1 }, dvi: { max: 100, step: 1 }, vb: { max: 100, step: 1 }, svb: { max: 100, step: 1 }, lvb: { max: 100, step: 1 }, dvb: { max: 100, step: 1 }, vmin: { max: 100, step: 1 }, svmin: { max: 100, step: 1 }, lvmin: { max: 100, step: 1 }, dvmin: { max: 100, step: 1 }, vmax: { max: 100, step: 1 }, svmax: { max: 100, step: 1 }, lvmax: { max: 100, step: 1 }, dvmax: { max: 100, step: 1 } }; export const LABELS = { all: __('All sides'), top: __('Top side'), bottom: __('Bottom side'), left: __('Left side'), right: __('Right side'), mixed: __('Mixed'), vertical: __('Top and bottom sides'), horizontal: __('Left and right sides') }; export const DEFAULT_VALUES = { top: undefined, right: undefined, bottom: undefined, left: undefined }; export const ALL_SIDES = ['top', 'right', 'bottom', 'left']; /** * Gets an items with the most occurrence within an array * https://stackoverflow.com/a/20762713 * * @param arr Array of items to check. * @return The item with the most occurrences. */ function mode(arr) { return arr.sort((a, b) => arr.filter(v => v === a).length - arr.filter(v => v === b).length).pop(); } /** * Gets the 'all' input value and unit from values data. * * @param values Box values. * @param selectedUnits Box units. * @param availableSides Available box sides to evaluate. * * @return A value + unit for the 'all' input. */ export function getAllValue(values = {}, selectedUnits, availableSides = ALL_SIDES) { const sides = normalizeSides(availableSides); const parsedQuantitiesAndUnits = sides.map(side => parseQuantityAndUnitFromRawValue(values[side])); const allParsedQuantities = parsedQuantitiesAndUnits.map(value => { var _value$; return (_value$ = value[0]) !== null && _value$ !== void 0 ? _value$ : ''; }); const allParsedUnits = parsedQuantitiesAndUnits.map(value => value[1]); const commonQuantity = allParsedQuantities.every(v => v === allParsedQuantities[0]) ? allParsedQuantities[0] : ''; /** * The typeof === 'number' check is important. On reset actions, the incoming value * may be null or an empty string. * * Also, the value may also be zero (0), which is considered a valid unit value. * * typeof === 'number' is more specific for these cases, rather than relying on a * simple truthy check. */ let commonUnit; if (typeof commonQuantity === 'number') { commonUnit = mode(allParsedUnits); } else { var _getAllUnitFallback; // Set meaningful unit selection if no commonQuantity and user has previously // selected units without assigning values while controls were unlinked. commonUnit = (_getAllUnitFallback = getAllUnitFallback(selectedUnits)) !== null && _getAllUnitFallback !== void 0 ? _getAllUnitFallback : mode(allParsedUnits); } return [commonQuantity, commonUnit].join(''); } /** * Determine the most common unit selection to use as a fallback option. * * @param selectedUnits Current unit selections for individual sides. * @return Most common unit selection. */ export function getAllUnitFallback(selectedUnits) { if (!selectedUnits || typeof selectedUnits !== 'object') { return undefined; } const filteredUnits = Object.values(selectedUnits).filter(Boolean); return mode(filteredUnits); } /** * Checks to determine if values are mixed. * * @param values Box values. * @param selectedUnits Box units. * @param sides Available box sides to evaluate. * * @return Whether values are mixed. */ export function isValuesMixed(values = {}, selectedUnits, sides = ALL_SIDES) { const allValue = getAllValue(values, selectedUnits, sides); const isMixed = isNaN(parseFloat(allValue)); return isMixed; } /** * Checks to determine if values are defined. * * @param values Box values. * * @return Whether values are mixed. */ export function isValuesDefined(values) { return values !== undefined && Object.values(values).filter( // Switching units when input is empty causes values only // containing units. This gives false positive on mixed values // unless filtered. value => !!value && /\d/.test(value)).length > 0; } /** * Get initial selected side, factoring in whether the sides are linked, * and whether the vertical / horizontal directions are grouped via splitOnAxis. * * @param isLinked Whether the box control's fields are linked. * @param splitOnAxis Whether splitting by horizontal or vertical axis. * @return The initial side. */ export function getInitialSide(isLinked, splitOnAxis) { let initialSide = 'all'; if (!isLinked) { initialSide = splitOnAxis ? 'vertical' : 'top'; } return initialSide; } /** * Normalizes provided sides configuration to an array containing only top, * right, bottom and left. This essentially just maps `horizontal` or `vertical` * to their appropriate sides to facilitate correctly determining value for * all input control. * * @param sides Available sides for box control. * @return Normalized sides configuration. */ export function normalizeSides(sides) { const filteredSides = []; if (!sides?.length) { return ALL_SIDES; } if (sides.includes('vertical')) { filteredSides.push(...['top', 'bottom']); } else if (sides.includes('horizontal')) { filteredSides.push(...['left', 'right']); } else { const newSides = ALL_SIDES.filter(side => sides.includes(side)); filteredSides.push(...newSides); } return filteredSides; } /** * Applies a value to an object representing top, right, bottom and left sides * while taking into account any custom side configuration. * * @param currentValues The current values for each side. * @param newValue The value to apply to the sides object. * @param sides Array defining valid sides. * * @return Object containing the updated values for each side. */ export function applyValueToSides(currentValues, newValue, sides) { const newValues = { ...currentValues }; if (sides?.length) { sides.forEach(side => { if (side === 'vertical') { newValues.top = newValue; newValues.bottom = newValue; } else if (side === 'horizontal') { newValues.left = newValue; newValues.right = newValue; } else { newValues[side] = newValue; } }); } else { ALL_SIDES.forEach(side => newValues[side] = newValue); } return newValues; } //# sourceMappingURL=utils.js.map