Tabs validate parent is proper tab container (#2463)
This commit is contained in:
parent
3ff88390c2
commit
209c5fab7b
@ -90,20 +90,28 @@ class Tab(ChakraComponent):
|
|||||||
# The id of the panel.
|
# The id of the panel.
|
||||||
panel_id: Var[str]
|
panel_id: Var[str]
|
||||||
|
|
||||||
|
_valid_parents: List[str] = ["TabList"]
|
||||||
|
|
||||||
|
|
||||||
class TabList(ChakraComponent):
|
class TabList(ChakraComponent):
|
||||||
"""Wrapper for the Tab components."""
|
"""Wrapper for the Tab components."""
|
||||||
|
|
||||||
tag = "TabList"
|
tag = "TabList"
|
||||||
|
|
||||||
|
_valid_parents: List[str] = ["Tabs"]
|
||||||
|
|
||||||
|
|
||||||
class TabPanels(ChakraComponent):
|
class TabPanels(ChakraComponent):
|
||||||
"""Wrapper for the Tab components."""
|
"""Wrapper for the Tab components."""
|
||||||
|
|
||||||
tag = "TabPanels"
|
tag = "TabPanels"
|
||||||
|
|
||||||
|
_valid_parents: List[str] = ["Tabs"]
|
||||||
|
|
||||||
|
|
||||||
class TabPanel(ChakraComponent):
|
class TabPanel(ChakraComponent):
|
||||||
"""An element that contains the content associated with a tab."""
|
"""An element that contains the content associated with a tab."""
|
||||||
|
|
||||||
tag = "TabPanel"
|
tag = "TabPanel"
|
||||||
|
|
||||||
|
_valid_parents: List[str] = ["TabPanels"]
|
||||||
|
@ -155,6 +155,9 @@ class Component(BaseComponent, ABC):
|
|||||||
# only components that are allowed as children
|
# only components that are allowed as children
|
||||||
_valid_children: List[str] = []
|
_valid_children: List[str] = []
|
||||||
|
|
||||||
|
# only components that are allowed as parent
|
||||||
|
_valid_parents: List[str] = []
|
||||||
|
|
||||||
# custom attribute
|
# custom attribute
|
||||||
custom_attrs: Dict[str, Union[Var, str]] = {}
|
custom_attrs: Dict[str, Union[Var, str]] = {}
|
||||||
|
|
||||||
@ -651,7 +654,8 @@ class Component(BaseComponent, ABC):
|
|||||||
children: The children of the component.
|
children: The children of the component.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not self._invalid_children and not self._valid_children:
|
skip_parentable = all(child._valid_parents == [] for child in children)
|
||||||
|
if not self._invalid_children and not self._valid_children and skip_parentable:
|
||||||
return
|
return
|
||||||
|
|
||||||
comp_name = type(self).__name__
|
comp_name = type(self).__name__
|
||||||
@ -671,6 +675,15 @@ class Component(BaseComponent, ABC):
|
|||||||
f"The component `{comp_name}` only allows the components: {valid_child_list} as children. Got `{child_name}` instead."
|
f"The component `{comp_name}` only allows the components: {valid_child_list} as children. Got `{child_name}` instead."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def validate_vaild_parent(child_name, valid_parents):
|
||||||
|
if comp_name not in valid_parents:
|
||||||
|
valid_parent_list = ", ".join(
|
||||||
|
[f"`{v_parent}`" for v_parent in valid_parents]
|
||||||
|
)
|
||||||
|
raise ValueError(
|
||||||
|
f"The component `{child_name}` can only be a child of the components: {valid_parent_list}. Got `{comp_name}` instead."
|
||||||
|
)
|
||||||
|
|
||||||
for child in children:
|
for child in children:
|
||||||
name = type(child).__name__
|
name = type(child).__name__
|
||||||
|
|
||||||
@ -680,6 +693,9 @@ class Component(BaseComponent, ABC):
|
|||||||
if self._valid_children:
|
if self._valid_children:
|
||||||
validate_valid_child(name)
|
validate_valid_child(name)
|
||||||
|
|
||||||
|
if child._valid_parents:
|
||||||
|
validate_vaild_parent(name, child._valid_parents)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_vars_from_event_triggers(
|
def _get_vars_from_event_triggers(
|
||||||
event_triggers: dict[str, EventChain | Var],
|
event_triggers: dict[str, EventChain | Var],
|
||||||
|
@ -55,6 +55,7 @@ EXCLUDED_PROPS = [
|
|||||||
"_invalid_children",
|
"_invalid_children",
|
||||||
"_memoization_mode",
|
"_memoization_mode",
|
||||||
"_valid_children",
|
"_valid_children",
|
||||||
|
"_valid_parents",
|
||||||
]
|
]
|
||||||
|
|
||||||
DEFAULT_TYPING_IMPORTS = {
|
DEFAULT_TYPING_IMPORTS = {
|
||||||
|
@ -137,6 +137,8 @@ def component5() -> Type[Component]:
|
|||||||
|
|
||||||
_valid_children: List[str] = ["Text"]
|
_valid_children: List[str] = ["Text"]
|
||||||
|
|
||||||
|
_valid_parents: List[str] = ["Text"]
|
||||||
|
|
||||||
return TestComponent5
|
return TestComponent5
|
||||||
|
|
||||||
|
|
||||||
@ -569,6 +571,20 @@ def test_unsupported_child_components(fixture, request):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_unsupported_parent_components(component5):
|
||||||
|
"""Test that a value error is raised when an component is not in _valid_parents of one of its children.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
component5: component with valid parent of "Text" only
|
||||||
|
"""
|
||||||
|
with pytest.raises(ValueError) as err:
|
||||||
|
rx.Box(children=[component5.create()])
|
||||||
|
assert (
|
||||||
|
err.value.args[0]
|
||||||
|
== f"The component `{component5.__name__}` can only be a child of the components: `{component5._valid_parents[0]}`. Got `Box` instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("fixture", ["component5", "component7"])
|
@pytest.mark.parametrize("fixture", ["component5", "component7"])
|
||||||
def test_component_with_only_valid_children(fixture, request):
|
def test_component_with_only_valid_children(fixture, request):
|
||||||
"""Test that a value error is raised when an unsupported component (a child component not found in the
|
"""Test that a value error is raised when an unsupported component (a child component not found in the
|
||||||
|
Loading…
Reference in New Issue
Block a user