import { memo, useState, useEffect, type ChangeEvent, type KeyboardEvent, type ClipboardEvent } from 'react'; import FieldWrapper from './FieldWrapper'; import TextInput from './TextInput'; import Icon from '../../utils/Icon'; import { __ } from '@wordpress/i18n'; interface NumberInputWithControlsProps { field: { id: string; label?: string; default?: number; min?: number; max?: number; is_lock?: boolean; tooltip?: any; [key: string]: any; }; value: number; onChange: (value: number) => void; } const NumberInputWithControls = ({ field, value, onChange }: NumberInputWithControlsProps) => { const min = field.min ?? 0; const max = field.max ?? Infinity; const disabled = field.is_lock === true; const [internalValue, setInternalValue] = useState(value); useEffect(() => { setInternalValue(value); }, [value]); const handleInputChange = (e: ChangeEvent) => { const sanitizedValue = e.target.value.replace(/[^0-9]/g, ''); const newValue = sanitizedValue === '' ? min : parseInt(sanitizedValue, 10); const clampedValue = Math.max(min, Math.min(max, newValue)); setInternalValue(clampedValue); onChange(clampedValue); }; const handleKeyDown = (e: KeyboardEvent) => { if ( ['Backspace', 'Delete', 'Tab', 'Escape', 'Enter', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(e.key) || ((e.ctrlKey || e.metaKey) && ['a', 'c', 'v', 'x'].includes(e.key.toLowerCase())) ) { return; } if (!/^\d$/.test(e.key)) { e.preventDefault(); } }; const handlePaste = (e: ClipboardEvent) => { e.preventDefault(); if (disabled) return; const pasteData = e.clipboardData.getData('text'); const sanitizedPasteData = pasteData.replace(/[^0-9]/g, ''); const currentTarget = e.target as HTMLInputElement; const start = currentTarget.selectionStart ?? 0; const end = currentTarget.selectionEnd ?? 0; const currentValue = currentTarget.value; const newValueString = currentValue.substring(0, start) + sanitizedPasteData + currentValue.substring(end); const finalSanitizedValue = newValueString.replace(/[^0-9]/g, ''); const newValue = finalSanitizedValue === '' ? min : parseInt(finalSanitizedValue, 10); const clampedValue = Math.max(min, Math.min(max, newValue)); setInternalValue(clampedValue); onChange(clampedValue); setTimeout(() => { const newCursorPosition = start + sanitizedPasteData.length; currentTarget.value = String(clampedValue); currentTarget.setSelectionRange(newCursorPosition, newCursorPosition); }, 0); }; const handleIncrement = () => { if (!disabled && internalValue < max) { const newValue = internalValue + 1; setInternalValue(newValue); onChange(newValue); } }; const handleDecrement = () => { if (!disabled && internalValue > min) { const newValue = internalValue - 1; setInternalValue(newValue); onChange(newValue); } }; return ( {field.label} {field.tooltip && ( )} } >
); }; export default memo(NumberInputWithControls);