Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion reflex/components/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,6 @@ def render(self) -> dict:
tag.set(
children=[child.render() for child in self.children],
contents=str(tag.contents),
props=tag.format_props(),
)
)
self._replace_prop_names(rendered_dict)
Expand Down
4 changes: 1 addition & 3 deletions reflex/components/core/clipboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,8 @@ def _exclude_props(self) -> list[str]:

def _render(self) -> Tag:
tag = super()._render()
tag.remove_props("targets")
# Ensure a different Fragment component is created whenever targets differ
tag.add_props(key=self.targets)
return tag
return tag.remove_props("targets").add_props(key=self.targets)

def add_imports(self) -> dict[str, ImportVar]:
"""Add the imports for the Clipboard component.
Expand Down
2 changes: 0 additions & 2 deletions reflex/components/core/cond.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,6 @@ def render(self) -> dict:
sx=self.style,
id=self.id,
class_name=self.class_name,
).set(
props=tag.format_props(),
),
cond_state=str(self.cond),
)
Expand Down
3 changes: 1 addition & 2 deletions reflex/components/core/match.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,7 @@ def render(self) -> dict:
The dictionary for template of component.
"""
tag = self._render()
tag.name = "match"
return dict(tag)
return dict(tag.set(name="match"))

def add_imports(self) -> ImportDict:
"""Add imports for the Match component.
Expand Down
10 changes: 6 additions & 4 deletions reflex/components/datadisplay/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,12 +500,14 @@ def _render(self):

theme = self.theme

out.add_props(style=theme).remove_props("theme", "code").add_props(
children=self.code,
return (
out.add_props(style=theme)
.remove_props("theme", "code")
.add_props(
children=self.code,
)
)

return out


class CodeblockNamespace(ComponentNamespace):
"""Namespace for the CodeBlock component."""
Expand Down
2 changes: 1 addition & 1 deletion reflex/components/el/elements/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def add_hooks(self) -> list[str]:
def _render(self) -> Tag:
render_tag = super()._render()
if EventTriggers.ON_SUBMIT in self.event_triggers:
render_tag.add_props(
render_tag = render_tag.add_props(
**{
EventTriggers.ON_SUBMIT: Var(
_js_expr=f"handleSubmit_{self.handle_submit_unique_name}",
Expand Down
24 changes: 16 additions & 8 deletions reflex/components/plotly/plotly.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,16 +245,24 @@ def _render(self):
template_dict = LiteralVar.create({"layout": {"template": self.template}})
merge_dicts.append(template_dict._without_data())
if merge_dicts:
tag.special_props.append(
# Merge all dictionaries and spread the result over props.
Var(
_js_expr=f"{{...mergician({figure!s},"
f"{','.join(str(md) for md in merge_dicts)})}}",
),
tag = tag.set(
special_props=[
*tag.special_props,
# Merge all dictionaries and spread the result over props.
Var(
_js_expr=f"{{...mergician({figure!s},"
f"{','.join(str(md) for md in merge_dicts)})}}",
),
]
)
else:
# Spread the figure dict over props, nothing to merge.
tag.special_props.append(Var(_js_expr=f"{figure!s}"))
tag = tag.set(
special_props=[
*tag.special_props,
# Spread the figure dict over props, nothing to merge.
Var(_js_expr=str(figure)),
]
)
return tag


Expand Down
6 changes: 2 additions & 4 deletions reflex/components/radix/themes/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,11 @@ def add_imports(self) -> ImportDict | list[ImportDict]:

def _render(self, props: dict[str, Any] | None = None) -> Tag:
tag = super()._render(props)
tag.add_props(
return tag.add_props(
css=Var(
_js_expr="{...theme.styles.global[':root'], ...theme.styles.global.body}"
),
)
tag.remove_props("appearance")
return tag
).remove_props("appearance")


class ThemePanel(RadixThemesComponent):
Expand Down
7 changes: 4 additions & 3 deletions reflex/components/tags/cond_tag.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
"""Tag to conditionally render components."""

import dataclasses
from collections.abc import Mapping
from typing import Any

from reflex.components.tags.tag import Tag
from reflex.vars.base import Var


@dataclasses.dataclass()
@dataclasses.dataclass(frozen=True)
class CondTag(Tag):
"""A conditional tag."""

# The condition to determine which component to render.
cond: Var[Any] = dataclasses.field(default_factory=lambda: Var.create(True))

# The code to render if the condition is true.
true_value: dict = dataclasses.field(default_factory=dict)
true_value: Mapping = dataclasses.field(default_factory=dict)

# The code to render if the condition is false.
false_value: dict | None = None
false_value: Mapping | None = None
2 changes: 1 addition & 1 deletion reflex/components/tags/iter_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from reflex.components.component import Component


@dataclasses.dataclass()
@dataclasses.dataclass(frozen=True)
class IterTag(Tag):
"""An iterator tag."""

Expand Down
5 changes: 3 additions & 2 deletions reflex/components/tags/match_tag.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
"""Tag to conditionally match cases."""

import dataclasses
from collections.abc import Sequence
from typing import Any

from reflex.components.tags.tag import Tag
from reflex.vars.base import Var


@dataclasses.dataclass()
@dataclasses.dataclass(frozen=True)
class MatchTag(Tag):
"""A match tag."""

# The condition to determine which case to match.
cond: Var[Any] = dataclasses.field(default_factory=lambda: Var.create(True))

# The list of match cases to be matched.
match_cases: list[Any] = dataclasses.field(default_factory=list)
match_cases: Sequence[Any] = dataclasses.field(default_factory=list)

# The catchall case to match.
default: Any = dataclasses.field(default=Var.create(None))
79 changes: 39 additions & 40 deletions reflex/components/tags/tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,32 +31,24 @@ def render_prop(value: Any) -> Any:
return value


@dataclasses.dataclass()
@dataclasses.dataclass(frozen=True)
class Tag:
"""A React tag."""

# The name of the tag.
name: str = ""

# The props of the tag.
props: dict[str, Any] = dataclasses.field(default_factory=dict)
props: Mapping[str, Any] = dataclasses.field(default_factory=dict)

# The inner contents of the tag.
contents: str = ""

# Special props that aren't key value pairs.
special_props: list[Var] = dataclasses.field(default_factory=list)
special_props: Sequence[Var] = dataclasses.field(default_factory=list)

# The children components.
children: list[Any] = dataclasses.field(default_factory=list)

def __post_init__(self):
"""Post initialize the tag."""
object.__setattr__(
self,
"props",
{name: LiteralVar.create(value) for name, value in self.props.items()},
)
children: Sequence[Any] = dataclasses.field(default_factory=list)

def format_props(self) -> list:
"""Format the tag's props.
Expand All @@ -67,18 +59,15 @@ def format_props(self) -> list:
return format.format_props(*self.special_props, **self.props)

def set(self, **kwargs: Any):
"""Set the tag's fields.
"""Return a new tag with the given fields set.

Args:
**kwargs: The fields to set.

Returns:
The tag with the fields
The tag with the fields set.
"""
for name, value in kwargs.items():
setattr(self, name, value)

return self
return dataclasses.replace(self, **kwargs)

def __iter__(self):
"""Iterate over the tag's fields.
Expand All @@ -87,46 +76,56 @@ def __iter__(self):
tuple[str, Any]: The field name and value.
"""
for field in dataclasses.fields(self):
rendered_value = render_prop(getattr(self, field.name))
if rendered_value is not None:
yield field.name, rendered_value
if field.name == "props":
yield "props", self.format_props()
elif field.name != "special_props":
rendered_value = render_prop(getattr(self, field.name))
if rendered_value is not None:
yield field.name, rendered_value

def add_props(self, **kwargs: Any | None) -> Tag:
"""Add props to the tag.
"""Return a new tag with the given props added.

Args:
**kwargs: The props to add.

Returns:
The tag with the props added.
"""
self.props.update(
{
format.to_camel_case(name, treat_hyphens_as_underscores=False): (
prop
if isinstance(prop, (EventChain, Mapping))
else LiteralVar.create(prop)
)
for name, prop in kwargs.items()
if self.is_valid_prop(prop)
}
return dataclasses.replace(
self,
props={
**self.props,
**{
format.to_camel_case(name, treat_hyphens_as_underscores=False): (
prop
if isinstance(prop, (EventChain, Mapping))
else LiteralVar.create(prop)
)
for name, prop in kwargs.items()
if self.is_valid_prop(prop)
},
},
)
return self

def remove_props(self, *args: str) -> Tag:
"""Remove props from the tag.
"""Return a new tag with the given props removed.

Args:
*args: The props to remove.
*args: The names of the props to remove.

Returns:
The tag with the props removed.
"""
for name in args:
prop_name = format.to_camel_case(name)
if prop_name in self.props:
del self.props[prop_name]
return self
formatted_args = [format.to_camel_case(arg) for arg in args]
return dataclasses.replace(
self,
props={
name: value
for name, value in self.props.items()
if name not in formatted_args
},
)

@staticmethod
def is_valid_prop(prop: Var | None) -> bool:
Expand Down
Loading