/** * WordPress dependencies */ import { Flex, BaseControl, __experimentalNumberControl as NumberControl, privateApis, } from '@wordpress/components'; import { useCallback } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import { OPERATOR_BETWEEN } from '../../../constants'; import type { DataFormControlProps, FormatNumber } from '../../../types'; import { unlock } from '../../../lock-unlock'; import getCustomValidity from './get-custom-validity'; const { ValidatedNumberControl } = unlock( privateApis ); type NumberBetween = [ number | string, number | string ]; function toNumberOrEmpty( value?: string ) { if ( value === '' || value === undefined ) { return ''; } const number = Number( value ); return Number.isFinite( number ) ? number : ''; } function BetweenControls( { value, onChange, hideLabelFromVision, step, }: { value: NumberBetween; onChange: ( [ min, max ]: NumberBetween ) => void; hideLabelFromVision?: boolean; step: number; } ) { const [ min = '', max = '' ] = value; const onChangeMin = useCallback( ( newValue: string | undefined ) => onChange( [ toNumberOrEmpty( newValue ), max ] ), [ onChange, max ] ); const onChangeMax = useCallback( ( newValue: string | undefined ) => onChange( [ min, toNumberOrEmpty( newValue ) ] ), [ onChange, min ] ); return ( ); } export default function ValidatedNumber< Item >( { data, field, onChange, hideLabelFromVision, markWhenOptional, operator, validity, }: DataFormControlProps< Item > ) { const decimals = ( field.format as FormatNumber )?.decimals ?? 0; const step = Math.pow( 10, Math.abs( decimals ) * -1 ); const { label, description, getValue, setValue, isValid } = field; const value = getValue( { item: data } ) ?? ''; const onChangeControl = useCallback( ( newValue: string | undefined ) => { onChange( setValue( { item: data, // Do not convert an empty string or undefined to a number, // otherwise there's a mismatch between the UI control (empty) // and the data relied by onChange (0). value: [ '', undefined ].includes( newValue ) ? undefined : Number( newValue ), } ) ); }, [ data, onChange, setValue ] ); const onChangeBetweenControls = useCallback( ( newValue: NumberBetween ) => { onChange( setValue( { item: data, value: newValue, } ) ); }, [ data, onChange, setValue ] ); if ( operator === OPERATOR_BETWEEN ) { let valueBetween: NumberBetween = [ '', '' ]; if ( Array.isArray( value ) && value.length === 2 && value.every( ( element ) => typeof element === 'number' || element === '' ) ) { valueBetween = value as NumberBetween; } return ( ); } return ( ); }