From 7ca50c62e2354d142f5870defb2a8a6cc79d43ee Mon Sep 17 00:00:00 2001 From: Elijah Ahianyo Date: Thu, 12 Dec 2024 23:24:15 +0000 Subject: [PATCH] [ENG-4153]Use empty string for None values in `rx.input` and `rx.el.input` (#4521) * Use empty string for None values in `rx.input` and `rx.el.input` * fix tests * fix pyi scripts * use nullish coalescing operator * fix unit tests * use ternary operator so old browsers and dynamic components tests pass * address comment on doing this only for optionals * Fix tests * pyright! * fix comments --- reflex/components/el/elements/forms.py | 28 +++++++++++++++++++ reflex/components/el/elements/forms.pyi | 4 +-- .../radix/themes/components/text_field.py | 15 ++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/reflex/components/el/elements/forms.py b/reflex/components/el/elements/forms.py index 205aae2673..61ded4fd3c 100644 --- a/reflex/components/el/elements/forms.py +++ b/reflex/components/el/elements/forms.py @@ -18,6 +18,7 @@ prevent_default, ) from reflex.utils.imports import ImportDict +from reflex.utils.types import is_optional from reflex.vars import VarData from reflex.vars.base import LiteralVar, Var @@ -382,6 +383,33 @@ class Input(BaseHTML): # Fired when a key is released on_key_up: EventHandler[key_event] + @classmethod + def create(cls, *children, **props): + """Create an Input component. + + Args: + *children: The children of the component. + **props: The properties of the component. + + Returns: + The component. + """ + from reflex.vars.number import ternary_operation + + value = props.get("value") + + # React expects an empty string(instead of null) for controlled inputs. + if value is not None and is_optional( + (value_var := Var.create(value))._var_type + ): + props["value"] = ternary_operation( + (value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues] + & (value_var != Var(_js_expr="undefined")), + value, + Var.create(""), + ) + return super().create(*children, **props) + class Label(BaseHTML): """Display the label element.""" diff --git a/reflex/components/el/elements/forms.pyi b/reflex/components/el/elements/forms.pyi index 5870d4b22a..dfab40b219 100644 --- a/reflex/components/el/elements/forms.pyi +++ b/reflex/components/el/elements/forms.pyi @@ -512,7 +512,7 @@ class Input(BaseHTML): on_unmount: Optional[EventType[[], BASE_STATE]] = None, **props, ) -> "Input": - """Create the component. + """Create an Input component. Args: *children: The children of the component. @@ -576,7 +576,7 @@ class Input(BaseHTML): class_name: The class name for the component. autofocus: Whether the component should take the focus once the page is loaded custom_attrs: custom attribute - **props: The props of the component. + **props: The properties of the component. Returns: The component. diff --git a/reflex/components/radix/themes/components/text_field.py b/reflex/components/radix/themes/components/text_field.py index 3dabe09366..7e6dfe85c9 100644 --- a/reflex/components/radix/themes/components/text_field.py +++ b/reflex/components/radix/themes/components/text_field.py @@ -9,7 +9,9 @@ from reflex.components.core.debounce import DebounceInput from reflex.components.el import elements from reflex.event import EventHandler, input_event, key_event +from reflex.utils.types import is_optional from reflex.vars.base import Var +from reflex.vars.number import ternary_operation from ..base import LiteralAccentColor, LiteralRadius, RadixThemesComponent @@ -96,6 +98,19 @@ def create(cls, *children, **props) -> Component: Returns: The component. """ + value = props.get("value") + + # React expects an empty string(instead of null) for controlled inputs. + if value is not None and is_optional( + (value_var := Var.create(value))._var_type + ): + props["value"] = ternary_operation( + (value_var != Var.create(None)) # pyright: ignore [reportGeneralTypeIssues] + & (value_var != Var(_js_expr="undefined")), + value, + Var.create(""), + ) + component = super().create(*children, **props) if props.get("value") is not None and props.get("on_change") is not None: # create a debounced input if the user requests full control to avoid typing jank