Skip to content

Commit eb52edb

Browse files
authored
components as props (#2124)
1 parent 4c97b4c commit eb52edb

File tree

2 files changed

+69
-9
lines changed

2 files changed

+69
-9
lines changed

reflex/components/component.py

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
)
2121
from reflex.style import Style
2222
from reflex.utils import console, format, imports, types
23+
from reflex.utils.serializers import serializer
2324
from reflex.vars import BaseVar, ImportVar, Var
2425

2526

@@ -400,6 +401,20 @@ def get_initial_props(cls) -> Set[str]:
400401
"""
401402
return set()
402403

404+
@classmethod
405+
def get_component_props(cls) -> set[str]:
406+
"""Get the props that expected a component as value.
407+
408+
Returns:
409+
The components props.
410+
"""
411+
return {
412+
name
413+
for name, field in cls.get_fields().items()
414+
if name in cls.get_props()
415+
and types._issubclass(field.outer_type_, Component)
416+
}
417+
403418
@classmethod
404419
def create(cls, *children, **props) -> Component:
405420
"""Create the component.
@@ -596,19 +611,48 @@ def get_dynamic_imports(self) -> Set[str]:
596611
# Return the dynamic imports
597612
return dynamic_imports
598613

599-
def _get_dependencies_imports(self):
600-
return {
601-
dep: {ImportVar(tag=None, render=False)} for dep in self.lib_dependencies
602-
}
614+
def _get_props_imports(self) -> imports.ImportDict:
615+
"""Get the imports needed for components props.
616+
617+
Returns:
618+
The imports for the components props of the component.
619+
"""
620+
return imports.merge_imports(
621+
*[
622+
getattr(self, prop).get_imports()
623+
for prop in self.get_component_props()
624+
if getattr(self, prop) is not None
625+
]
626+
)
627+
628+
def _get_dependencies_imports(self) -> imports.ImportDict:
629+
"""Get the imports from lib_dependencies for installing.
630+
631+
Returns:
632+
The dependencies imports of the component.
633+
"""
634+
return imports.merge_imports(
635+
{dep: {ImportVar(tag=None, render=False)} for dep in self.lib_dependencies}
636+
)
603637

604638
def _get_imports(self) -> imports.ImportDict:
605-
imports = {}
639+
"""Get all the libraries and fields that are used by the component.
640+
641+
Returns:
642+
The imports needed by the component.
643+
"""
644+
_imports = {}
606645
if self.library is not None and self.tag is not None:
607-
imports[self.library] = {self.import_var}
608-
return {**self._get_dependencies_imports(), **imports}
646+
_imports[self.library] = {self.import_var}
647+
648+
return imports.merge_imports(
649+
self._get_props_imports(),
650+
self._get_dependencies_imports(),
651+
_imports,
652+
)
609653

610654
def get_imports(self) -> imports.ImportDict:
611-
"""Get all the libraries and fields that are used by the component.
655+
"""Get all the libraries and fields that are used by the component and its children.
612656
613657
Returns:
614658
The import dict with the required imports.
@@ -988,3 +1032,16 @@ def _get_dynamic_imports(self) -> str:
9881032
else ""
9891033
)
9901034
return "".join((library_import, mod_import, opts_fragment))
1035+
1036+
1037+
@serializer
1038+
def serialize_component(comp: Component):
1039+
"""Serialize a component.
1040+
1041+
Args:
1042+
comp: The component to serialize.
1043+
1044+
Returns:
1045+
The serialized component.
1046+
"""
1047+
return str(comp)

reflex/components/forms/iconbutton.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
"""An icon button component."""
22

3+
from typing import Optional
4+
5+
from reflex.components.component import Component
36
from reflex.components.typography.text import Text
47
from reflex.vars import Var
58

@@ -16,7 +19,7 @@ class IconButton(Text):
1619
aria_label: Var[str]
1720

1821
# The icon to be used in the button.
19-
icon: Var[str]
22+
icon: Optional[Component]
2023

2124
# If true, the button will be styled in its active state.
2225
is_active: Var[bool]

0 commit comments

Comments
 (0)