Support aria and data props

This commit is contained in:
Masen Furer 2024-10-10 09:25:14 -07:00
parent 87648af3ee
commit 2adf7fd2a2
No known key found for this signature in database
GPG Key ID: B0008AD22B3B3A95
3 changed files with 70 additions and 3 deletions

View File

@ -1,4 +1,4 @@
"""Base component definitions."""
"," "Base component definitions." ""
from __future__ import annotations
@ -36,6 +36,7 @@ from reflex.constants import (
MemoizationMode,
PageNames,
)
from reflex.constants.compiler import SpecialAttributes
from reflex.event import (
EventChain,
EventChainVar,
@ -474,6 +475,15 @@ class Component(BaseComponent, ABC):
for key in kwargs["event_triggers"]:
del kwargs[key]
# Place data_ and aria_ attributes into custom_attrs
special_attributes = tuple(
key for key in kwargs if SpecialAttributes.is_special(key)
)
if special_attributes:
custom_attrs = kwargs.setdefault("custom_attrs", {})
for key in special_attributes:
custom_attrs[format.to_kebab_case(key)] = kwargs.pop(key)
# Add style props to the component.
style = kwargs.get("style", {})
if isinstance(style, List):
@ -493,8 +503,6 @@ class Component(BaseComponent, ABC):
**{attr: value for attr, value in kwargs.items() if attr not in fields},
}
)
if "custom_attrs" not in kwargs:
kwargs["custom_attrs"] = {}
# Convert class_name to str if it's list
class_name = kwargs.get("class_name", "")

View File

@ -160,3 +160,29 @@ class MemoizationMode(Base):
# Whether children of this component should be memoized first.
recursive: bool = True
class SpecialAttributes(enum.Enum):
"""Special attributes for components.
These are placed in custom_attrs and rendered as-is rather than converting
to a style prop.
"""
DATA = "data"
ARIA = "aria"
@classmethod
def is_special(cls, attr: str) -> bool:
"""Check if the attribute is special.
Args:
attr: the attribute to check
Returns:
True if the attribute is special.
"""
for value in cls:
if attr.startswith(f"{value.value}-") or attr.startswith(f"{value.value}_"):
return True
return False

View File

@ -2215,3 +2215,36 @@ class TriggerState(rx.State):
)
def test_has_state_event_triggers(component, output):
assert component._has_stateful_event_triggers() == output
@pytest.mark.parametrize(
("component_kwargs", "exp_custom_attrs", "exp_style"),
[
(
{"data_test": "test", "aria_test": "test"},
{"data-test": "test", "aria-test": "test"},
{},
),
(
{"data-test": "test", "aria-test": "test"},
{"data-test": "test", "aria-test": "test"},
{},
),
(
{"custom_attrs": {"data-existing": "test"}, "data_new": "test"},
{"data-existing": "test", "data-new": "test"},
{},
),
],
)
def test_special_props(component_kwargs, exp_custom_attrs, exp_style):
"""Test that data_ and aria_ special props are correctly added to the component.
Args:
component_kwargs: The component kwargs.
exp_custom_attrs: The expected custom attributes.
exp_style: The expected style.
"""
component = rx.box(**component_kwargs)
assert component.custom_attrs == exp_custom_attrs
assert component.style == exp_style