UNPKG

@wordpress/components

Version:
412 lines (397 loc) 15 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DEFAULT_UNIT = exports.CSS_UNITS = exports.ALL_CSS_UNITS = void 0; exports.filterUnitsWithSettings = filterUnitsWithSettings; exports.getAccessibleLabelForUnit = getAccessibleLabelForUnit; exports.getParsedQuantityAndUnit = getParsedQuantityAndUnit; exports.getUnitsWithCurrentUnit = getUnitsWithCurrentUnit; exports.getValidParsedQuantityAndUnit = getValidParsedQuantityAndUnit; exports.hasUnits = hasUnits; exports.parseQuantityAndUnitFromRawValue = parseQuantityAndUnitFromRawValue; exports.useCustomUnits = void 0; var _i18n = require("@wordpress/i18n"); var _element = require("@wordpress/element"); /** * WordPress dependencies */ /** * Internal dependencies */ const isWeb = _element.Platform.OS === 'web'; const allUnits = { px: { value: 'px', label: isWeb ? 'px' : (0, _i18n.__)('Pixels (px)'), a11yLabel: (0, _i18n.__)('Pixels (px)'), step: 1 }, '%': { value: '%', label: isWeb ? '%' : (0, _i18n.__)('Percentage (%)'), a11yLabel: (0, _i18n.__)('Percent (%)'), step: 0.1 }, em: { value: 'em', label: isWeb ? 'em' : (0, _i18n.__)('Relative to parent font size (em)'), a11yLabel: (0, _i18n._x)('ems', 'Relative to parent font size (em)'), step: 0.01 }, rem: { value: 'rem', label: isWeb ? 'rem' : (0, _i18n.__)('Relative to root font size (rem)'), a11yLabel: (0, _i18n._x)('rems', 'Relative to root font size (rem)'), step: 0.01 }, vw: { value: 'vw', label: isWeb ? 'vw' : (0, _i18n.__)('Viewport width (vw)'), a11yLabel: (0, _i18n.__)('Viewport width (vw)'), step: 0.1 }, vh: { value: 'vh', label: isWeb ? 'vh' : (0, _i18n.__)('Viewport height (vh)'), a11yLabel: (0, _i18n.__)('Viewport height (vh)'), step: 0.1 }, vmin: { value: 'vmin', label: isWeb ? 'vmin' : (0, _i18n.__)('Viewport smallest dimension (vmin)'), a11yLabel: (0, _i18n.__)('Viewport smallest dimension (vmin)'), step: 0.1 }, vmax: { value: 'vmax', label: isWeb ? 'vmax' : (0, _i18n.__)('Viewport largest dimension (vmax)'), a11yLabel: (0, _i18n.__)('Viewport largest dimension (vmax)'), step: 0.1 }, ch: { value: 'ch', label: isWeb ? 'ch' : (0, _i18n.__)('Width of the zero (0) character (ch)'), a11yLabel: (0, _i18n.__)('Width of the zero (0) character (ch)'), step: 0.01 }, ex: { value: 'ex', label: isWeb ? 'ex' : (0, _i18n.__)('x-height of the font (ex)'), a11yLabel: (0, _i18n.__)('x-height of the font (ex)'), step: 0.01 }, cm: { value: 'cm', label: isWeb ? 'cm' : (0, _i18n.__)('Centimeters (cm)'), a11yLabel: (0, _i18n.__)('Centimeters (cm)'), step: 0.001 }, mm: { value: 'mm', label: isWeb ? 'mm' : (0, _i18n.__)('Millimeters (mm)'), a11yLabel: (0, _i18n.__)('Millimeters (mm)'), step: 0.1 }, in: { value: 'in', label: isWeb ? 'in' : (0, _i18n.__)('Inches (in)'), a11yLabel: (0, _i18n.__)('Inches (in)'), step: 0.001 }, pc: { value: 'pc', label: isWeb ? 'pc' : (0, _i18n.__)('Picas (pc)'), a11yLabel: (0, _i18n.__)('Picas (pc)'), step: 1 }, pt: { value: 'pt', label: isWeb ? 'pt' : (0, _i18n.__)('Points (pt)'), a11yLabel: (0, _i18n.__)('Points (pt)'), step: 1 }, svw: { value: 'svw', label: isWeb ? 'svw' : (0, _i18n.__)('Small viewport width (svw)'), a11yLabel: (0, _i18n.__)('Small viewport width (svw)'), step: 0.1 }, svh: { value: 'svh', label: isWeb ? 'svh' : (0, _i18n.__)('Small viewport height (svh)'), a11yLabel: (0, _i18n.__)('Small viewport height (svh)'), step: 0.1 }, svi: { value: 'svi', label: isWeb ? 'svi' : (0, _i18n.__)('Viewport smallest size in the inline direction (svi)'), a11yLabel: (0, _i18n.__)('Small viewport width or height (svi)'), step: 0.1 }, svb: { value: 'svb', label: isWeb ? 'svb' : (0, _i18n.__)('Viewport smallest size in the block direction (svb)'), a11yLabel: (0, _i18n.__)('Small viewport width or height (svb)'), step: 0.1 }, svmin: { value: 'svmin', label: isWeb ? 'svmin' : (0, _i18n.__)('Small viewport smallest dimension (svmin)'), a11yLabel: (0, _i18n.__)('Small viewport smallest dimension (svmin)'), step: 0.1 }, lvw: { value: 'lvw', label: isWeb ? 'lvw' : (0, _i18n.__)('Large viewport width (lvw)'), a11yLabel: (0, _i18n.__)('Large viewport width (lvw)'), step: 0.1 }, lvh: { value: 'lvh', label: isWeb ? 'lvh' : (0, _i18n.__)('Large viewport height (lvh)'), a11yLabel: (0, _i18n.__)('Large viewport height (lvh)'), step: 0.1 }, lvi: { value: 'lvi', label: isWeb ? 'lvi' : (0, _i18n.__)('Large viewport width or height (lvi)'), a11yLabel: (0, _i18n.__)('Large viewport width or height (lvi)'), step: 0.1 }, lvb: { value: 'lvb', label: isWeb ? 'lvb' : (0, _i18n.__)('Large viewport width or height (lvb)'), a11yLabel: (0, _i18n.__)('Large viewport width or height (lvb)'), step: 0.1 }, lvmin: { value: 'lvmin', label: isWeb ? 'lvmin' : (0, _i18n.__)('Large viewport smallest dimension (lvmin)'), a11yLabel: (0, _i18n.__)('Large viewport smallest dimension (lvmin)'), step: 0.1 }, dvw: { value: 'dvw', label: isWeb ? 'dvw' : (0, _i18n.__)('Dynamic viewport width (dvw)'), a11yLabel: (0, _i18n.__)('Dynamic viewport width (dvw)'), step: 0.1 }, dvh: { value: 'dvh', label: isWeb ? 'dvh' : (0, _i18n.__)('Dynamic viewport height (dvh)'), a11yLabel: (0, _i18n.__)('Dynamic viewport height (dvh)'), step: 0.1 }, dvi: { value: 'dvi', label: isWeb ? 'dvi' : (0, _i18n.__)('Dynamic viewport width or height (dvi)'), a11yLabel: (0, _i18n.__)('Dynamic viewport width or height (dvi)'), step: 0.1 }, dvb: { value: 'dvb', label: isWeb ? 'dvb' : (0, _i18n.__)('Dynamic viewport width or height (dvb)'), a11yLabel: (0, _i18n.__)('Dynamic viewport width or height (dvb)'), step: 0.1 }, dvmin: { value: 'dvmin', label: isWeb ? 'dvmin' : (0, _i18n.__)('Dynamic viewport smallest dimension (dvmin)'), a11yLabel: (0, _i18n.__)('Dynamic viewport smallest dimension (dvmin)'), step: 0.1 }, dvmax: { value: 'dvmax', label: isWeb ? 'dvmax' : (0, _i18n.__)('Dynamic viewport largest dimension (dvmax)'), a11yLabel: (0, _i18n.__)('Dynamic viewport largest dimension (dvmax)'), step: 0.1 }, svmax: { value: 'svmax', label: isWeb ? 'svmax' : (0, _i18n.__)('Small viewport largest dimension (svmax)'), a11yLabel: (0, _i18n.__)('Small viewport largest dimension (svmax)'), step: 0.1 }, lvmax: { value: 'lvmax', label: isWeb ? 'lvmax' : (0, _i18n.__)('Large viewport largest dimension (lvmax)'), a11yLabel: (0, _i18n.__)('Large viewport largest dimension (lvmax)'), step: 0.1 } }; /** * An array of all available CSS length units. */ const ALL_CSS_UNITS = exports.ALL_CSS_UNITS = Object.values(allUnits); /** * Units of measurements. `a11yLabel` is used by screenreaders. */ const CSS_UNITS = exports.CSS_UNITS = [allUnits.px, allUnits['%'], allUnits.em, allUnits.rem, allUnits.vw, allUnits.vh]; const DEFAULT_UNIT = exports.DEFAULT_UNIT = allUnits.px; /** * Handles legacy value + unit handling. * This component use to manage both incoming value and units separately. * * Moving forward, ideally the value should be a string that contains both * the value and unit, example: '10px' * * @param rawValue The raw value as a string (may or may not contain the unit) * @param fallbackUnit The unit used as a fallback, if not unit is detected in the `value` * @param allowedUnits Units to derive from. * @return The extracted quantity and unit. The quantity can be `undefined` in case the raw value * could not be parsed to a number correctly. The unit can be `undefined` in case the unit parse * from the raw value could not be matched against the list of allowed units. */ function getParsedQuantityAndUnit(rawValue, fallbackUnit, allowedUnits) { const initialValue = fallbackUnit ? `${rawValue !== null && rawValue !== void 0 ? rawValue : ''}${fallbackUnit}` : rawValue; return parseQuantityAndUnitFromRawValue(initialValue, allowedUnits); } /** * Checks if units are defined. * * @param units List of units. * @return Whether the list actually contains any units. */ function hasUnits(units) { // Although the `isArray` check shouldn't be necessary (given the signature of // this typed function), it's better to stay on the side of caution, since // this function may be called from un-typed environments. return Array.isArray(units) && !!units.length; } /** * Parses a quantity and unit from a raw string value, given a list of allowed * units and otherwise falling back to the default unit. * * @param rawValue The raw value as a string (may or may not contain the unit) * @param allowedUnits Units to derive from. * @return The extracted quantity and unit. The quantity can be `undefined` in case the raw value * could not be parsed to a number correctly. The unit can be `undefined` in case the unit parsed * from the raw value could not be matched against the list of allowed units. */ function parseQuantityAndUnitFromRawValue(rawValue, allowedUnits = ALL_CSS_UNITS) { let trimmedValue; let quantityToReturn; if (typeof rawValue !== 'undefined' || rawValue === null) { trimmedValue = `${rawValue}`.trim(); const parsedQuantity = parseFloat(trimmedValue); quantityToReturn = !isFinite(parsedQuantity) ? undefined : parsedQuantity; } const unitMatch = trimmedValue?.match(/[\d.\-\+]*\s*(.*)/); const matchedUnit = unitMatch?.[1]?.toLowerCase(); let unitToReturn; if (hasUnits(allowedUnits)) { const match = allowedUnits.find(item => item.value === matchedUnit); unitToReturn = match?.value; } else { unitToReturn = DEFAULT_UNIT.value; } return [quantityToReturn, unitToReturn]; } /** * Parses quantity and unit from a raw value. Validates parsed value, using fallback * value if invalid. * * @param rawValue The next value. * @param allowedUnits Units to derive from. * @param fallbackQuantity The fallback quantity, used in case it's not possible to parse a valid quantity from the raw value. * @param fallbackUnit The fallback unit, used in case it's not possible to parse a valid unit from the raw value. * @return The extracted quantity and unit. The quantity can be `undefined` in case the raw value * could not be parsed to a number correctly, and the `fallbackQuantity` was also `undefined`. The * unit can be `undefined` only if the unit parsed from the raw value could not be matched against * the list of allowed units, the `fallbackQuantity` is also `undefined` and the list of * `allowedUnits` is passed empty. */ function getValidParsedQuantityAndUnit(rawValue, allowedUnits, fallbackQuantity, fallbackUnit) { const [parsedQuantity, parsedUnit] = parseQuantityAndUnitFromRawValue(rawValue, allowedUnits); // The parsed value from `parseQuantityAndUnitFromRawValue` should now be // either a real number or undefined. If undefined, use the fallback value. const quantityToReturn = parsedQuantity !== null && parsedQuantity !== void 0 ? parsedQuantity : fallbackQuantity; // If no unit is parsed from the raw value, or if the fallback unit is not // defined, use the first value from the list of allowed units as fallback. let unitToReturn = parsedUnit || fallbackUnit; if (!unitToReturn && hasUnits(allowedUnits)) { unitToReturn = allowedUnits[0].value; } return [quantityToReturn, unitToReturn]; } /** * Takes a unit value and finds the matching accessibility label for the * unit abbreviation. * * @param unit Unit value (example: `px`) * @return a11y label for the unit abbreviation */ function getAccessibleLabelForUnit(unit) { const match = ALL_CSS_UNITS.find(item => item.value === unit); return match?.a11yLabel ? match?.a11yLabel : match?.value; } /** * Filters available units based on values defined a list of allowed unit values. * * @param allowedUnitValues Collection of allowed unit value strings. * @param availableUnits Collection of available unit objects. * @return Filtered units. */ function filterUnitsWithSettings(allowedUnitValues = [], availableUnits) { // Although the `isArray` check shouldn't be necessary (given the signature of // this typed function), it's better to stay on the side of caution, since // this function may be called from un-typed environments. return Array.isArray(availableUnits) ? availableUnits.filter(unit => allowedUnitValues.includes(unit.value)) : []; } /** * Custom hook to retrieve and consolidate units setting from add_theme_support(). * TODO: ideally this hook shouldn't be needed * https://github.com/WordPress/gutenberg/pull/31822#discussion_r633280823 * * @param args An object containing units, settingPath & defaultUnits. * @param args.units Collection of all potentially available units. * @param args.availableUnits Collection of unit value strings for filtering available units. * @param args.defaultValues Collection of default values for defined units. Example: `{ px: 350, em: 15 }`. * * @return Filtered list of units, with their default values updated following the `defaultValues` * argument's property. */ const useCustomUnits = ({ units = ALL_CSS_UNITS, availableUnits = [], defaultValues }) => { const customUnitsToReturn = filterUnitsWithSettings(availableUnits, units); if (!defaultValues) { return customUnitsToReturn; } return customUnitsToReturn.map(unit => { const [defaultValue] = defaultValues[unit.value] ? parseQuantityAndUnitFromRawValue(defaultValues[unit.value]) : []; return { ...unit, default: defaultValue }; }); }; /** * Get available units with the unit for the currently selected value * prepended if it is not available in the list of units. * * This is useful to ensure that the current value's unit is always * accurately displayed in the UI, even if the intention is to hide * the availability of that unit. * * @param rawValue Selected value to parse. * @param legacyUnit Legacy unit value, if rawValue needs it appended. * @param units List of available units. * * @return A collection of units containing the unit for the current value. */ exports.useCustomUnits = useCustomUnits; function getUnitsWithCurrentUnit(rawValue, legacyUnit, units = ALL_CSS_UNITS) { const unitsToReturn = Array.isArray(units) ? [...units] : []; const [, currentUnit] = getParsedQuantityAndUnit(rawValue, legacyUnit, ALL_CSS_UNITS); if (currentUnit && !unitsToReturn.some(unit => unit.value === currentUnit)) { if (allUnits[currentUnit]) { unitsToReturn.unshift(allUnits[currentUnit]); } } return unitsToReturn; } //# sourceMappingURL=utils.js.map