Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added `rx.recharts.layer` and `rx.recharts.rectangle`, wrapping the Recharts `Layer` and `Rectangle` components used for constructing custom node elements.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@
"LabelList",
"cell",
"Cell",
"layer",
"Layer",
"rectangle",
"Rectangle",
],
"polar": [
"pie",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,9 +299,77 @@ class Cell(Recharts):
)


class Layer(Recharts):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Forward Layer SVG attributes instead of wrapperStyle

When users use Layer to build custom SVG nodes and pass common group attributes such as transform or style, those names are not declared on the wrapper, so Reflex treats them as style entries and this subclass then inherits Recharts._get_style, which serializes them as wrapperStyle. Recharts Layer expects normal SVG attributes on its <g> element, not wrapperStyle, so translated/styled custom node groups are silently rendered without those attributes.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, and accurate — an undeclared kwarg (or style=) folds into self.style, which Recharts._get_style emits as wrapperStyle, and recharts drops that on the bare <g>/<path>. Note this is the shared behavior of every recharts SVG-element wrapper (e.g. Cell), not something specific to these two, so I've kept it consistent here rather than diverging from the base _get_style convention in this PR.

For the custom-node use case the practical paths are:

  • declared propsx/y/width/height/fill/stroke/… all serialize correctly;
  • class_name — merged onto the <g>/recharts-layer group;
  • custom_attrs={"transform": "translate(…)"} — raw SVG attributes pass straight through to the element.

Forwarding style to the SVG element for the whole recharts package (or just these primitives) is a reasonable follow-up, but it's a convention change I'd rather make deliberately across the package than one-off here.


Generated by Claude Code

"""A Layer component in Recharts. Renders an SVG <g> element that groups
other SVG elements, e.g. when constructing custom node elements.
"""

tag = "Layer"

alias = "RechartsLayer"


class Rectangle(Recharts):
"""A Rectangle shape component in Recharts, e.g. used as a building block
for custom node elements.
"""

tag = "Rectangle"

alias = "RechartsRectangle"

x: Var[int | float] = field(
doc="The x-coordinate of the top left corner of the rectangle. Default: 0"
)

y: Var[int | float] = field(
doc="The y-coordinate of the top left corner of the rectangle. Default: 0"
)

width: Var[int | float] = field(doc="The width of the rectangle. Default: 0")

height: Var[int | float] = field(doc="The height of the rectangle. Default: 0")

radius: Var[int | float | Sequence[int | float]] = field(
doc="The radius of the rectangle's corners. When a number, sets all four corners; when a sequence of four numbers, sets the radii of the top-left, top-right, bottom-right and bottom-left corners. Default: 0"
)

fill: Var[str | Color] = field(doc="The fill color of the rectangle.")

fill_opacity: Var[float] = field(doc="The opacity of the rectangle fill.")

stroke: Var[str | Color] = field(doc="The stroke color of the rectangle.")

stroke_width: Var[str | int | float] = field(
doc="The width of the rectangle stroke."
)

is_animation_active: Var[bool] = field(
doc="If set false, animation of the rectangle will be disabled. Default: False"
)
Comment on lines +347 to +349

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Animation Default Is Misstated

When is_animation_active is omitted, this wrapper does not emit isAnimationActive, so Recharts applies its own runtime default. The generated API docs currently say the default is False, which can lead callers to leave the prop unset and still see rectangle animations.

Suggested change
is_animation_active: Var[bool] = field(
doc="If set false, animation of the rectangle will be disabled. Default: False"
)
is_animation_active: Var[bool] = field(
doc="If set false, animation of the rectangle will be disabled."
)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping the Default: False here — it's accurate. Unlike Bar/Area/Line (whose isAnimationActive defaults to true), the Rectangle shape defaults it to false in recharts 3.8.1:

// src/shape/Rectangle.tsx
export const defaultRectangleProps = {
  ...
  isAnimationActive: false,
  isUpdateAnimationActive: false,
  ...
} as const satisfies Partial<Props>;

So when the prop is omitted, recharts applies false (no animation), which is exactly what the docstring states. The other animation defaults (is_update_animation_active: False, animation_begin: 0, animation_duration: 1500, animation_easing: "ease") come from the same object and are documented to match.


Generated by Claude Code


is_update_animation_active: Var[bool] = field(
doc="If set false, the animation of the rectangle when its coordinates or size update will be disabled. Default: False"
)

animation_begin: Var[int] = field(
doc="Specifies when the animation should begin, the unit of this option is ms. Default: 0"
)

animation_duration: Var[int] = field(
doc="Specifies the duration of animation, the unit of this option is ms. Default: 1500"
)

animation_easing: Var[LiteralAnimationEasing] = field(
doc='The type of easing function. Default: "ease"'
)


responsive_container = ResponsiveContainer.create
legend = Legend.create
graphing_tooltip = tooltip = GraphingTooltip.create
label = Label.create
label_list = LabelList.create
cell = Cell.create
layer = Layer.create
rectangle = Rectangle.create
4 changes: 2 additions & 2 deletions pyi_hashes.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@
"packages/reflex-components-react-player/src/reflex_components_react_player/audio.pyi": "39e4144cef066bbff8c27b36a205a54b",
"packages/reflex-components-react-player/src/reflex_components_react_player/react_player.pyi": "86fc106181638c6a0a2a199332be817f",
"packages/reflex-components-react-player/src/reflex_components_react_player/video.pyi": "2682dc6e825d25307d8390d01e2bd653",
"packages/reflex-components-recharts/src/reflex_components_recharts/__init__.pyi": "359e123d9a046557ce05a96ce10313f5",
"packages/reflex-components-recharts/src/reflex_components_recharts/__init__.pyi": "8a8c59c2751ba91455d4b75c00940ae1",
"packages/reflex-components-recharts/src/reflex_components_recharts/cartesian.pyi": "3485aaabbfd3ca89908ae19425c7297e",
"packages/reflex-components-recharts/src/reflex_components_recharts/charts.pyi": "280a7cd51298ee676f3d076104133f44",
"packages/reflex-components-recharts/src/reflex_components_recharts/general.pyi": "f5e3491c4e1f69ba89085682888888a9",
"packages/reflex-components-recharts/src/reflex_components_recharts/general.pyi": "9485d89e4612fddd1e9b42c7c82327e8",
"packages/reflex-components-recharts/src/reflex_components_recharts/polar.pyi": "99ebcfc07868061bdc3c2010d85a153f",
"packages/reflex-components-recharts/src/reflex_components_recharts/recharts.pyi": "4f6c26f8c76543cc41e2b9dc400ece8a",
"packages/reflex-components-sonner/src/reflex_components_sonner/toast.pyi": "58521fcd1b514804f534d97624e82c9a",
Expand Down
43 changes: 43 additions & 0 deletions tests/units/components/recharts/test_general.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from reflex_components_recharts import Layer, Rectangle


def test_layer():
layer = Layer.create().render()
assert layer["name"] == "RechartsLayer"


def test_layer_with_children():
layer = Layer.create(Rectangle.create()).render()
assert layer["name"] == "RechartsLayer"
assert layer["children"][0]["name"] == "RechartsRectangle"


def test_rectangle():
rectangle = Rectangle.create().render()
assert rectangle["name"] == "RechartsRectangle"


def test_rectangle_props():
rectangle = Rectangle.create(
x=10,
y=20.5,
width=100,
height=50,
radius=[4, 4, 0, 0],
fill="#5192ca",
fill_opacity=0.8,
stroke="none",
stroke_width=2,
is_animation_active=False,
).render()
props = rectangle["props"]
assert "x:10" in props
assert "y:20.5" in props
assert "width:100" in props
assert "height:50" in props
assert "radius:[4, 4, 0, 0]" in props
assert 'fill:"#5192ca"' in props
assert "fillOpacity:0.8" in props
assert 'stroke:"none"' in props
assert "strokeWidth:2" in props
assert "isAnimationActive:false" in props
Loading