97 lines
3.8 KiB
JavaScript
97 lines
3.8 KiB
JavaScript
import { __ } from '@wordpress/i18n';
|
|
import { BaseControl, __experimentalNumberControl as NumberControl, SelectControl, __experimentalHStack as HStack } from '@wordpress/components';
|
|
import { useState, useEffect } from 'react';
|
|
|
|
/**
|
|
* Control component with a number input and a select dropdown for units (px, rem, em, % etc.).
|
|
* Accepts a default value as a string (e.g., "15px", "10rem", etc.).
|
|
* Includes an optional 'auto' unit if includeAuto is true, and handles autoReturnsNull behavior.
|
|
*/
|
|
export function DimensionValueControl({ value = '10px', onChange, includeAuto = false, autoReturnsNull = false }) {
|
|
// Options for select control (CSS units) including 'auto' if enabled
|
|
const unitOptions = [
|
|
{ label: __('px'), value: 'px' },
|
|
{ label: __('%'), value: '%' },
|
|
{ label: __('em'), value: 'em' },
|
|
{ label: __('rem'), value: 'rem' },
|
|
{ label: __('vw'), value: 'vw' },
|
|
{ label: __('vh'), value: 'vh' },
|
|
...(includeAuto ? [{ label: __('auto'), value: 'auto' }] : []), // Add 'auto' option if includeAuto is true
|
|
];
|
|
|
|
// Parse the value string into a number and unit
|
|
const parseValue = (value) => {
|
|
const regex = /([0-9]+)([a-zA-Z%]+)?/; // Capture the number and the unit
|
|
const match = value.match(regex);
|
|
if (match) {
|
|
return {
|
|
numberValue: parseInt(match[1], 10), // Number part
|
|
unitValue: match[2] || 'px' // Unit part (default to 'px' if no unit found)
|
|
};
|
|
}
|
|
return { numberValue: 0, unitValue: 'px' }; // Fallback if invalid format
|
|
};
|
|
|
|
// Use the parsed value to set initial state
|
|
const { numberValue: initialNumber, unitValue: initialUnit } = parseValue(value);
|
|
const [numberValue, setNumberValue] = useState(initialNumber);
|
|
const [unitValue, setUnitValue] = useState(initialUnit);
|
|
|
|
// Combine the number and unit into a string like "15px"
|
|
const dimensionValue = `${numberValue}${unitValue}`;
|
|
|
|
// Handle number change
|
|
const onNumberChange = (newValue) => {
|
|
setNumberValue(newValue);
|
|
if (onChange && unitValue !== 'auto') {
|
|
onChange(`${newValue}${unitValue}`); // Pass updated value back to parent
|
|
}
|
|
};
|
|
|
|
// Handle unit change
|
|
const onUnitChange = (newUnit) => {
|
|
if (newUnit === 'auto') {
|
|
setNumberValue(null); // Reset the number value when 'auto' is selected
|
|
}
|
|
setUnitValue(newUnit);
|
|
if (onChange) {
|
|
const updatedValue = newUnit === 'auto'
|
|
? (autoReturnsNull ? null : 'auto')
|
|
: `${numberValue}${newUnit}`; // Pass 'auto' or null or updated value back to parent
|
|
onChange(updatedValue);
|
|
}
|
|
};
|
|
|
|
// Effect to handle when value prop changes (useful for syncing)
|
|
useEffect(() => {
|
|
const { numberValue, unitValue } = parseValue(value);
|
|
setNumberValue(numberValue);
|
|
setUnitValue(unitValue);
|
|
}, [value]);
|
|
|
|
return (
|
|
<BaseControl className="lcp-dimension-value-control">
|
|
<HStack>
|
|
{/* Number input control, disabled when 'auto' is selected */}
|
|
<NumberControl
|
|
className="lcp-number-control"
|
|
value={numberValue || ''}
|
|
onChange={onNumberChange}
|
|
min={0}
|
|
step={0.1}
|
|
spinControls={'none'}
|
|
disabled={unitValue === 'auto'} // Disable number input if 'auto' is selected
|
|
/>
|
|
|
|
{/* Select dropdown control for units */}
|
|
<SelectControl
|
|
className="lcp-select-control"
|
|
value={unitValue}
|
|
options={unitOptions}
|
|
onChange={onUnitChange}
|
|
/>
|
|
</HStack>
|
|
</BaseControl>
|
|
);
|
|
}
|