From f80ebd61a66091a324d67b4ead87cf3eb671d05c Mon Sep 17 00:00:00 2001 From: Johannes Eriksson Date: Tue, 15 Apr 2025 10:20:49 +0200 Subject: [PATCH 1/8] refactor(material-renderers): flushable debounce this is just a poc to see if this path is viable --- .../src/mui-controls/MuiInputText.tsx | 15 ++++++++++++--- packages/material-renderers/src/util/debounce.ts | 15 +++++++++------ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/material-renderers/src/mui-controls/MuiInputText.tsx b/packages/material-renderers/src/mui-controls/MuiInputText.tsx index de4845af41..985693a146 100644 --- a/packages/material-renderers/src/mui-controls/MuiInputText.tsx +++ b/packages/material-renderers/src/mui-controls/MuiInputText.tsx @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { CellProps, WithClassname } from '@jsonforms/core'; import { IconButton, @@ -38,6 +38,7 @@ import { WithInputProps, useDebouncedChange, useInputComponent, + useFocus, } from '../util'; interface MuiTextInputProps { @@ -51,6 +52,7 @@ const eventToValue = (ev: any) => export const MuiInputText = React.memo(function MuiInputText( props: CellProps & WithClassname & MuiTextInputProps & WithInputProps ) { + const [focused, onFocus, onBlur] = useFocus(); const [showAdornment, setShowAdornment] = useState(false); const { data, @@ -83,13 +85,18 @@ export const MuiInputText = React.memo(function MuiInputText( inputProps.size = maxLength; } - const [inputText, onChange, onClear] = useDebouncedChange( + const [inputText, onChange, onClear, cancelDebounce] = useDebouncedChange( handleChange, '', data, path, - eventToValue + eventToValue, ); + useEffect(() => { + if (!focused) { + cancelDebounce(); + } + }, [focused, cancelDebounce]); const onPointerEnter = () => setShowAdornment(true); const onPointerLeave = () => setShowAdornment(false); @@ -109,6 +116,8 @@ export const MuiInputText = React.memo(function MuiInputText( value={inputText} onChange={onChange} className={className} + onBlur={onBlur} + onFocus={onFocus} id={id} disabled={!enabled} autoFocus={appliedUiSchemaOptions.focus} diff --git a/packages/material-renderers/src/util/debounce.ts b/packages/material-renderers/src/util/debounce.ts index 2971df8273..9e4743c151 100644 --- a/packages/material-renderers/src/util/debounce.ts +++ b/packages/material-renderers/src/util/debounce.ts @@ -1,19 +1,19 @@ /* The MIT License - + Copyright (c) 2021 EclipseSource Munich https://github.com/eclipsesource/jsonforms - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -33,7 +33,7 @@ export const useDebouncedChange = ( path: string, eventToValueFunction: (ev: any) => any = eventToValue, timeout = 300 -): [any, React.ChangeEventHandler, () => void] => { +): [any, React.ChangeEventHandler, () => void, () => void] => { const [input, setInput] = useState(data ?? defaultValue); useEffect(() => { setInput(data ?? defaultValue); @@ -54,5 +54,8 @@ export const useDebouncedChange = ( setInput(defaultValue); handleChange(path, undefined); }, [defaultValue, handleChange, path]); - return [input, onChange, onClear]; + const immediateUpdate = useCallback(() => { + debouncedUpdate.flush(); + }, [debouncedUpdate]); + return [input, onChange, onClear, immediateUpdate]; }; From 301a30a75003473b2fc556e776681c6a830888cc Mon Sep 17 00:00:00 2001 From: Johannes Eriksson Date: Wed, 16 Apr 2025 08:11:07 +0200 Subject: [PATCH 2/8] refactor: add `focused`and `flushOnBlur` parameters to `useDebouncedChange` --- .../src/mui-controls/MuiInputText.tsx | 11 ++++------- packages/material-renderers/src/util/debounce.ts | 14 +++++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/material-renderers/src/mui-controls/MuiInputText.tsx b/packages/material-renderers/src/mui-controls/MuiInputText.tsx index 985693a146..d84171f555 100644 --- a/packages/material-renderers/src/mui-controls/MuiInputText.tsx +++ b/packages/material-renderers/src/mui-controls/MuiInputText.tsx @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { CellProps, WithClassname } from '@jsonforms/core'; import { IconButton, @@ -85,18 +85,15 @@ export const MuiInputText = React.memo(function MuiInputText( inputProps.size = maxLength; } - const [inputText, onChange, onClear, cancelDebounce] = useDebouncedChange( + const [inputText, onChange, onClear] = useDebouncedChange( handleChange, '', data, path, eventToValue, + focused, + true ); - useEffect(() => { - if (!focused) { - cancelDebounce(); - } - }, [focused, cancelDebounce]); const onPointerEnter = () => setShowAdornment(true); const onPointerLeave = () => setShowAdornment(false); diff --git a/packages/material-renderers/src/util/debounce.ts b/packages/material-renderers/src/util/debounce.ts index 9e4743c151..ea9840008a 100644 --- a/packages/material-renderers/src/util/debounce.ts +++ b/packages/material-renderers/src/util/debounce.ts @@ -32,8 +32,10 @@ export const useDebouncedChange = ( data: any, path: string, eventToValueFunction: (ev: any) => any = eventToValue, + focused = false, + flushOnBlur = false, timeout = 300 -): [any, React.ChangeEventHandler, () => void, () => void] => { +): [any, React.ChangeEventHandler, () => void] => { const [input, setInput] = useState(data ?? defaultValue); useEffect(() => { setInput(data ?? defaultValue); @@ -42,6 +44,11 @@ export const useDebouncedChange = ( debounce((newValue: string) => handleChange(path, newValue), timeout), [handleChange, path, timeout] ); + useEffect(() => { + if (!focused && flushOnBlur) { + debouncedUpdate.flush(); + } + }, [focused, flushOnBlur, debouncedUpdate]); const onChange = useCallback( (ev: any) => { const newValue = eventToValueFunction(ev); @@ -54,8 +61,5 @@ export const useDebouncedChange = ( setInput(defaultValue); handleChange(path, undefined); }, [defaultValue, handleChange, path]); - const immediateUpdate = useCallback(() => { - debouncedUpdate.flush(); - }, [debouncedUpdate]); - return [input, onChange, onClear, immediateUpdate]; + return [input, onChange, onClear]; }; From d34a19bc7e45b361134f86f20a3f286e59b2a13f Mon Sep 17 00:00:00 2001 From: Johannes Eriksson Date: Wed, 16 Apr 2025 08:53:51 +0200 Subject: [PATCH 3/8] refactor: add `DebouncedChangeParams`interface --- .../material-renderers/src/util/debounce.ts | 34 ++++++++++++------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/material-renderers/src/util/debounce.ts b/packages/material-renderers/src/util/debounce.ts index ea9840008a..f3790f1962 100644 --- a/packages/material-renderers/src/util/debounce.ts +++ b/packages/material-renderers/src/util/debounce.ts @@ -25,17 +25,27 @@ import debounce from 'lodash/debounce'; import { useState, useCallback, useEffect } from 'react'; -const eventToValue = (ev: any) => ev.target.value; -export const useDebouncedChange = ( - handleChange: (path: string, value: any) => void, - defaultValue: any, - data: any, - path: string, - eventToValueFunction: (ev: any) => any = eventToValue, - focused = false, +const defaultEventToValue = (ev: any) => ev.target.value; +interface DebouncedChangeParams { + handleChange: (path: string, value: any) => void; + data: any; + path: string; + eventToValue?: (ev: any) => any; + defaultValue?: any; + flushOnBlur?: boolean; + focused?: boolean; + timeout?: number; +} +export const useDebouncedChange = ({ + handleChange, + data, + path, + eventToValue = defaultEventToValue, + defaultValue = '', flushOnBlur = false, - timeout = 300 -): [any, React.ChangeEventHandler, () => void] => { + focused = false, + timeout = 500, +}: DebouncedChangeParams): [any, React.ChangeEventHandler, () => void] => { const [input, setInput] = useState(data ?? defaultValue); useEffect(() => { setInput(data ?? defaultValue); @@ -51,11 +61,11 @@ export const useDebouncedChange = ( }, [focused, flushOnBlur, debouncedUpdate]); const onChange = useCallback( (ev: any) => { - const newValue = eventToValueFunction(ev); + const newValue = eventToValue(ev); setInput(newValue ?? defaultValue); debouncedUpdate(newValue); }, - [debouncedUpdate, eventToValueFunction] + [debouncedUpdate, eventToValue] ); const onClear = useCallback(() => { setInput(defaultValue); From e91e3c6e2fde8190c8928c489c7b2660d02cc9cb Mon Sep 17 00:00:00 2001 From: Johannes Eriksson Date: Wed, 16 Apr 2025 08:54:36 +0200 Subject: [PATCH 4/8] refactor: implement `flushOnBlur` on controls where typing occurs --- .../MaterialAnyOfStringOrEnumControl.tsx | 19 ++++++++++++----- .../src/controls/MaterialNativeControl.tsx | 15 +++++++------ .../src/mui-controls/MuiInputInteger.tsx | 19 ++++++++++++----- .../src/mui-controls/MuiInputNumber.tsx | 19 ++++++++++++----- .../src/mui-controls/MuiInputNumberFormat.tsx | 21 +++++++++++++------ .../src/mui-controls/MuiInputText.tsx | 7 +++---- .../src/mui-controls/MuiInputTime.tsx | 7 +++---- 7 files changed, 70 insertions(+), 37 deletions(-) diff --git a/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx b/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx index 7cb128f8bb..288f84cc61 100644 --- a/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx +++ b/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx @@ -38,7 +38,12 @@ import { Control, withJsonFormsControlProps } from '@jsonforms/react'; import { InputBaseComponentProps } from '@mui/material'; import merge from 'lodash/merge'; import React, { useMemo } from 'react'; -import { useDebouncedChange, useInputComponent, WithInputProps } from '../util'; +import { + useDebouncedChange, + useInputComponent, + WithInputProps, + useFocus, +} from '../util'; import { MaterialInputControl } from './MaterialInputControl'; const findEnumSchema = (schemas: JsonSchema[]) => @@ -51,6 +56,7 @@ const findTextSchema = (schemas: JsonSchema[]) => const MuiAutocompleteInputText = ( props: EnumCellProps & WithClassname & WithInputProps ) => { + const [focused, onFocus, onBlur] = useFocus(); const { data, config, @@ -83,12 +89,13 @@ const MuiAutocompleteInputText = ( propMemo.list = props.id + 'datalist'; return propMemo; }, [appliedUiSchemaOptions, props.id]); - const [inputText, onChange] = useDebouncedChange( + const [inputText, onChange] = useDebouncedChange({ handleChange, - '', data, - path - ); + path, + focused, + flushOnBlur: true, + }); const dataList = ( @@ -102,6 +109,8 @@ const MuiAutocompleteInputText = ( type='text' value={inputText} onChange={onChange} + onFocus={onFocus} + onBlur={onBlur} className={className} id={id} label={label} diff --git a/packages/material-renderers/src/controls/MaterialNativeControl.tsx b/packages/material-renderers/src/controls/MaterialNativeControl.tsx index 358d45f71b..b538a7e5e4 100644 --- a/packages/material-renderers/src/controls/MaterialNativeControl.tsx +++ b/packages/material-renderers/src/controls/MaterialNativeControl.tsx @@ -1,19 +1,19 @@ /* The MIT License - + Copyright (c) 2017-2019 EclipseSource Munich https://github.com/eclipsesource/jsonforms - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -56,12 +56,11 @@ export const MaterialNativeControl = (props: ControlProps) => { } = props; const isValid = errors.length === 0; const appliedUiSchemaOptions = merge({}, config, props.uischema.options); - const [inputValue, onChange] = useDebouncedChange( + const [inputValue, onChange] = useDebouncedChange({ handleChange, - '', data, - path - ); + path, + }); const fieldType = appliedUiSchemaOptions.format ?? schema.format; const showDescription = !isDescriptionHidden( visible, diff --git a/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx b/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx index 4d2f8f376b..2fc2db81d1 100644 --- a/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx +++ b/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx @@ -25,7 +25,12 @@ import React from 'react'; import { CellProps, WithClassname } from '@jsonforms/core'; import merge from 'lodash/merge'; -import { useDebouncedChange, useInputComponent, WithInputProps } from '../util'; +import { + useDebouncedChange, + useInputComponent, + WithInputProps, + useFocus, +} from '../util'; const toNumber = (value: string) => value === '' ? undefined : parseInt(value, 10); @@ -34,6 +39,7 @@ const eventToValue = (ev: any) => toNumber(ev.target.value); export const MuiInputInteger = React.memo(function MuiInputInteger( props: CellProps & WithClassname & WithInputProps ) { + const [focused, onFocus, onBlur] = useFocus(); const { data, className, @@ -51,19 +57,22 @@ export const MuiInputInteger = React.memo(function MuiInputInteger( const appliedUiSchemaOptions = merge({}, config, uischema.options); - const [inputValue, onChange] = useDebouncedChange( + const [inputValue, onChange] = useDebouncedChange({ handleChange, - '', data, path, - eventToValue - ); + eventToValue, + focused, + flushOnBlur: true, + }); return ( value === '' ? undefined : parseFloat(value); @@ -33,6 +38,7 @@ const eventToValue = (ev: any) => toNumber(ev.target.value); export const MuiInputNumber = React.memo(function MuiInputNumber( props: CellProps & WithClassname & WithInputProps ) { + const [focused, onFocus, onBlur] = useFocus(); const { data, className, @@ -49,13 +55,14 @@ export const MuiInputNumber = React.memo(function MuiInputNumber( const inputProps = { step: '0.1' }; const appliedUiSchemaOptions = merge({}, config, uischema.options); - const [inputValue, onChange] = useDebouncedChange( + const [inputValue, onChange] = useDebouncedChange({ handleChange, - '', data, path, - eventToValue - ); + eventToValue, + focused, + flushOnBlur: true, + }); return ( & WithInputProps ) { + const [focused, onFocus, onBlur] = useFocus(); const { className, id, @@ -57,19 +63,22 @@ export const MuiInputNumberFormat = React.memo(function MuiInputNumberFormat( (ev: any) => props.fromFormatted(ev.currentTarget.value), [props.fromFormatted] ); - const [inputValue, onChange] = useDebouncedChange( + const [inputValue, onChange] = useDebouncedChange({ handleChange, - '', - formattedNumber, + data: formattedNumber, path, - validStringNumber - ); + eventToValue: validStringNumber, + focused, + flushOnBlur: true, + }); return ( setShowAdornment(true); const onPointerLeave = () => setShowAdornment(false); diff --git a/packages/material-renderers/src/mui-controls/MuiInputTime.tsx b/packages/material-renderers/src/mui-controls/MuiInputTime.tsx index 0a7c1da8eb..a5b4483ca5 100644 --- a/packages/material-renderers/src/mui-controls/MuiInputTime.tsx +++ b/packages/material-renderers/src/mui-controls/MuiInputTime.tsx @@ -44,12 +44,11 @@ export const MuiInputTime = React.memo(function MuiInputTime( } = props; const InputComponent = useInputComponent(); const appliedUiSchemaOptions = merge({}, config, uischema.options); - const [inputValue, onChange] = useDebouncedChange( + const [inputValue, onChange] = useDebouncedChange({ handleChange, - '', data, - path - ); + path, + }); return ( Date: Wed, 16 Apr 2025 09:06:38 +0200 Subject: [PATCH 5/8] refactor: set default timeout to 300 --- packages/material-renderers/src/util/debounce.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/material-renderers/src/util/debounce.ts b/packages/material-renderers/src/util/debounce.ts index f3790f1962..a1338ff18e 100644 --- a/packages/material-renderers/src/util/debounce.ts +++ b/packages/material-renderers/src/util/debounce.ts @@ -44,7 +44,7 @@ export const useDebouncedChange = ({ defaultValue = '', flushOnBlur = false, focused = false, - timeout = 500, + timeout = 300, }: DebouncedChangeParams): [any, React.ChangeEventHandler, () => void] => { const [input, setInput] = useState(data ?? defaultValue); useEffect(() => { From e6a238220fba671523be73a3f9aa4a7ace888c8f Mon Sep 17 00:00:00 2001 From: Johannes Eriksson Date: Wed, 16 Apr 2025 13:39:56 +0200 Subject: [PATCH 6/8] fix: does this fix the CI test run? --- packages/material-renderers/src/util/debounce.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/material-renderers/src/util/debounce.ts b/packages/material-renderers/src/util/debounce.ts index a1338ff18e..2d0099ccc2 100644 --- a/packages/material-renderers/src/util/debounce.ts +++ b/packages/material-renderers/src/util/debounce.ts @@ -40,7 +40,7 @@ export const useDebouncedChange = ({ handleChange, data, path, - eventToValue = defaultEventToValue, + eventToValue = undefined, defaultValue = '', flushOnBlur = false, focused = false, @@ -61,7 +61,9 @@ export const useDebouncedChange = ({ }, [focused, flushOnBlur, debouncedUpdate]); const onChange = useCallback( (ev: any) => { - const newValue = eventToValue(ev); + const newValue = eventToValue + ? eventToValue(ev) + : defaultEventToValue(ev); setInput(newValue ?? defaultValue); debouncedUpdate(newValue); }, From 1f1b394f6e17bb08574756d790a8d9e36c6ef35f Mon Sep 17 00:00:00 2001 From: Johannes Eriksson Date: Thu, 22 May 2025 14:53:57 +0200 Subject: [PATCH 7/8] refactor: revert named parameters and add optional parameters to the original function signature --- .../MaterialAnyOfStringOrEnumControl.tsx | 11 +++--- .../src/controls/MaterialNativeControl.tsx | 9 +++-- .../src/mui-controls/MuiInputInteger.tsx | 10 +++--- .../src/mui-controls/MuiInputNumber.tsx | 10 +++--- .../src/mui-controls/MuiInputNumberFormat.tsx | 14 ++++---- .../src/mui-controls/MuiInputText.tsx | 10 +++--- .../src/mui-controls/MuiInputTime.tsx | 7 ++-- .../material-renderers/src/util/debounce.ts | 34 ++++++------------- 8 files changed, 55 insertions(+), 50 deletions(-) diff --git a/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx b/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx index 288f84cc61..87939a32c0 100644 --- a/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx +++ b/packages/material-renderers/src/controls/MaterialAnyOfStringOrEnumControl.tsx @@ -89,13 +89,16 @@ const MuiAutocompleteInputText = ( propMemo.list = props.id + 'datalist'; return propMemo; }, [appliedUiSchemaOptions, props.id]); - const [inputText, onChange] = useDebouncedChange({ + const [inputText, onChange] = useDebouncedChange( handleChange, + '', data, path, - focused, - flushOnBlur: true, - }); + undefined, + undefined, + true, + focused + ); const dataList = ( diff --git a/packages/material-renderers/src/controls/MaterialNativeControl.tsx b/packages/material-renderers/src/controls/MaterialNativeControl.tsx index b538a7e5e4..6c650f1f50 100644 --- a/packages/material-renderers/src/controls/MaterialNativeControl.tsx +++ b/packages/material-renderers/src/controls/MaterialNativeControl.tsx @@ -56,11 +56,16 @@ export const MaterialNativeControl = (props: ControlProps) => { } = props; const isValid = errors.length === 0; const appliedUiSchemaOptions = merge({}, config, props.uischema.options); - const [inputValue, onChange] = useDebouncedChange({ + const [inputValue, onChange] = useDebouncedChange( handleChange, + '', data, path, - }); + undefined, + undefined, + true, + focused + ); const fieldType = appliedUiSchemaOptions.format ?? schema.format; const showDescription = !isDescriptionHidden( visible, diff --git a/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx b/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx index 2fc2db81d1..8d69b1e635 100644 --- a/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx +++ b/packages/material-renderers/src/mui-controls/MuiInputInteger.tsx @@ -57,14 +57,16 @@ export const MuiInputInteger = React.memo(function MuiInputInteger( const appliedUiSchemaOptions = merge({}, config, uischema.options); - const [inputValue, onChange] = useDebouncedChange({ + const [inputValue, onChange] = useDebouncedChange( handleChange, + '', data, path, eventToValue, - focused, - flushOnBlur: true, - }); + undefined, + true, + focused + ); return ( props.fromFormatted(ev.currentTarget.value), [props.fromFormatted] ); - const [inputValue, onChange] = useDebouncedChange({ + const [inputValue, onChange] = useDebouncedChange( handleChange, - data: formattedNumber, + '', + formattedNumber, path, - eventToValue: validStringNumber, - focused, - flushOnBlur: true, - }); + validStringNumber, + undefined, + true, + focused + ); return ( setShowAdornment(true); const onPointerLeave = () => setShowAdornment(false); diff --git a/packages/material-renderers/src/mui-controls/MuiInputTime.tsx b/packages/material-renderers/src/mui-controls/MuiInputTime.tsx index a5b4483ca5..0a7c1da8eb 100644 --- a/packages/material-renderers/src/mui-controls/MuiInputTime.tsx +++ b/packages/material-renderers/src/mui-controls/MuiInputTime.tsx @@ -44,11 +44,12 @@ export const MuiInputTime = React.memo(function MuiInputTime( } = props; const InputComponent = useInputComponent(); const appliedUiSchemaOptions = merge({}, config, uischema.options); - const [inputValue, onChange] = useDebouncedChange({ + const [inputValue, onChange] = useDebouncedChange( handleChange, + '', data, - path, - }); + path + ); return ( ev.target.value; -interface DebouncedChangeParams { - handleChange: (path: string, value: any) => void; - data: any; - path: string; - eventToValue?: (ev: any) => any; - defaultValue?: any; - flushOnBlur?: boolean; - focused?: boolean; - timeout?: number; -} -export const useDebouncedChange = ({ - handleChange, - data, - path, - eventToValue = undefined, - defaultValue = '', - flushOnBlur = false, - focused = false, +const eventToValue = (ev: any) => ev.target.value; +export const useDebouncedChange = ( + handleChange: (path: string, value: any) => void, + defaultValue: any, + data: any, + path: string, + eventToValueFunction: (ev: any) => any = eventToValue, timeout = 300, -}: DebouncedChangeParams): [any, React.ChangeEventHandler, () => void] => { + flushOnBlur = false, + focused = false +): [any, React.ChangeEventHandler, () => void] => { const [input, setInput] = useState(data ?? defaultValue); useEffect(() => { setInput(data ?? defaultValue); @@ -61,9 +51,7 @@ export const useDebouncedChange = ({ }, [focused, flushOnBlur, debouncedUpdate]); const onChange = useCallback( (ev: any) => { - const newValue = eventToValue - ? eventToValue(ev) - : defaultEventToValue(ev); + const newValue = eventToValueFunction(ev); setInput(newValue ?? defaultValue); debouncedUpdate(newValue); }, From 4d4fca1ea83f3c6ae1a8fc5cb07e10f671893b4d Mon Sep 17 00:00:00 2001 From: Johannes Eriksson Date: Fri, 23 May 2025 12:17:28 +0200 Subject: [PATCH 8/8] fix: restore original dependency --- packages/material-renderers/src/util/debounce.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/material-renderers/src/util/debounce.ts b/packages/material-renderers/src/util/debounce.ts index 7b24ef3e9a..2df8a13cc2 100644 --- a/packages/material-renderers/src/util/debounce.ts +++ b/packages/material-renderers/src/util/debounce.ts @@ -55,7 +55,7 @@ export const useDebouncedChange = ( setInput(newValue ?? defaultValue); debouncedUpdate(newValue); }, - [debouncedUpdate, eventToValue] + [debouncedUpdate, eventToValueFunction] ); const onClear = useCallback(() => { setInput(defaultValue);