Clean up tags.

This commit is contained in:
Nikhil Rao 2022-11-18 13:04:16 -08:00
parent b1c10d3ada
commit 2008417bd7
6 changed files with 35 additions and 34 deletions

View File

@ -15,7 +15,7 @@ class Link(Component):
rel: Var[str] rel: Var[str]
def _render(self) -> Tag: def _render(self) -> Tag:
return Tag(name="link").add_attrs( return Tag(name="link").add_props(
href=self.href, href=self.href,
rel=self.rel, rel=self.rel,
) )

View File

@ -30,7 +30,7 @@ class Component(Base, ABC):
# The style of the component. # The style of the component.
style: Style = Style() style: Style = Style()
# A mapping of event chains to event triggers. # A mapping from event triggers to event chains.
event_triggers: Dict[str, EventChain] = {} event_triggers: Dict[str, EventChain] = {}
# The library that the component is based on. # The library that the component is based on.
@ -114,10 +114,9 @@ class Component(Base, ABC):
del kwargs[key] del kwargs[key]
# Add style props to the component. # Add style props to the component.
style = kwargs["style"] if "style" in kwargs else {}
kwargs["style"] = Style( kwargs["style"] = Style(
{ {
**style, **kwargs.get("style", {}),
**{attr: value for attr, value in kwargs.items() if attr not in fields}, **{attr: value for attr, value in kwargs.items() if attr not in fields},
} }
) )
@ -220,14 +219,17 @@ class Component(Base, ABC):
Returns: Returns:
The tag to render. The tag to render.
""" """
tag = Tag(name=self.tag).add_attrs( # Create the base tag.
**{attr: getattr(self, attr) for attr in self.get_props()} tag = Tag(name=self.tag)
)
# Add component props to the tag.
props = {attr: getattr(self, attr) for attr in self.get_props()}
# Special case for props named `type_`. # Special case for props named `type_`.
if hasattr(self, "type_"): if hasattr(self, "type_"):
tag.add_attrs(type=getattr(self, "type_")) props["type"] = getattr(self, "type_")
return tag
return tag.add_props(**props)
@classmethod @classmethod
def get_props(cls) -> Set[str]: def get_props(cls) -> Set[str]:
@ -297,7 +299,7 @@ class Component(Base, ABC):
""" """
tag = self._render() tag = self._render()
return str( return str(
tag.add_attrs(**self.event_triggers, key=self.key, sx=self.style).set( tag.add_props(**self.event_triggers, key=self.key, sx=self.style).set(
contents=utils.join( contents=utils.join(
[str(tag.contents)] + [child.render() for child in self.children] [str(tag.contents)] + [child.render() for child in self.children]
), ),

View File

@ -17,7 +17,7 @@ class Box(ChakraComponent):
return ( return (
super() super()
._render() ._render()
.add_attrs( .add_props(
**{ **{
"as": self.element, "as": self.element,
} }

View File

@ -7,7 +7,6 @@ import os
import re import re
from typing import Any, Dict, Optional, Union from typing import Any, Dict, Optional, Union
import pydantic
from plotly.graph_objects import Figure from plotly.graph_objects import Figure
from plotly.io import to_json from plotly.io import to_json
@ -23,8 +22,8 @@ class Tag(Base):
# The name of the tag. # The name of the tag.
name: str = "" name: str = ""
# The attributes of the tag. # The props of the tag.
attrs: Dict[str, Any] = {} props: Dict[str, Any] = {}
# The inner contents of the tag. # The inner contents of the tag.
contents: str = "" contents: str = ""
@ -36,10 +35,10 @@ class Tag(Base):
*args: Args to initialize the tag. *args: Args to initialize the tag.
**kwargs: Kwargs to initialize the tag. **kwargs: Kwargs to initialize the tag.
""" """
# Convert any attrs to properties. # Convert any props to vars.
if "attrs" in kwargs: if "props" in kwargs:
kwargs["attrs"] = { kwargs["props"] = {
name: Var.create(value) for name, value in kwargs["attrs"].items() name: Var.create(value) for name, value in kwargs["props"].items()
} }
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -109,21 +108,21 @@ class Tag(Base):
assert isinstance(value, str), "The value must be a string." assert isinstance(value, str), "The value must be a string."
return utils.wrap(value, "{", check_first=False) return utils.wrap(value, "{", check_first=False)
def format_attrs(self) -> str: def format_props(self) -> str:
"""Format a dictionary of attributes. """Format a dictionary of attributes.
Returns: Returns:
The formatted attributes. The formatted attributes.
""" """
# If there are no attributes, return an empty string. # If there are no attributes, return an empty string.
if len(self.attrs) == 0: if len(self.props) == 0:
return "" return ""
# Get the string representation of all the attributes joined. # Get the string representation of all the attributes joined.
# We need a space at the beginning for formatting. # We need a space at the beginning for formatting.
return os.linesep.join( return os.linesep.join(
f"{name}={self.format_attr_value(value)}" f"{name}={self.format_attr_value(value)}"
for name, value in self.attrs.items() for name, value in self.props.items()
if value is not None if value is not None
) )
@ -134,22 +133,22 @@ class Tag(Base):
The React code to render the tag. The React code to render the tag.
""" """
# Get the tag attributes. # Get the tag attributes.
attrs_str = self.format_attrs() props_str = self.format_props()
if len(attrs_str) > 0: if len(props_str) > 0:
attrs_str = " " + attrs_str props_str = " " + props_str
if len(self.contents) == 0: if len(self.contents) == 0:
# If there is no inner content, we don't need a closing tag. # If there is no inner content, we don't need a closing tag.
tag_str = utils.wrap(f"{self.name}{attrs_str}/", "<") tag_str = utils.wrap(f"{self.name}{props_str}/", "<")
else: else:
# Otherwise wrap it in opening and closing tags. # Otherwise wrap it in opening and closing tags.
open = utils.wrap(f"{self.name}{attrs_str}", "<") open = utils.wrap(f"{self.name}{props_str}", "<")
close = utils.wrap(f"/{self.name}", "<") close = utils.wrap(f"/{self.name}", "<")
tag_str = utils.wrap(self.contents, open, close) tag_str = utils.wrap(self.contents, open, close)
return tag_str return tag_str
def add_attrs(self, **kwargs: Optional[Any]) -> Tag: def add_props(self, **kwargs: Optional[Any]) -> Tag:
"""Add attributes to the tag. """Add attributes to the tag.
Args: Args:
@ -158,7 +157,7 @@ class Tag(Base):
Returns: Returns:
The tag with the attributes added. The tag with the attributes added.
""" """
self.attrs.update( self.props.update(
{ {
utils.to_camel_case(name): attr utils.to_camel_case(name): attr
if utils._isinstance(attr, Union[EventChain, dict]) if utils._isinstance(attr, Union[EventChain, dict])
@ -169,7 +168,7 @@ class Tag(Base):
) )
return self return self
def remove_attrs(self, *args: str) -> Tag: def remove_props(self, *args: str) -> Tag:
"""Remove attributes from the tag. """Remove attributes from the tag.
Args: Args:
@ -179,8 +178,8 @@ class Tag(Base):
The tag with the attributes removed. The tag with the attributes removed.
""" """
for name in args: for name in args:
if name in self.attrs: if name in self.props:
del self.attrs[name] del self.props[name]
return self return self
@staticmethod @staticmethod

View File

@ -28,7 +28,7 @@ class Markdown(Component):
def _render(self): def _render(self):
tag = super()._render() tag = super()._render()
return tag.add_attrs( return tag.add_props(
children=utils.wrap(str(self.src).strip(), "`"), children=utils.wrap(str(self.src).strip(), "`"),
components={ components={
"h1": "{({node, ...props}) => <Heading size='2xl' {...props} />}", "h1": "{({node, ...props}) => <Heading size='2xl' {...props} />}",

View File

@ -111,9 +111,9 @@ def test_is_valid_attr(attr: Var, valid: bool):
assert Tag.is_valid_attr(attr) == valid assert Tag.is_valid_attr(attr) == valid
def test_add_attrs(): def test_add_props():
"""Test that the attributes are added.""" """Test that the attributes are added."""
tag = Tag().add_attrs(key="value", key2=42, invalid=None, invalid2={}) tag = Tag().add_props(key="value", key2=42, invalid=None, invalid2={})
assert tag.attrs["key"] == Var.create("value") assert tag.attrs["key"] == Var.create("value")
assert tag.attrs["key2"] == Var.create(42) assert tag.attrs["key2"] == Var.create(42)
assert "invalid" not in tag.attrs assert "invalid" not in tag.attrs