157 lines
4.5 KiB
JavaScript
157 lines
4.5 KiB
JavaScript
import { useState } from '@wordpress/element';
|
|
|
|
import {
|
|
BaseControl,
|
|
Button,
|
|
RangeControl,
|
|
__experimentalHStack as HStack,
|
|
__experimentalVStack as VStack,
|
|
__experimentalUnitControl as UnitControl,
|
|
Icon
|
|
} from '@wordpress/components';
|
|
import { __ } from '@wordpress/i18n';
|
|
import { sidesHorizontal, sidesVertical, sidesTop, sidesBottom, sidesLeft, sidesRight, settings } from '@wordpress/icons';
|
|
|
|
export default function SpacingControl({ label, value = {}, onChange, themeSpacing = {} }) {
|
|
const [verticalAdvanced, setVerticalAdvanced] = useState(false);
|
|
const [horizontalAdvanced, setHorizontalAdvanced] = useState(false);
|
|
const [advancedMode, setAdvancedMode] = useState(false); // full advanced toggle
|
|
|
|
const parseValue = (val) => (val ? parseInt(val) : 0);
|
|
|
|
const handleChange = (sides, val) => {
|
|
const unit = val.toString().replace(/[0-9]/g, '') || 'px';
|
|
const newValue = { ...value };
|
|
sides.forEach((side) => {
|
|
newValue[side] = `${parseInt(val)}${unit}`;
|
|
});
|
|
onChange(newValue);
|
|
};
|
|
|
|
// --- Generate marks for RangeControl from theme.json spacing ---
|
|
const spacingMarks = themeSpacing?.spacingSizes?.map((s) => ({
|
|
value: parseInt(s.size), // you may need to strip "px" or clamp()
|
|
label: s.name,
|
|
})) || [];
|
|
|
|
// --- Advanced 4-row mode ---
|
|
if (advancedMode) {
|
|
const sides = [
|
|
{ key: 'top', sideIcon: sidesTop },
|
|
{ key: 'bottom', sideIcon: sidesBottom },
|
|
{ key: 'left', sideIcon: sidesLeft },
|
|
{ key: 'right', sideIcon: sidesRight },
|
|
];
|
|
|
|
return (
|
|
<BaseControl label={label}>
|
|
<VStack gap={16}>
|
|
<Button variant="secondary" onClick={() => setAdvancedMode(false)}>
|
|
{__('Back to Simple Mode', 'directory-listings')}
|
|
</Button>
|
|
|
|
{sides.map(({ key, sideIcon }) => (
|
|
<VStack key={key} gap={4}>
|
|
<HStack align="center" gap={8}>
|
|
<Icon icon={sideIcon} />
|
|
<div style={{ flex: 1 }}>
|
|
<RangeControl
|
|
value={parseValue(value[key] || 0)}
|
|
onChange={(val) => handleChange([key], val)}
|
|
min={0}
|
|
max={Math.max(...spacingMarks.map((m) => m.value))}
|
|
step={1}
|
|
marks={spacingMarks}
|
|
withInputField={false}
|
|
/>
|
|
</div>
|
|
<UnitControl
|
|
value={value[key] || '0px'}
|
|
onChange={(val) => handleChange([key], val)}
|
|
min={0}
|
|
max={Math.max(...spacingMarks.map((m) => m.value))}
|
|
/>
|
|
</HStack>
|
|
</VStack>
|
|
))}
|
|
</VStack>
|
|
</BaseControl>
|
|
);
|
|
}
|
|
|
|
// --- Simple vertical + horizontal mode ---
|
|
return (
|
|
<BaseControl label={label}>
|
|
<VStack gap={16}>
|
|
<Button variant="secondary" onClick={() => setAdvancedMode(true)}>
|
|
{__('Advanced Mode', 'directory-listings')}
|
|
</Button>
|
|
|
|
{/* Vertical */}
|
|
<VStack gap={4}>
|
|
<HStack align="center" gap={8}>
|
|
<Icon icon={sidesVertical} />
|
|
{verticalAdvanced && (
|
|
<UnitControl
|
|
value={value.top || '0px'}
|
|
onChange={(val) => handleChange(['top', 'bottom'], val)}
|
|
min={0}
|
|
max={Math.max(...spacingMarks.map((m) => m.value))}
|
|
/>
|
|
)}
|
|
<div style={{ flex: 1 }}>
|
|
<RangeControl
|
|
value={parseValue(value.top || 0)}
|
|
onChange={(val) => handleChange(['top', 'bottom'], val)}
|
|
min={0}
|
|
max={Math.max(...spacingMarks.map((m) => m.value))}
|
|
step={1}
|
|
marks={spacingMarks}
|
|
withInputField={false}
|
|
/>
|
|
</div>
|
|
<Button
|
|
icon={settings}
|
|
isSecondary
|
|
onClick={() => setVerticalAdvanced(!verticalAdvanced)}
|
|
aria-label={__('Toggle vertical spacing input', 'directory-listings')}
|
|
/>
|
|
</HStack>
|
|
</VStack>
|
|
|
|
{/* Horizontal */}
|
|
<VStack gap={4}>
|
|
<HStack align="center" gap={8}>
|
|
<Icon icon={sidesHorizontal} />
|
|
{horizontalAdvanced && (
|
|
<UnitControl
|
|
value={value.left || '0px'}
|
|
onChange={(val) => handleChange(['left', 'right'], val)}
|
|
min={0}
|
|
max={Math.max(...spacingMarks.map((m) => m.value))}
|
|
/>
|
|
)}
|
|
<div style={{ flex: 1 }}>
|
|
<RangeControl
|
|
value={parseValue(value.left || 0)}
|
|
onChange={(val) => handleChange(['left', 'right'], val)}
|
|
min={0}
|
|
max={Math.max(...spacingMarks.map((m) => m.value))}
|
|
step={1}
|
|
marks={spacingMarks}
|
|
withInputField={false}
|
|
/>
|
|
</div>
|
|
<Button
|
|
icon={settings}
|
|
isSecondary
|
|
onClick={() => setHorizontalAdvanced(!horizontalAdvanced)}
|
|
aria-label={__('Toggle horizontal spacing input', 'directory-listings')}
|
|
/>
|
|
</HStack>
|
|
</VStack>
|
|
</VStack>
|
|
</BaseControl>
|
|
);
|
|
}
|