@@ -60,6 +60,9 @@ export function createReconciler(
6060 // Store the onChange callbacks to be runned every time a Result has changed
6161 const changeEvents = new Map < Entity , Map < number , OnChangeState | undefined > > ( )
6262 const clickEvents = new Map < Entity , Map < PointerEventType , Callback > > ( )
63+ // Track the last value reported by the renderer for each input entity,
64+ // so we can avoid echoing it back and causing keystroke drops.
65+ const lastInputResultValues = new Map < Entity , string | undefined > ( )
6366 // Initialize components
6467 const UiTransform = components . UiTransform ( engine )
6568 const UiText = components . UiText ( engine )
@@ -175,6 +178,18 @@ export function createReconciler(
175178 delete ( props as any ) . onSubmit
176179 }
177180
181+ // Prevent keystroke drops: when React echoes back the same value the renderer
182+ // reported, strip it from the props so the component isn't marked dirty for it.
183+ // This avoids sending a stale value that overwrites what the user is currently typing.
184+ if (
185+ componentName === 'uiInput' &&
186+ 'value' in props &&
187+ lastInputResultValues . has ( instance . entity ) &&
188+ ( props as any ) . value === lastInputResultValues . get ( instance . entity )
189+ ) {
190+ delete ( props as any ) . value
191+ }
192+
178193 // We check if there is any key pending to be changed to avoid updating the existing component
179194 if ( ! Object . keys ( props ) . length ) {
180195 return
@@ -192,6 +207,7 @@ export function createReconciler(
192207 function removeChildEntity ( instance : Instance ) {
193208 changeEvents . delete ( instance . entity )
194209 clickEvents . delete ( instance . entity )
210+ lastInputResultValues . delete ( instance . entity )
195211 engine . removeEntity ( instance . entity )
196212 for ( const child of instance . _child ) {
197213 removeChildEntity ( child )
@@ -252,6 +268,9 @@ export function createReconciler(
252268 const resultComponentId =
253269 componentId === UiDropdown . componentId ? UiDropdownResult . componentId : UiInputResult . componentId
254270 engine . getComponent < PBUiInputResult | PBUiDropdownResult > ( resultComponentId ) . onChange ( entity , ( value ) => {
271+ if ( resultComponentId === UiInputResult . componentId ) {
272+ lastInputResultValues . set ( entity , value ?. value as string | undefined )
273+ }
255274 if ( ( value as PBUiInputResult ) ?. isSubmit ) {
256275 const onSubmit = changeEvents . get ( entity ) ?. get ( componentId ) ?. onSubmitCallback
257276 onSubmit && onSubmit ( value ?. value )
0 commit comments