import { useEffect, useRef, useState } from '@wordpress/element'; type BoxSide = 'top' | 'right' | 'bottom' | 'left'; type FourDirectionInputGroupProps = { idPrefix: string; values: Record; max: number; onChange: ( values: Record ) => void; }; const CONTROLS: Array<{ key: BoxSide; icon: string }> = [ { key: 'top', icon: '↑' }, { key: 'right', icon: '→' }, { key: 'bottom', icon: '↓' }, { key: 'left', icon: '←' }, ]; const clampValue = ( value: number, max: number ): number => Math.max( 0, Math.min( max, Number.isFinite( value ) ? value : 0 ) ); const FourDirectionInputGroup = ( { idPrefix, values, max, onChange, }: FourDirectionInputGroupProps ) => { const [ activeSide, setActiveSide ] = useState( null ); const rootRef = useRef( null ); useEffect( () => { const handlePointerDown = ( event: MouseEvent ) => { if ( ! rootRef.current?.contains( event.target as Node ) ) { setActiveSide( null ); } }; const handleEscape = ( event: KeyboardEvent ) => { if ( 'Escape' === event.key ) { setActiveSide( null ); } }; document.addEventListener( 'mousedown', handlePointerDown ); document.addEventListener( 'keydown', handleEscape ); return () => { document.removeEventListener( 'mousedown', handlePointerDown ); document.removeEventListener( 'keydown', handleEscape ); }; }, [] ); return (
{ CONTROLS.map( ( control ) => { const id = `${ idPrefix }-${ control.key }`; const dropdownId = `${ id }-slider`; const currentValue = clampValue( values[ control.key ], max ); const isActive = activeSide === control.key; return (
setActiveSide( control.key ) } onClick={ () => setActiveSide( control.key ) } onChange={ ( event ) => onChange( { ...values, [ control.key ]: clampValue( Number( event.target.value ), max ), } ) } /> { isActive ? (
{ `${ control.icon } 0-${ max }` } { currentValue }
onChange( { ...values, [ control.key ]: clampValue( Number( event.target.value ), max ), } ) } />
0 { max }
) : null }
); } ) }
); }; export default FourDirectionInputGroup;