From 548987d758895b062728c926a5c7f674589c844f Mon Sep 17 00:00:00 2001 From: Nathan Silveira Date: Tue, 9 Jan 2024 18:08:38 -0300 Subject: [PATCH] Add step buttons for Number block and component (#43045) * Add showStepButtons attribute for Number block and component * Use native step buttons * Revert "Use native step buttons" This reverts commit 8425d17399077642d055621fe74d54866322dd09. * Use custom step buttons and hide them when field is not focused * Revert type="number" as it's not working well with number formatting * Disable autocomplete * Remove leftover showStepButtons from documentation * Prevent default event when pressing up/down * Change to onKeyDown event * Implement timeout to hold + and - buttons * Remove unnecessary onBlur and prevent default event when onKeyUp * Fix TS issue * Update changelog --- .../product-editor/changelog/add-step-buttons | 4 + .../number-control/number-control.tsx | 104 +++++++++++++++++- .../src/hooks/use-number-input-props.ts | 16 ++- 3 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 packages/js/product-editor/changelog/add-step-buttons diff --git a/packages/js/product-editor/changelog/add-step-buttons b/packages/js/product-editor/changelog/add-step-buttons new file mode 100644 index 00000000000..fe84d148c82 --- /dev/null +++ b/packages/js/product-editor/changelog/add-step-buttons @@ -0,0 +1,4 @@ +Significance: minor +Type: add + +Add step buttons for Number block and component diff --git a/packages/js/product-editor/src/components/number-control/number-control.tsx b/packages/js/product-editor/src/components/number-control/number-control.tsx index 80f512e5baa..f055a164961 100644 --- a/packages/js/product-editor/src/components/number-control/number-control.tsx +++ b/packages/js/product-editor/src/components/number-control/number-control.tsx @@ -1,11 +1,20 @@ /** * External dependencies */ -import { createElement } from '@wordpress/element'; +import { + createElement, + Fragment, + useEffect, + useRef, + useState, +} from '@wordpress/element'; import { useInstanceId } from '@wordpress/compose'; import classNames from 'classnames'; +import { plus, reset } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; import { BaseControl, + Button, // @ts-expect-error `__experimentalInputControl` does exist. __experimentalInputControl as InputControl, } from '@wordpress/components'; @@ -43,14 +52,45 @@ export const NumberControl: React.FC< NumberProps > = ( { tooltip, placeholder, disabled, - step, + step = 1, }: NumberProps ) => { + const id = useInstanceId( BaseControl, 'product_number_field' ) as string; + const [ isFocused, setIsFocused ] = useState( false ); + const unfocusIfOutside = ( event: React.FocusEvent ) => { + if ( + ! document + .getElementById( id ) + ?.parentElement?.contains( event.relatedTarget ) + ) { + setIsFocused( false ); + onBlur?.(); + } + }; const inputProps = useNumberInputProps( { value: value || '', onChange, + onFocus: () => setIsFocused( true ), } ); - const id = useInstanceId( BaseControl, 'product_number_field' ) as string; + const [ increment, setIncrement ] = useState( 0 ); + + const timeoutRef = useRef< number | null >( null ); + + const incrementValue = () => + onChange( String( parseFloat( value || '0' ) + increment ) ); + + useEffect( () => { + if ( increment !== 0 ) { + timeoutRef.current = setTimeout( incrementValue, 100 ); + } else if ( timeoutRef.current ) { + clearTimeout( timeoutRef.current ); + } + return () => { + if ( timeoutRef.current ) { + clearTimeout( timeoutRef.current ); + } + }; + }, [ increment, value ] ); return ( = ( { { ...inputProps } step={ step } disabled={ disabled } + autoComplete="off" id={ id } - suffix={ suffix } + className="woocommerce-number-control" + suffix={ + <> + { suffix } + { isFocused && ( + <> +