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 de4845af4..985693a14 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 2971df827..9e4743c15 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 985693a14..d84171f55 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 9e4743c15..ea9840008 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 ea9840008..f3790f196 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 7cb128f8b..288f84cc6 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 358d45f71..b538a7e5e 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 4d2f8f376..2fc2db81d 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 0a7c1da8e..a5b4483ca 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 f3790f196..a1338ff18 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 a1338ff18..2d0099ccc 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 288f84cc6..87939a32c 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 b538a7e5e..6c650f1f5 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 2fc2db81d..8d69b1e63 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 a5b4483ca..0a7c1da8e 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 7b24ef3e9..2df8a13cc 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);