| 1 |
import { __ } from '@wordpress/i18n'; |
| 2 |
import { |
| 3 |
RangeControl, |
| 4 |
SelectControl, |
| 5 |
} from '@wordpress/components'; |
| 6 |
|
| 7 |
const RangeControlWithUnit = ({ |
| 8 |
attributes, |
| 9 |
setAttributes, |
| 10 |
attributeKey, |
| 11 |
label = __('Size', 'boldpost'), |
| 12 |
units = ['px', '%', 'em', 'rem', 'vw', 'vh'], |
| 13 |
min, |
| 14 |
max, |
| 15 |
step, |
| 16 |
}) => { |
| 17 |
|
| 18 |
const currentValue = attributes[attributeKey]; |
| 19 |
|
| 20 |
// Parse the value |
| 21 |
const parseValue = (val) => { |
| 22 |
if (val === undefined || val === null || val === '') return { value: '', unit: 'px' }; |
| 23 |
const match = String(val).match(/^([\d.-]+)([a-z%]*)$/); |
| 24 |
return { |
| 25 |
value: match ? parseFloat(match[1]) : 0, |
| 26 |
unit: (match && match[2]) ? match[2] : 'px' |
| 27 |
}; |
| 28 |
}; |
| 29 |
|
| 30 |
const { value, unit } = parseValue(currentValue); |
| 31 |
|
| 32 |
const onChangeValue = (newValue) => { |
| 33 |
// If the value is cleared (undefined), don't set a unit-only string |
| 34 |
if (newValue === undefined) { |
| 35 |
setAttributes({ [attributeKey]: '' }); |
| 36 |
return; |
| 37 |
} |
| 38 |
setAttributes({ [attributeKey]: `${newValue}${unit}` }); |
| 39 |
}; |
| 40 |
|
| 41 |
const onChangeUnit = (newUnit) => { |
| 42 |
setAttributes({ [attributeKey]: `${value || 0}${newUnit}` }); |
| 43 |
}; |
| 44 |
|
| 45 |
// Determine min/max/step based on unit if not provided |
| 46 |
const getSettings = (currentUnit) => { |
| 47 |
if (currentUnit === 'px') return { min: min !== undefined ? min : 0, max: max !== undefined ? max : 100, step: step || 1 }; |
| 48 |
if (currentUnit === '%') return { min: min !== undefined ? min : 0, max: max !== undefined ? max : 100, step: step || 1 }; |
| 49 |
if (['em', 'rem', 'vw', 'vh'].includes(currentUnit)) return { min: min !== undefined ? min : 0, max: max !== undefined ? max : 10, step: step || 0.1 }; |
| 50 |
return { min: 0, max: 100, step: 1 }; |
| 51 |
}; |
| 52 |
|
| 53 |
const currentSettings = getSettings(unit); |
| 54 |
|
| 55 |
return ( |
| 56 |
<div className="boldpost-range-control-with-unit" style={{ marginBottom: '24px' }}> |
| 57 |
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '10px' }}> |
| 58 |
<span className="components-base-control__label" style={{ marginBottom: 0, marginRight: '10px' }}>{label}</span> |
| 59 |
<div style={{ width: '80px' }}> |
| 60 |
<SelectControl |
| 61 |
value={unit} |
| 62 |
options={units.map((u) => ({ label: u, value: u }))} |
| 63 |
onChange={onChangeUnit} |
| 64 |
__nextHasNoMarginBottom={true} |
| 65 |
__next40pxDefaultSize |
| 66 |
size="__unstable-small" |
| 67 |
/> |
| 68 |
</div> |
| 69 |
</div> |
| 70 |
<RangeControl |
| 71 |
value={value} |
| 72 |
onChange={onChangeValue} |
| 73 |
min={currentSettings.min} |
| 74 |
max={currentSettings.max} |
| 75 |
step={currentSettings.step} |
| 76 |
withInputField={true} |
| 77 |
allowReset={true} |
| 78 |
__nextHasNoMarginBottom={true} |
| 79 |
/> |
| 80 |
</div> |
| 81 |
); |
| 82 |
}; |
| 83 |
|
| 84 |
export default RangeControlWithUnit; |