@gechiui/components
Version:
UI components for GeChiUI.
310 lines (286 loc) • 9.06 kB
JavaScript
/**
* GeChiUI dependencies
*/
import { __, _x } from '@gechiui/i18n';
import { Platform } from '@gechiui/element';
/**
* Internal dependencies
*/
const isWeb = Platform.OS === 'web';
const allUnits = {
px: {
value: 'px',
label: isWeb ? 'px' : __('像素(px)'),
default: '',
a11yLabel: __('像素(px)'),
step: 1
},
'%': {
value: '%',
label: isWeb ? '%' : __('百分比(%)'),
default: '',
a11yLabel: __('百分比(%)'),
step: 0.1
},
em: {
value: 'em',
label: isWeb ? 'em' : __('相对父字体大小(em)'),
default: '',
a11yLabel: _x('ems', '相对父字体大小(em)'),
step: 0.01
},
rem: {
value: 'rem',
label: isWeb ? 'rem' : __('相对主字体大小(rem)'),
default: '',
a11yLabel: _x('rems', '相对主字体大小(rem)'),
step: 0.01
},
vw: {
value: 'vw',
label: isWeb ? 'vw' : __('视口宽度(vw)'),
default: '',
a11yLabel: __('视口宽度(vw)'),
step: 0.1
},
vh: {
value: 'vh',
label: isWeb ? 'vh' : __('视口高度(vh)'),
default: '',
a11yLabel: __('视口高度(vh)'),
step: 0.1
},
vmin: {
value: 'vmin',
label: isWeb ? 'vmin' : __('视口最小尺寸(vmin)'),
default: '',
a11yLabel: __('视口最小尺寸(vmin)'),
step: 0.1
},
vmax: {
value: 'vmax',
label: isWeb ? 'vmax' : __('视口最大尺寸(vmax)'),
default: '',
a11yLabel: __('视口最大尺寸(vmax)'),
step: 0.1
},
ch: {
value: 'ch',
label: isWeb ? 'ch' : __('零(0)字符的宽度(ch)'),
default: '',
a11yLabel: __('零(0)字符的宽度(ch)'),
step: 0.01
},
ex: {
value: 'ex',
label: isWeb ? 'ex' : __('x—字体高度(ex)'),
default: '',
a11yLabel: __('x—字体高度(ex)'),
step: 0.01
},
cm: {
value: 'cm',
label: isWeb ? 'cm' : __('厘米(cm)'),
default: '',
a11yLabel: __('厘米(cm)'),
step: 0.001
},
mm: {
value: 'mm',
label: isWeb ? 'mm' : __('毫米(mm)'),
default: '',
a11yLabel: __('毫米(mm)'),
step: 0.1
},
in: {
value: 'in',
label: isWeb ? 'in' : __('英寸 (in)'),
default: '',
a11yLabel: __('英寸 (in)'),
step: 0.001
},
pc: {
value: 'pc',
label: isWeb ? 'pc' : __('黑桃 (PC)'),
default: '',
a11yLabel: __('黑桃 (PC)'),
step: 1
},
pt: {
value: 'pt',
label: isWeb ? 'pt' : __('小数点(pt)'),
default: '',
a11yLabel: __('小数点(pt)'),
step: 1
}
};
/**
* An array of all available CSS length units.
*/
export const ALL_CSS_UNITS = Object.values(allUnits);
/**
* Units of measurements. `a11yLabel` is used by screenreaders.
*/
export const CSS_UNITS = [allUnits.px, allUnits['%'], allUnits.em, allUnits.rem, allUnits.vw, allUnits.vh];
export const 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 value Value
* @param unit Unit value
* @param units Units to derive from.
* @return The extracted number and unit.
*/
export function getParsedValue(value, unit, units) {
const initialValue = unit ? `${value}${unit}` : value;
return parseUnit(initialValue, units);
}
/**
* Checks if units are defined.
*
* @param units Units to check.
* @return Whether units are defined.
*/
export function hasUnits(units) {
return Array.isArray(units) && !!units.length;
}
/**
* Parses a number and unit from a value.
*
* @param initialValue Value to parse
* @param units Units to derive from.
* @return The extracted number and unit.
*/
export function parseUnit(initialValue) {
let units = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ALL_CSS_UNITS;
const value = String(initialValue).trim();
let num = parseFloat(value);
num = isNaN(num) ? '' : num;
const unitMatch = value.match(/[\d.\-\+]*\s*(.*)/);
let unit = (unitMatch === null || unitMatch === void 0 ? void 0 : unitMatch[1]) !== undefined ? unitMatch[1] : '';
unit = unit.toLowerCase();
if (hasUnits(units) && units !== false) {
const match = units.find(item => item.value === unit);
unit = match === null || match === void 0 ? void 0 : match.value;
} else {
unit = DEFAULT_UNIT.value;
}
return [num, unit];
}
/**
* Parses a number and unit from a value. Validates parsed value, using fallback
* value if invalid.
*
* @param next The next value.
* @param units Units to derive from.
* @param fallbackValue The fallback value.
* @param fallbackUnit The fallback value.
* @return The extracted value and unit.
*/
export function getValidParsedUnit(next, units, fallbackValue, fallbackUnit) {
const [parsedValue, parsedUnit] = parseUnit(next, units);
let baseValue = parsedValue;
let baseUnit; // The parsed value from `parseUnit` should now be either a
// real number or an empty string. If not, use the fallback value.
if (!Number.isFinite(parsedValue) || parsedValue === '') {
baseValue = fallbackValue;
}
baseUnit = parsedUnit || fallbackUnit;
/**
* If no unit is found, attempt to use the first value from the collection
* of units as a default fallback.
*/
if (Array.isArray(units) && hasUnits(units) && !baseUnit) {
var _units$;
baseUnit = (_units$ = units[0]) === null || _units$ === void 0 ? void 0 : _units$.value;
}
return [baseValue, baseUnit];
}
/**
* 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
*/
export function parseA11yLabelForUnit(unit) {
const match = ALL_CSS_UNITS.find(item => item.value === unit);
return match !== null && match !== void 0 && match.a11yLabel ? match === null || match === void 0 ? void 0 : match.a11yLabel : match === null || match === void 0 ? void 0 : match.value;
}
/**
* Filters available units based on values defined by the unit setting/property.
*
* @param unitSetting Collection of preferred unit value strings.
* @param units Collection of available unit objects.
*
* @return Filtered units based on settings.
*/
export function filterUnitsWithSettings() {
let unitSetting = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
let units = arguments.length > 1 ? arguments[1] : undefined;
return Array.isArray(units) ? units.filter(unit => {
return unitSetting.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/GeChiUI/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 units based on settings.
*/
export const useCustomUnits = _ref => {
let {
units,
availableUnits,
defaultValues
} = _ref;
units = units || ALL_CSS_UNITS;
const usedUnits = filterUnitsWithSettings(!availableUnits ? [] : availableUnits, units);
if (defaultValues) {
usedUnits.forEach((unit, i) => {
if (defaultValues[unit.value]) {
usedUnits[i].default = defaultValues[unit.value];
}
});
}
return usedUnits.length === 0 ? false : usedUnits;
};
/**
* 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 currentValue Selected value to parse.
* @param legacyUnit Legacy unit value, if currentValue needs it appended.
* @param units List of available units.
*
* @return A collection of units containing the unit for the current value.
*/
export function getUnitsWithCurrentUnit(currentValue, legacyUnit) {
let units = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ALL_CSS_UNITS;
if (!Array.isArray(units)) {
return units;
}
const unitsWithCurrentUnit = [...units];
const [, currentUnit] = getParsedValue(currentValue, legacyUnit, ALL_CSS_UNITS);
if (currentUnit && !unitsWithCurrentUnit.some(unit => unit.value === currentUnit)) {
if (allUnits[currentUnit]) {
unitsWithCurrentUnit.unshift(allUnits[currentUnit]);
}
}
return unitsWithCurrentUnit;
}
//# sourceMappingURL=utils.js.map