Преглед на файлове

[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
Elijah Ahianyo преди 5 месеца
родител
ревизия
7ca50c62e2
променени са 3 файла, в които са добавени 45 реда и са изтрити 2 реда
  1. 28 0
      reflex/components/el/elements/forms.py
  2. 2 2
      reflex/components/el/elements/forms.pyi
  3. 15 0
      reflex/components/radix/themes/components/text_field.py

+ 28 - 0
reflex/components/el/elements/forms.py

@@ -18,6 +18,7 @@ from reflex.event import (
     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."""

+ 2 - 2
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.

+ 15 - 0
reflex/components/radix/themes/components/text_field.py

@@ -9,7 +9,9 @@ from reflex.components.core.breakpoints import Responsive
 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 @@ class TextFieldRoot(elements.Div, RadixThemesComponent):
         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