@wordpress/block-editor
Version:
233 lines (216 loc) • 8.16 kB
JavaScript
import { createElement, Fragment } from "@wordpress/element";
/**
* WordPress dependencies
*/
import { Button, CustomSelectControl, Icon, RangeControl, __experimentalHStack as HStack, __experimentalUnitControl as UnitControl, __experimentalUseCustomUnits as useCustomUnits, __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useState, useMemo } from '@wordpress/element';
import { usePrevious } from '@wordpress/compose';
import { __, sprintf } from '@wordpress/i18n';
import { settings } from '@wordpress/icons';
/**
* Internal dependencies
*/
import useSetting from '../../use-setting';
import { store as blockEditorStore } from '../../../store';
import { ALL_SIDES, LABELS, getSliderValueFromPreset, getCustomValueFromPreset, getPresetValueFromCustomValue, isValueSpacingPreset } from '../utils';
const CUSTOM_VALUE_SETTINGS = {
px: {
max: 300,
steps: 1
},
'%': {
max: 100,
steps: 1
},
vw: {
max: 100,
steps: 1
},
vh: {
max: 100,
steps: 1
},
em: {
max: 10,
steps: 0.1
},
rm: {
max: 10,
steps: 0.1
}
};
export default function SpacingInputControl({
icon,
isMixed = false,
minimumCustomValue,
onChange,
onMouseOut,
onMouseOver,
showSideInLabel = true,
side,
spacingSizes,
type,
value
}) {
var _CUSTOM_VALUE_SETTING, _CUSTOM_VALUE_SETTING2;
// Treat value as a preset value if the passed in value matches the value of one of the spacingSizes.
value = getPresetValueFromCustomValue(value, spacingSizes);
let selectListSizes = spacingSizes;
const showRangeControl = spacingSizes.length <= 8;
const disableCustomSpacingSizes = useSelect(select => {
const editorSettings = select(blockEditorStore).getSettings();
return editorSettings?.disableCustomSpacingSizes;
});
const [showCustomValueControl, setShowCustomValueControl] = useState(!disableCustomSpacingSizes && value !== undefined && !isValueSpacingPreset(value));
const previousValue = usePrevious(value);
if (!!value && previousValue !== value && !isValueSpacingPreset(value) && showCustomValueControl !== true) {
setShowCustomValueControl(true);
}
const units = useCustomUnits({
availableUnits: useSetting('spacing.units') || ['px', 'em', 'rem']
});
let currentValue = null;
const showCustomValueInSelectList = !showRangeControl && !showCustomValueControl && value !== undefined && (!isValueSpacingPreset(value) || isValueSpacingPreset(value) && isMixed);
if (showCustomValueInSelectList) {
selectListSizes = [...spacingSizes, {
name: !isMixed ? // translators: A custom measurement, eg. a number followed by a unit like 12px.
sprintf(__('Custom (%s)'), value) : __('Mixed'),
slug: 'custom',
size: value
}];
currentValue = selectListSizes.length - 1;
} else if (!isMixed) {
currentValue = !showCustomValueControl ? getSliderValueFromPreset(value, spacingSizes) : getCustomValueFromPreset(value, spacingSizes);
}
const selectedUnit = useMemo(() => parseQuantityAndUnitFromRawValue(currentValue), [currentValue])[1] || units[0].value;
const setInitialValue = () => {
if (value === undefined) {
onChange('0');
}
};
const customTooltipContent = newValue => value === undefined ? undefined : spacingSizes[newValue]?.name;
const customRangeValue = parseFloat(currentValue, 10);
const getNewCustomValue = newSize => {
const isNumeric = !isNaN(parseFloat(newSize));
const nextValue = isNumeric ? newSize : undefined;
return nextValue;
};
const getNewPresetValue = (newSize, controlType) => {
const size = parseInt(newSize, 10);
if (controlType === 'selectList') {
if (size === 0) {
return undefined;
}
if (size === 1) {
return '0';
}
} else if (size === 0) {
return '0';
}
return `var:preset|spacing|${spacingSizes[newSize]?.slug}`;
};
const handleCustomValueSliderChange = next => {
onChange([next, selectedUnit].join(''));
};
const allPlaceholder = isMixed ? __('Mixed') : null;
const options = selectListSizes.map((size, index) => ({
key: index,
name: size.name
}));
const marks = spacingSizes.map((_newValue, index) => ({
value: index,
label: undefined
}));
const sideLabel = ALL_SIDES.includes(side) && showSideInLabel ? LABELS[side] : '';
const typeLabel = showSideInLabel ? type?.toLowerCase() : type;
const ariaLabel = sprintf( // translators: 1: The side of the block being modified (top, bottom, left, All sides etc.). 2. Type of spacing being modified (Padding, margin, etc)
__('%1$s %2$s'), sideLabel, typeLabel).trim();
return createElement(HStack, {
className: "spacing-sizes-control__wrapper"
}, icon && createElement(Icon, {
className: "spacing-sizes-control__icon",
icon: icon,
size: 24
}), showCustomValueControl && createElement(Fragment, null, createElement(UnitControl, {
onMouseOver: onMouseOver,
onMouseOut: onMouseOut,
onFocus: onMouseOver,
onBlur: onMouseOut,
onChange: newSize => onChange(getNewCustomValue(newSize)),
value: currentValue,
units: units,
min: minimumCustomValue,
placeholder: allPlaceholder,
disableUnits: isMixed,
label: ariaLabel,
hideLabelFromVision: true,
className: "spacing-sizes-control__custom-value-input",
size: '__unstable-large'
}), createElement(RangeControl, {
onMouseOver: onMouseOver,
onMouseOut: onMouseOut,
onFocus: onMouseOver,
onBlur: onMouseOut,
value: customRangeValue,
min: 0,
max: (_CUSTOM_VALUE_SETTING = CUSTOM_VALUE_SETTINGS[selectedUnit]?.max) !== null && _CUSTOM_VALUE_SETTING !== void 0 ? _CUSTOM_VALUE_SETTING : 10,
step: (_CUSTOM_VALUE_SETTING2 = CUSTOM_VALUE_SETTINGS[selectedUnit]?.steps) !== null && _CUSTOM_VALUE_SETTING2 !== void 0 ? _CUSTOM_VALUE_SETTING2 : 0.1,
withInputField: false,
onChange: handleCustomValueSliderChange,
className: "spacing-sizes-control__custom-value-range",
__nextHasNoMarginBottom: true
})), showRangeControl && !showCustomValueControl && createElement(RangeControl, {
onMouseOver: onMouseOver,
onMouseOut: onMouseOut,
className: "spacing-sizes-control__range-control",
value: currentValue,
onChange: newSize => onChange(getNewPresetValue(newSize)),
onMouseDown: event => {
// If mouse down is near start of range set initial value to 0, which
// prevents the user have to drag right then left to get 0 setting.
if (event?.nativeEvent?.offsetX < 35) {
setInitialValue();
}
},
withInputField: false,
"aria-valuenow": currentValue,
"aria-valuetext": spacingSizes[currentValue]?.name,
renderTooltipContent: customTooltipContent,
min: 0,
max: spacingSizes.length - 1,
marks: marks,
label: ariaLabel,
hideLabelFromVision: true,
__nextHasNoMarginBottom: true,
onFocus: onMouseOver,
onBlur: onMouseOut
}), !showRangeControl && !showCustomValueControl && createElement(CustomSelectControl, {
className: "spacing-sizes-control__custom-select-control",
value: options.find(option => option.key === currentValue) || '' // passing undefined here causes a downshift controlled/uncontrolled warning
,
onChange: selection => {
onChange(getNewPresetValue(selection.selectedItem.key, 'selectList'));
},
options: options,
label: ariaLabel,
hideLabelFromVision: true,
__nextUnconstrainedWidth: true,
size: '__unstable-large',
onMouseOver: onMouseOver,
onMouseOut: onMouseOut,
onFocus: onMouseOver,
onBlur: onMouseOut
}), !disableCustomSpacingSizes && createElement(Button, {
label: showCustomValueControl ? __('Use size preset') : __('Set custom size'),
icon: settings,
onClick: () => {
setShowCustomValueControl(!showCustomValueControl);
},
isPressed: showCustomValueControl,
isSmall: true,
className: "spacing-sizes-control__custom-toggle",
iconSize: 24
}));
}
//# sourceMappingURL=spacing-input-control.js.map