UNPKG

@wordpress/block-editor

Version:
245 lines (244 loc) 8.35 kB
// packages/block-editor/src/components/preset-input-control/index.js import { Button, CustomSelectControl, Icon, RangeControl, __experimentalHStack as HStack, __experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue } from "@wordpress/components"; import { usePrevious } from "@wordpress/compose"; import { __, sprintf } from "@wordpress/i18n"; import { settings } from "@wordpress/icons"; import { useState, useEffect, useMemo } from "@wordpress/element"; import { CUSTOM_VALUE_SETTINGS, ICON_SIZE, RANGE_CONTROL_MAX_SIZE } from "./constants.mjs"; import { getCustomValueFromPreset, getPresetValueFromCustomValue, getSliderValueFromPreset, isValuePreset } from "./utils.mjs"; import CustomValueControls from "./custom-value-controls.mjs"; import { jsx, jsxs } from "react/jsx-runtime"; function PresetInputControl({ allowNegativeOnDrag = false, ariaLabel, className: classNameProp, customValueSettings = CUSTOM_VALUE_SETTINGS, disableCustomValues, icon, isMixed, value: valueProp, minimumCustomValue, onChange, onMouseOut, onMouseOver, onUnitChange, presets = [], presetType, selectedUnit, showTooltip, units }) { const value = useMemo( () => getPresetValueFromCustomValue(valueProp, presets, presetType), [valueProp, presets, presetType] ); const className = classNameProp ?? "preset-input-control"; const marks = presets.slice(1, presets.length - 1).map((_newValue, index) => ({ value: index + 1, label: void 0 })); const hasPresets = marks.length > 0; const showRangeControl = presets.length <= RANGE_CONTROL_MAX_SIZE; const allPlaceholder = isMixed ? __("Mixed") : null; const [minValue, setMinValue] = useState(minimumCustomValue); const [showCustomValueControl, setShowCustomValueControl] = useState( !disableCustomValues && value !== void 0 && !isValuePreset(value, presetType) ); let currentValue = null; const previousValue = usePrevious(value); useEffect(() => { if (!!value && previousValue !== value && !isValuePreset(value, presetType) && showCustomValueControl !== true) { setShowCustomValueControl(true); } }, [value, previousValue, presetType, showCustomValueControl]); const showCustomValueInSelectList = !showRangeControl && !showCustomValueControl && value !== void 0 && (!isValuePreset(value, presetType) || isValuePreset(value, presetType) && isMixed); let selectListOptions = presets; if (showCustomValueInSelectList) { selectListOptions = [ ...presets, { 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 = selectListOptions.length - 1; } else if (!isMixed) { currentValue = !showCustomValueControl ? getSliderValueFromPreset(value, presets, presetType) : getCustomValueFromPreset(value, presets, presetType); } const options = selectListOptions.map((size, index) => ({ key: index, name: size.name })); const resolvedPresetValue = isValuePreset(value, presetType) ? getCustomValueFromPreset(value, presets, presetType) : value; const [parsedQuantity, parsedUnit] = parseQuantityAndUnitFromRawValue(resolvedPresetValue); const computedUnit = parsedUnit || selectedUnit || "px"; const unitConfig = units?.find((item) => item.value === computedUnit); const step = unitConfig?.step ?? customValueSettings[computedUnit]?.steps ?? 0.1; const max = unitConfig?.max ?? customValueSettings[computedUnit]?.max ?? 10; const handleCustomValueChange = (newValue) => { const isNumeric = !isNaN(parseFloat(newValue)); const newCustomValue = isNumeric ? newValue : void 0; if (newCustomValue !== void 0) { onChange(newCustomValue); } }; const handleCustomValueSliderChange = (next) => { onChange([next, computedUnit].join("")); }; const customTooltipContent = (newValue) => value === void 0 ? void 0 : presets[newValue]?.name; const getNewPresetValue = (next, controlType) => { const newValue = parseInt(next, 10); if (controlType === "selectList") { if (newValue === 0 && presets[0]?.slug === "0") { return "0"; } if (newValue === 0) { return void 0; } } else if (newValue === 0) { return "0"; } return `var:preset|${presetType}|${presets[next]?.slug}`; }; return /* @__PURE__ */ jsxs( HStack, { className: `preset-input-control__wrapper ${className}__wrapper`, children: [ icon && /* @__PURE__ */ jsx( Icon, { className: "preset-input-control__icon", icon, size: ICON_SIZE } ), (!hasPresets || showCustomValueControl) && /* @__PURE__ */ jsx( CustomValueControls, { allowNegativeOnDrag, ariaLabel, allPlaceholder, minValue, parsedQuantity, computedUnit, units, isMixed, step, max, showTooltip, value, minimumCustomValue, onCustomValueChange: handleCustomValueChange, onCustomValueSliderChange: handleCustomValueSliderChange, onUnitChange, onMouseOut, onMouseOver, setMinValue } ), hasPresets && showRangeControl && !showCustomValueControl && /* @__PURE__ */ jsx( RangeControl, { "aria-valuenow": currentValue, "aria-valuetext": presets[currentValue]?.name, className: "preset-input-control__preset-range", hideLabelFromVision: true, initialPosition: 0, label: ariaLabel, max: presets.length - 1, marks, min: 0, onBlur: onMouseOut, onChange: (newValue) => onChange(getNewPresetValue(newValue)), onFocus: onMouseOver, onMouseDown: (event) => { const nearStart = event?.nativeEvent?.offsetX < 35; if (nearStart && value === void 0) { onChange("0"); } }, onMouseOut, onMouseOver, renderTooltipContent: customTooltipContent, step: 1, value: currentValue, withInputField: false, __next40pxDefaultSize: true } ), hasPresets && !showRangeControl && !showCustomValueControl && /* @__PURE__ */ jsx( CustomSelectControl, { className: "preset-input-control__custom-select-control", hideLabelFromVision: true, label: ariaLabel, onBlur: onMouseOut, onChange: (selection) => { if (showCustomValueInSelectList && selection.selectedItem.key === options.length - 1) { setShowCustomValueControl(true); } else { onChange( getNewPresetValue( selection.selectedItem.key, "selectList" ) ); } }, onFocus: onMouseOver, onMouseOut, onMouseOver, options, size: "__unstable-large", value: ( // passing empty string as a fallback to continue using the // component in controlled mode options.find( (option) => option.key === currentValue ) || "" ) } ), hasPresets && !disableCustomValues && /* @__PURE__ */ jsx( Button, { className: "preset-input-control__custom-toggle", icon: settings, iconSize: ICON_SIZE, isPressed: showCustomValueControl, label: showCustomValueControl ? __("Use preset") : __("Set custom value"), onClick: () => { setShowCustomValueControl(!showCustomValueControl); }, size: "small" } ) ] } ); } export { PresetInputControl as default }; //# sourceMappingURL=index.mjs.map