@wordpress/block-editor
Version:
299 lines (298 loc) • 9.72 kB
JavaScript
// packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js
import {
Button,
Icon,
RangeControl,
__experimentalHStack as HStack,
__experimentalUnitControl as UnitControl,
__experimentalUseCustomUnits as useCustomUnits,
__experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue,
CustomSelectControl
} from "@wordpress/components";
import { useSelect } from "@wordpress/data";
import { useState, useMemo } from "@wordpress/element";
import { usePrevious } from "@wordpress/compose";
import { __, _x, sprintf } from "@wordpress/i18n";
import { settings } from "@wordpress/icons";
import { useSettings } from "../../use-settings";
import { store as blockEditorStore } from "../../../store";
import {
RANGE_CONTROL_MAX_SIZE,
ALL_SIDES,
LABELS,
getSliderValueFromPreset,
getCustomValueFromPreset,
getPresetValueFromCustomValue,
isValueSpacingPreset
} from "../utils";
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
var 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 },
svw: { max: 100, steps: 1 },
lvw: { max: 100, steps: 1 },
dvw: { max: 100, steps: 1 },
svh: { max: 100, steps: 1 },
lvh: { max: 100, steps: 1 },
dvh: { max: 100, steps: 1 },
vi: { max: 100, steps: 1 },
svi: { max: 100, steps: 1 },
lvi: { max: 100, steps: 1 },
dvi: { max: 100, steps: 1 },
vb: { max: 100, steps: 1 },
svb: { max: 100, steps: 1 },
lvb: { max: 100, steps: 1 },
dvb: { max: 100, steps: 1 },
vmin: { max: 100, steps: 1 },
svmin: { max: 100, steps: 1 },
lvmin: { max: 100, steps: 1 },
dvmin: { max: 100, steps: 1 },
vmax: { max: 100, steps: 1 },
svmax: { max: 100, steps: 1 },
lvmax: { max: 100, steps: 1 },
dvmax: { max: 100, steps: 1 }
};
function SpacingInputControl({
icon,
isMixed = false,
minimumCustomValue,
onChange,
onMouseOut,
onMouseOver,
showSideInLabel = true,
side,
spacingSizes,
type,
value
}) {
value = getPresetValueFromCustomValue(value, spacingSizes);
let selectListSizes = spacingSizes;
const showRangeControl = spacingSizes.length <= RANGE_CONTROL_MAX_SIZE;
const disableCustomSpacingSizes = useSelect((select) => {
const editorSettings = select(blockEditorStore).getSettings();
return editorSettings?.disableCustomSpacingSizes;
});
const [showCustomValueControl, setShowCustomValueControl] = useState(
!disableCustomSpacingSizes && value !== void 0 && !isValueSpacingPreset(value)
);
const [minValue, setMinValue] = useState(minimumCustomValue);
const previousValue = usePrevious(value);
if (!!value && previousValue !== value && !isValueSpacingPreset(value) && showCustomValueControl !== true) {
setShowCustomValueControl(true);
}
const [availableUnits] = useSettings("spacing.units");
const units = useCustomUnits({
availableUnits: availableUnits || ["px", "em", "rem"]
});
let currentValue = null;
const showCustomValueInSelectList = !showRangeControl && !showCustomValueControl && value !== void 0 && (!isValueSpacingPreset(value) || isValueSpacingPreset(value) && isMixed);
if (showCustomValueInSelectList) {
selectListSizes = [
...spacingSizes,
{
name: !isMixed ? (
// translators: %s: A custom measurement, e.g. 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 === void 0) {
onChange("0");
}
};
const customTooltipContent = (newValue) => value === void 0 ? void 0 : spacingSizes[newValue]?.name;
const customRangeValue = parseFloat(currentValue, 10);
const getNewCustomValue = (newSize) => {
const isNumeric = !isNaN(parseFloat(newSize));
const nextValue = isNumeric ? newSize : void 0;
return nextValue;
};
const getNewPresetValue = (newSize, controlType) => {
const size = parseInt(newSize, 10);
if (controlType === "selectList") {
if (size === 0) {
return void 0;
}
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.slice(1, spacingSizes.length - 1).map((_newValue, index) => ({
value: index + 1,
label: void 0
}));
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 etc.). 2. Type of spacing being modified (padding, margin, etc).
_x("%1$s %2$s", "spacing"),
sideLabel,
typeLabel
).trim();
return /* @__PURE__ */ jsxs(HStack, { className: "spacing-sizes-control__wrapper", children: [
icon && /* @__PURE__ */ jsx(
Icon,
{
className: "spacing-sizes-control__icon",
icon,
size: 24
}
),
showCustomValueControl && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
UnitControl,
{
onMouseOver,
onMouseOut,
onFocus: onMouseOver,
onBlur: onMouseOut,
onChange: (newSize) => onChange(getNewCustomValue(newSize)),
value: currentValue,
units,
min: minValue,
placeholder: allPlaceholder,
disableUnits: isMixed,
label: ariaLabel,
hideLabelFromVision: true,
className: "spacing-sizes-control__custom-value-input",
size: "__unstable-large",
onDragStart: () => {
if (value?.charAt(0) === "-") {
setMinValue(0);
}
},
onDrag: () => {
if (value?.charAt(0) === "-") {
setMinValue(0);
}
},
onDragEnd: () => {
setMinValue(minimumCustomValue);
}
}
),
/* @__PURE__ */ jsx(
RangeControl,
{
__next40pxDefaultSize: true,
onMouseOver,
onMouseOut,
onFocus: onMouseOver,
onBlur: onMouseOut,
value: customRangeValue,
min: 0,
max: CUSTOM_VALUE_SETTINGS[selectedUnit]?.max ?? 10,
step: CUSTOM_VALUE_SETTINGS[selectedUnit]?.steps ?? 0.1,
withInputField: false,
onChange: handleCustomValueSliderChange,
className: "spacing-sizes-control__custom-value-range",
__nextHasNoMarginBottom: true,
label: ariaLabel,
hideLabelFromVision: true
}
)
] }),
showRangeControl && !showCustomValueControl && /* @__PURE__ */ jsx(
RangeControl,
{
__next40pxDefaultSize: true,
onMouseOver,
onMouseOut,
className: "spacing-sizes-control__range-control",
value: currentValue,
onChange: (newSize) => onChange(getNewPresetValue(newSize)),
onMouseDown: (event) => {
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,
label: ariaLabel,
hideLabelFromVision: true,
__nextHasNoMarginBottom: true,
onFocus: onMouseOver,
onBlur: onMouseOut
}
),
!showRangeControl && !showCustomValueControl && /* @__PURE__ */ jsx(
CustomSelectControl,
{
className: "spacing-sizes-control__custom-select-control",
value: (
// passing empty string as a fallback to continue using the
// component in controlled mode
options.find(
(option) => option.key === currentValue
) || ""
),
onChange: (selection) => {
onChange(
getNewPresetValue(
selection.selectedItem.key,
"selectList"
)
);
},
options,
label: ariaLabel,
hideLabelFromVision: true,
size: "__unstable-large",
onMouseOver,
onMouseOut,
onFocus: onMouseOver,
onBlur: onMouseOut
}
),
!disableCustomSpacingSizes && /* @__PURE__ */ jsx(
Button,
{
label: showCustomValueControl ? __("Use size preset") : __("Set custom size"),
icon: settings,
onClick: () => {
setShowCustomValueControl(!showCustomValueControl);
},
isPressed: showCustomValueControl,
size: "small",
className: "spacing-sizes-control__custom-toggle",
iconSize: 24
}
)
] });
}
export {
SpacingInputControl as default
};
//# sourceMappingURL=spacing-input-control.js.map