[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
This commit is contained in:
Masen Furer 2024-05-08 14:39:22 -07:00 committed by GitHub
parent 7fee5d9e8d
commit 6fb254ae3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 94 additions and 4 deletions

View File

@ -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]:

View File

@ -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)

View File

@ -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