Quellcode durchsuchen

[REF-2789] Graceful deprecation of rx.input.root and rx.input.input (#3249)

* [REF-2789] Graceful deprecation of rx.input.root and rx.input.input

Handle previously valid code where rx.input.root wrapped
rx.input/rx.input.input and rx.input.slot.

Raise deprecation warnings with hints about how to refactor code.

Copy props from rx.input.root to children inputs and apply any rx.input.slot
components to children inputs in an attempt to keep existing code working as
best as possible.

Fix DebounceInput:
  * pass children through (for rx.input.slots)
  * pass _rename_props through (for color_scheme)

* Fix for case where `rx.input.root` had event triggers

Fix for case where `rx.input.root` had no input children
Masen Furer vor 1 Jahr
Ursprung
Commit
6fb254ae3d

+ 2 - 0
reflex/components/core/debounce.py

@@ -121,6 +121,8 @@ class DebounceInput(Component):
         component = super().create(**props)
         component._get_style = child._get_style
         component.event_triggers.update(child.event_triggers)
+        component.children = child.children
+        component._rename_props = child._rename_props
         return component
 
     def get_event_triggers(self) -> dict[str, Any]:

+ 83 - 3
reflex/components/radix/themes/components/text_field.py

@@ -1,11 +1,15 @@
 """Interactive components provided by @radix-ui/themes."""
+from __future__ import annotations
 
 from typing import Any, Dict, Literal, Union
 
 from reflex.components import el
+from reflex.components.base.fragment import Fragment
 from reflex.components.component import Component, ComponentNamespace
 from reflex.components.core.debounce import DebounceInput
 from reflex.constants import EventTriggers
+from reflex.style import Style, format_as_emotion
+from reflex.utils import console
 from reflex.vars import Var
 
 from ..base import (
@@ -79,10 +83,85 @@ class TextFieldRoot(el.Div, RadixThemesComponent):
         Returns:
             The component.
         """
+        component = super().create(*children, **props)
         if props.get("value") is not None and props.get("on_change"):
             # create a debounced input if the user requests full control to avoid typing jank
-            return DebounceInput.create(super().create(*children, **props))
-        return super().create(*children, **props)
+            return DebounceInput.create(component)
+        return component
+
+    @classmethod
+    def create_root_deprecated(cls, *children, **props) -> Component:
+        """Create a Fragment component (wrapper for deprecated name).
+
+        Copy the attributes that were previously defined on TextFieldRoot in 0.4.9 to
+        any child input elements (via custom_attrs).
+
+        Args:
+            *children: The children of the component.
+            **props: The properties of the component.
+
+        Returns:
+            The component.
+        """
+        console.deprecate(
+            feature_name="rx.input.root",
+            reason="use rx.input without the .root suffix",
+            deprecation_version="0.5.0",
+            removal_version="0.6.0",
+        )
+        inputs = [
+            child
+            for child in children
+            if isinstance(child, (TextFieldRoot, DebounceInput))
+        ]
+        if not inputs:
+            # Old-style where no explicit child input was provided
+            return cls.create(*children, **props)
+        slots = [child for child in children if isinstance(child, TextFieldSlot)]
+        carry_props = {
+            prop: props.pop(prop)
+            for prop in ["size", "variant", "color_scheme", "radius"]
+            if prop in props
+        }
+        template = cls.create(**props)
+        for child in inputs:
+            child.children.extend(slots)
+            custom_attrs = child.custom_attrs
+            custom_attrs.update(
+                {
+                    prop: value
+                    for prop, value in carry_props.items()
+                    if prop not in custom_attrs and getattr(child, prop) is None
+                }
+            )
+            style = Style(template.style)
+            style.update(child.style)
+            child._get_style = lambda style=style: {
+                "css": Var.create(format_as_emotion(style))
+            }
+            for trigger in template.event_triggers:
+                if trigger not in child.event_triggers:
+                    child.event_triggers[trigger] = template.event_triggers[trigger]
+        return Fragment.create(*inputs)
+
+    @classmethod
+    def create_input_deprecated(cls, *children, **props) -> Component:
+        """Create a TextFieldRoot component (wrapper for deprecated name).
+
+        Args:
+            *children: The children of the component.
+            **props: The properties of the component.
+
+        Returns:
+            The component.
+        """
+        console.deprecate(
+            feature_name="rx.input.input",
+            reason="use rx.input without the .input suffix",
+            deprecation_version="0.5.0",
+            removal_version="0.6.0",
+        )
+        return cls.create(*children, **props)
 
     def get_event_triggers(self) -> Dict[str, Any]:
         """Get the event triggers that pass the component's value to the handler.
@@ -112,7 +191,8 @@ class TextFieldSlot(RadixThemesComponent):
 class TextField(ComponentNamespace):
     """TextField components namespace."""
 
-    root = staticmethod(TextFieldRoot.create)
+    root = staticmethod(TextFieldRoot.create_root_deprecated)
+    input = staticmethod(TextFieldRoot.create_input_deprecated)
     slot = staticmethod(TextFieldSlot.create)
     __call__ = staticmethod(TextFieldRoot.create)
 

+ 9 - 1
reflex/components/radix/themes/components/text_field.pyi

@@ -9,9 +9,12 @@ from reflex.event import EventChain, EventHandler, EventSpec
 from reflex.style import Style
 from typing import Any, Dict, Literal, Union
 from reflex.components import el
+from reflex.components.base.fragment import Fragment
 from reflex.components.component import Component, ComponentNamespace
 from reflex.components.core.debounce import DebounceInput
 from reflex.constants import EventTriggers
+from reflex.style import Style, format_as_emotion
+from reflex.utils import console
 from reflex.vars import Var
 from ..base import LiteralAccentColor, LiteralRadius, RadixThemesComponent
 
@@ -263,6 +266,10 @@ class TextFieldRoot(el.Div, RadixThemesComponent):
             The component.
         """
         ...
+    @classmethod
+    def create_root_deprecated(cls, *children, **props) -> Component: ...
+    @classmethod
+    def create_input_deprecated(cls, *children, **props) -> Component: ...
     def get_event_triggers(self) -> Dict[str, Any]: ...
 
 class TextFieldSlot(RadixThemesComponent):
@@ -408,7 +415,8 @@ class TextFieldSlot(RadixThemesComponent):
         ...
 
 class TextField(ComponentNamespace):
-    root = staticmethod(TextFieldRoot.create)
+    root = staticmethod(TextFieldRoot.create_root_deprecated)
+    input = staticmethod(TextFieldRoot.create_input_deprecated)
     slot = staticmethod(TextFieldSlot.create)
 
     @staticmethod