Skip to content

fix: DH-22684: ui.text_field preserves user input while focused#1350

Open
mofojed wants to merge 1 commit into
deephaven:mainfrom
mofojed:DH-22684-text-field-input
Open

fix: DH-22684: ui.text_field preserves user input while focused#1350
mofojed wants to merge 1 commit into
deephaven:mainfrom
mofojed:DH-22684-text-field-input

Conversation

@mofojed
Copy link
Copy Markdown
Member

@mofojed mofojed commented May 21, 2026

  • Do not overwrite the input value with server-pushed propValue while the
    text field is focused; sync on focus->blur transition instead.
  • Stop passing defaultValue as the controlled value when no value prop is
    provided.
  • Add current input value to the serialized FocusEvent payload so on_focus
    / on_blur handlers can read what the user typed.
  • Add e2e test covering the laggy-on_change focused-typing scenario, focus and change events.

- Do not overwrite the input value with server-pushed propValue while the
  text field is focused; sync on focus->blur transition instead.
- Stop passing defaultValue as the controlled value when no value prop is
  provided.
- Add current input value to the serialized FocusEvent payload so on_focus
  / on_blur handlers can read what the user typed.
- Add e2e test covering the laggy-on_change focused-typing scenario, focus and change events.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses DH-22684 by preventing ui.text_field from overwriting in-progress user typing while the field is focused, and by enriching focus/blur event payloads so server-side handlers can read the current input value.

Changes:

  • Add focus-tracking + updated debounced value syncing so server-pushed value updates are deferred until blur.
  • Extend serialized focus events to include the current input element value.
  • Add Playwright e2e coverage (including a slow server on_change scenario) and a test app panel to exercise focus/change/blur payloads.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/utils.ts Type-only import cleanup for Playwright types.
tests/ui_text_field.spec.ts New e2e coverage for focused typing + focus/change/blur payload assertions.
tests/app.d/ui_text_field.py Adds test panels used by the new e2e spec (slow on_change + event logging).
tests/app.d/tests.app Registers the new test app panel module.
plugins/ui/src/js/src/elements/hooks/useTextInputProps.ts Tracks focus state and passes it into debounced change handling.
plugins/ui/src/js/src/elements/hooks/useFocusEventCallback.ts Serializes current target value into focus/blur events when available.
plugins/ui/src/js/src/elements/hooks/useDebouncedOnChange.ts Skips server→UI value sync while focused; syncs on blur transition.
plugins/ui/src/deephaven/ui/components/types/events.py Updates Python FocusEvent typing to include value.
Comments suppressed due to low confidence (1)

plugins/ui/src/js/src/elements/hooks/useTextInputProps.ts:51

  • useTextInputProps now calls useDebouncedOnChange(propValue, ...) but still always returns a value prop. When propValue is omitted (uncontrolled usage with only defaultValue), the hook initializes value to undefined and then sets it to a string on first user edit, which causes an uncontrolled→controlled transition (React warning) and effectively reintroduces local control of the field. Consider branching: if propValue is undefined, omit value from the returned props (and avoid storing local value state), while still wiring onChange to call the debounced server callback; only provide a controlled value when propValue is defined.
  const [value, onChange] = useDebouncedOnChange(
    propValue,
    propOnChange,
    isFocused
  );

  return {
    defaultValue,
    value,
    onChange,

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +18 to 33
// Update local value to match a new propValue from the server when no user
// changes are queued. Skip while the input is focused so we don't change the
// value out from under the user while they are typing. When the input loses
// focus, sync to the latest propValue even if it didn't change on this
// render.
const justBlurred = prevIsFocused === true && isFocused === false;
const propValueChanged = propValue !== prevPropValue;
if (
propValue !== prevPropValue &&
(propValueChanged || justBlurred) &&
propValue !== value &&
propValue !== undefined &&
!pending
!pending &&
!isFocused
) {
setValue(propValue);
}
Comment on lines 18 to +25
The name of the related target element of the focus event.
"""

value: str | None
"""
The current `value` of the underlying input element, when available
(e.g. for text fields, text areas, search fields, number fields).
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants