Skip to content

[WEB-4855] refactor: bar chart improvements#7731

Closed
JayashTripathy wants to merge 3 commits intopreviewfrom
refactor-bar-chart
Closed

[WEB-4855] refactor: bar chart improvements#7731
JayashTripathy wants to merge 3 commits intopreviewfrom
refactor-bar-chart

Conversation

@JayashTripathy
Copy link
Member

@JayashTripathy JayashTripathy commented Sep 6, 2025

Description

This PR adds the following :-

  • Missing fill property in Bar config
  • Custom x- and y-axis tick support

Type of Change

  • Improvement (change that would cause existing functionality to not work as expected)

Summary by CodeRabbit

  • New Features
    • Added customTicks prop to Bar, Line, Area, and Scatter charts to allow custom X/Y axis tick components with safe fallbacks.
    • Introduced a default bar color used when a function-based fill is provided; also exposed as a reusable color token.
  • Refactor
    • Reorganized chart prop types into base and axis-focused groups; chart-specific props updated accordingly. No behavioral changes expected aside from the new customTicks support.

@makeplane
Copy link

makeplane bot commented Sep 6, 2025

Pull Request Linked with Plane Work Items

Comment Automatically Generated by Plane

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR enhances the bar chart component by adding support for custom axis ticks and fixing a missing fill property. The changes improve chart customization capabilities while ensuring proper default values.

  • Adds customTicks property to allow custom X and Y axis tick components
  • Implements proper fill property handling with fallback to default color

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/types/src/charts/index.ts Adds customTicks type definition to TBarChartProps interface
packages/propel/src/charts/bar-chart/root.tsx Implements custom tick support and adds fill property with default fallback

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

key={bar.key}
dataKey={bar.key}
stackId={bar.stackId}
fill={typeof bar.fill === "function" ? "#000000" : bar.fill}
Copy link

Copilot AI Sep 6, 2025

Choose a reason for hiding this comment

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

The hardcoded fallback color '#000000' should be extracted to a constant or use a theme-based default color to maintain consistency with the design system.

Copilot uses AI. Check for mistakes.
Comment on lines 73 to 76
customTicks?: {
x?: React.ComponentType<any>;
y?: React.ComponentType<any>;
};
Copy link

Copilot AI Sep 6, 2025

Choose a reason for hiding this comment

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

Using 'any' type weakens type safety. Consider defining a proper interface for tick component props or use a more specific type constraint.

Copilot uses AI. Check for mistakes.
@JayashTripathy JayashTripathy changed the title [WEB-4855] feat: bar chart improvements [WEB-4855] impovement: bar chart improvements Sep 6, 2025
@JayashTripathy JayashTripathy changed the title [WEB-4855] impovement: bar chart improvements [WEB-4855] improvement: bar chart improvements Sep 6, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 7, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Introduces optional customTicks prop to Area, Bar, Line, and Scatter charts to select axis tick components at render time. Refactors chart prop types: TChartProps renamed to TBaseChartProps, adds TAxisChartProps with customTicks and tickCount, and updates chart-specific prop types. Adds and uses DEFAULT_BAR_FILL_COLOR in bar chart rendering.

Changes

Cohort / File(s) Summary
Axis tick customization across charts
packages/propel/src/charts/area-chart/root.tsx, packages/propel/src/charts/line-chart/root.tsx, packages/propel/src/charts/scatter-chart/root.tsx, packages/propel/src/charts/bar-chart/root.tsx
Add optional prop customTicks?: { x?: React.ComponentType; y?: React.ComponentType }. XAxis/YAxis now render ticks using provided components; fallback to existing CustomXAxisTick/CustomYAxisTick. Backward compatible defaults.
Bar chart default color export and usage
packages/propel/src/charts/bar-chart/bar.tsx, packages/propel/src/charts/bar-chart/root.tsx
Add and export DEFAULT_BAR_FILL_COLOR = "#6B7280". Update CustomBar and CustomBarLollipop to use default color when fill is a function at render time; bar root wires the constant and applies fallback for function-based fills.
Types reorganization and API surface
packages/types/src/charts/index.ts
Rename TChartPropsTBaseChartProps. Introduce TAxisChartProps with xAxis, yAxis, tickCount, and customTicks. Update TBarChartProps, TLineChartProps, TScatterChartProps, TAreaChartProps to extend TAxisChartProps. Update TPieChartProps, TRadarChartProps to Pick from TBaseChartProps. Public types now expose customTicks.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant App as App
  participant Chart as Chart (Area/Bar/Line/Scatter)
  participant AxisX as XAxis
  participant AxisY as YAxis
  participant TickX as TickComponent (X)
  participant TickY as TickComponent (Y)

  App->>Chart: render({ customTicks, xAxis, yAxis, ... })
  Chart->>AxisX: render with tick = customTicks?.x || CustomXAxisTick
  AxisX->>TickX: render(props)
  Chart->>AxisY: render with tick = customTicks?.y || CustomYAxisTick
  AxisY->>TickY: render(props)

  note over Chart,AxisY: Backward compatible when customTicks not provided
Loading
sequenceDiagram
  autonumber
  participant App as App
  participant BarRoot as BarChart/root
  participant Bar as CustomBar/CustomBarLollipop

  App->>BarRoot: render({ bars, ... })
  BarRoot->>Bar: render({ fill })
  alt fill is function at render time
    Bar-->>Bar: use DEFAULT_BAR_FILL_COLOR "#6B7280"
  else fill is color/string
    Bar-->>Bar: use provided fill
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

🌐frontend, 🌟improvement

Suggested reviewers

  • aaryan610
  • prateekshourya29
  • sriramveeraghanta

Poem

I nibbled the ticks on X and Y,
Swapped them quick with a twitch of my eye.
Bars now don a steady gray hue,
When colors play coy and won’t come through.
Types burrowed neat in a tidy warren—
Charts hop smoother, bright as the morn. 🐇🎨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor-bar-chart

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/propel/src/charts/area-chart/root.tsx (1)

83-103: Fix divide-by-zero when data has a single point.

index / (data.length - 1) yields NaN for length === 1, producing invalid values for comparisonLine.

-  const comparisonLineData = useMemo(() => {
-    if (!data || data.length === 0) return [];
+  const comparisonLineData = useMemo(() => {
+    if (!data?.length) return [];
+    if (data.length === 1) {
+      return data.map((item) => ({
+        [xAxis.key]: item[xAxis.key],
+        comparisonLine: 0,
+      }));
+    }
     // get the last data point
     const lastPoint = data[data.length - 1];
     // for the y-value in the last point, use its yAxis key value
     const lastYValue = lastPoint[yAxis.key] ?? 0;
     // create data for a straight line that has points at each x-axis position
     return data.map((item, index) => {
       // calculate the y value for this point on the straight line
       // using linear interpolation between (0,0) and (last_x, last_y)
-      const ratio = index / (data.length - 1);
+      const ratio = index / (data.length - 1);
       const interpolatedValue = ratio * lastYValue;
packages/propel/src/charts/bar-chart/bar.tsx (1)

166-176: Pass through original fill to shapes to preserve function-based coloring.

Currently createShapeVariant resolves fill to a string, making the above fixes unreachable.

-        fill={typeof bar.fill === "function" ? bar.fill(shapeProps.payload) : bar.fill}
+        fill={bar.fill as any}
♻️ Duplicate comments (3)
packages/types/src/charts/index.ts (2)

24-31: Tighten tooltip prop typing (avoid any).

Recommend narrowing to safer primitives to reduce unsoundness without pulling Recharts types into the types package.

-  customTooltipContent?: (props: { active?: boolean; label: string; payload: any }) => React.ReactNode;
+  customTooltipContent?: (props: { active?: boolean; label: string | number; payload: unknown[] }) => React.ReactNode;

33-58: Type customTicks more strictly or document the contract.

React.ComponentType<any> hides the expected tick props. Minimum: switch to unknown. Better: export explicit tick prop interfaces (e.g., { x: number; y: number; payload: { value: string | number } }), and use them for x/y.

-  customTicks?: {
-    x?: React.ComponentType<any>;
-    y?: React.ComponentType<any>;
-  };
+  customTicks?: {
+    x?: React.ComponentType<unknown>;
+    y?: React.ComponentType<unknown>;
+  };

Optionally add explicit types (outside this hunk):

export type TXAxisTickProps = { x: number; y: number; payload: { value: string | number }; getLabel?: (v: string | number) => React.ReactNode };
export type TYAxisTickProps = { x: number; y: number; payload: { value: string | number } };
packages/propel/src/charts/bar-chart/root.tsx (1)

52-57: Unify fallback color with design token.

Use DEFAULT_BAR_FILL_COLOR instead of hardcoded #000000 for tooltip dot colors.

-      colors[bar.key] = typeof bar.fill === "function" ? "#000000" : bar.fill;
+      colors[bar.key] = typeof bar.fill === "function" ? DEFAULT_BAR_FILL_COLOR : bar.fill;
🧹 Nitpick comments (4)
packages/types/src/charts/index.ts (1)

78-81: Align fill requirement with runtime fallback
Runtime applies DEFAULT_BAR_FILL_COLOR when fill is a function (see packages/propel/src/charts/bar-chart/bar.tsx:13). Either make TBarItem.fill optional (fill?: string | ((payload: T) => string)) in packages/types/src/charts/index.ts, or remove the fallback and keep fill required.

packages/propel/src/charts/area-chart/root.tsx (1)

117-131: Honor x-axis label dy from props.

The types expose xAxis.dy, but the label uses a fixed 28. Use the provided value when present.

-            label={
+            label={
               xAxis.label && {
                 value: xAxis.label,
-                dy: 28,
+                dy: xAxis.dy ?? 28,
                 className: AXIS_LABEL_CLASSNAME,
               }
             }
packages/propel/src/charts/scatter-chart/root.tsx (2)

96-101: Honor x-axis label dy from props.

Use xAxis.dy if provided.

-              xAxis.label && {
+              xAxis.label && {
                 value: xAxis.label,
-                dy: 28,
+                dy: xAxis.dy ?? 28,
                 className: AXIS_LABEL_CLASSNAME,
               }

109-116: Respect yAxis.offset consistently (matches AreaChart).

Offset is hardcoded to -24. Use the configured value.

-              yAxis.label && {
+              yAxis.label && {
                 value: yAxis.label,
                 angle: -90,
                 position: "bottom",
-                offset: -24,
+                offset: yAxis.offset ?? -24,
                 dx: yAxis.dx ?? -16,
                 className: AXIS_LABEL_CLASSNAME,
               }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20d139c and d063573.

📒 Files selected for processing (6)
  • packages/propel/src/charts/area-chart/root.tsx (3 hunks)
  • packages/propel/src/charts/bar-chart/bar.tsx (4 hunks)
  • packages/propel/src/charts/bar-chart/root.tsx (5 hunks)
  • packages/propel/src/charts/line-chart/root.tsx (3 hunks)
  • packages/propel/src/charts/scatter-chart/root.tsx (3 hunks)
  • packages/types/src/charts/index.ts (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
packages/propel/src/charts/line-chart/root.tsx (1)
packages/propel/src/charts/components/tick.tsx (2)
  • CustomXAxisTick (7-13)
  • CustomYAxisTick (16-22)
packages/propel/src/charts/scatter-chart/root.tsx (1)
packages/propel/src/charts/components/tick.tsx (2)
  • CustomXAxisTick (7-13)
  • CustomYAxisTick (16-22)
packages/propel/src/charts/bar-chart/root.tsx (2)
packages/propel/src/charts/bar-chart/bar.tsx (1)
  • DEFAULT_BAR_FILL_COLOR (180-180)
packages/propel/src/charts/components/tick.tsx (2)
  • CustomXAxisTick (7-13)
  • CustomYAxisTick (16-22)
packages/propel/src/charts/area-chart/root.tsx (1)
packages/propel/src/charts/components/tick.tsx (2)
  • CustomXAxisTick (7-13)
  • CustomYAxisTick (16-22)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (16)
packages/types/src/charts/index.ts (5)

98-101: LGTM on Line chart props extension.
Consistent with TAxisChartProps.


113-116: LGTM on Scatter chart props extension.
Type composition reads clean.


134-140: LGTM on Area chart props.
comparisonLine shape is clear and minimal.


151-153: LGTM on Pie props pick.
Correct reuse of base props.


234-235: LGTM on Radar props pick.
Consistent with refactor.

packages/propel/src/charts/area-chart/root.tsx (1)

118-121: Custom tick injection looks good.

Dynamic selection preserves backward compatibility with existing Custom* ticks.

Also applies to: 147-150

packages/propel/src/charts/scatter-chart/root.tsx (2)

89-92: Custom X tick injection is correct.

Runtime selection between default and custom components is clean.


118-121: Custom Y tick injection is correct.
Matches X axis pattern; no issues.

packages/propel/src/charts/line-chart/root.tsx (2)

35-35: Prop addition looks good and is backward-compatible.


133-136: Dynamic Y-axis tick component: LGTM.

packages/propel/src/charts/bar-chart/bar.tsx (2)

13-13: Good: centralized default bar color.


180-181: Exporting the default color: LGTM.

packages/propel/src/charts/bar-chart/root.tsx (4)

22-22: Import of DEFAULT_BAR_FILL_COLOR: LGTM.


38-38: Prop addition for custom ticks: LGTM.


69-69: OK to set Bar fill; shapes will override.

No action needed; just ensure it stays in sync with the default color constant.


126-129: Dynamic Y-axis tick component: LGTM.

Comment on lines 110 to 114
d={getBarPath(x, y, width, height, topBorderRadius, bottomBorderRadius)}
className="transition-opacity duration-200"
fill={typeof fill === "function" ? fill(payload) : fill}
fill={typeof fill === "function" ? DEFAULT_BAR_FILL_COLOR : fill}
opacity={opacity}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Bug: functional fills are ignored; bars won’t use per-datapoint color.

When fill is a function, this should call fill(payload), not a static default.

-        fill={typeof fill === "function" ? DEFAULT_BAR_FILL_COLOR : fill}
+        fill={typeof fill === "function" ? fill(payload) : fill}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
d={getBarPath(x, y, width, height, topBorderRadius, bottomBorderRadius)}
className="transition-opacity duration-200"
fill={typeof fill === "function" ? fill(payload) : fill}
fill={typeof fill === "function" ? DEFAULT_BAR_FILL_COLOR : fill}
opacity={opacity}
/>
d={getBarPath(x, y, width, height, topBorderRadius, bottomBorderRadius)}
className="transition-opacity duration-200"
fill={typeof fill === "function" ? fill(payload) : fill}
opacity={opacity}
/>
🤖 Prompt for AI Agents
In packages/propel/src/charts/bar-chart/bar.tsx around lines 110 to 114, the
current fill prop uses a static default when fill is a function; update it so
when fill is a function it is invoked with the bar's payload (e.g.
fill(payload)) and its return value is used as the fill; keep the existing
behavior of using the provided non-function fill value unchanged and fallback to
DEFAULT_BAR_FILL_COLOR only if the function returns a falsy/undefined value.

Comment on lines 140 to 145
cx={x + width / 2}
cy={y}
r={DEFAULT_LOLLIPOP_CIRCLE_RADIUS}
fill={typeof fill === "function" ? fill(payload) : fill}
fill={typeof fill === "function" ? DEFAULT_BAR_FILL_COLOR : fill}
stroke="none"
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Circle color inconsistent with lollipop stroke.

Circle should match computed stroke color when fill is a function.

-        fill={typeof fill === "function" ? DEFAULT_BAR_FILL_COLOR : fill}
+        fill={typeof fill === "function" ? fill(payload) : fill}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
cx={x + width / 2}
cy={y}
r={DEFAULT_LOLLIPOP_CIRCLE_RADIUS}
fill={typeof fill === "function" ? fill(payload) : fill}
fill={typeof fill === "function" ? DEFAULT_BAR_FILL_COLOR : fill}
stroke="none"
/>
cx={x + width / 2}
cy={y}
r={DEFAULT_LOLLIPOP_CIRCLE_RADIUS}
fill={typeof fill === "function" ? fill(payload) : fill}
stroke="none"
/>
🤖 Prompt for AI Agents
In packages/propel/src/charts/bar-chart/bar.tsx around lines 140 to 145, the
circle's fill uses DEFAULT_BAR_FILL_COLOR when fill is a function which makes it
inconsistent with the lollipop stroke; instead compute the stroke color exactly
the same way the stroke prop is computed (e.g., call fill(...) or the stroke
color resolver used for the lollipop) and set the circle's fill to that computed
stroke color when fill is a function, otherwise keep using the provided fill
value; ensure the fallback behavior for non-function fills remains unchanged.

Comment on lines +101 to +104
tick={(props) => {
const TickComponent = customTicks?.x || CustomXAxisTick;
return <TickComponent {...props} />;
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Regression: X-axis tick formatter (getLabel) dropped.

Same issue as LineChart; pass through xAxis.getLabel.

-            tick={(props) => {
-              const TickComponent = customTicks?.x || CustomXAxisTick;
-              return <TickComponent {...props} />;
-            }}
+            tick={(props) => {
+              const TickComponent = customTicks?.x || CustomXAxisTick;
+              return <TickComponent {...props} getLabel={xAxis.getLabel} />;
+            }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tick={(props) => {
const TickComponent = customTicks?.x || CustomXAxisTick;
return <TickComponent {...props} />;
}}
tick={(props) => {
const TickComponent = customTicks?.x || CustomXAxisTick;
return <TickComponent {...props} getLabel={xAxis.getLabel} />;
}}
🤖 Prompt for AI Agents
In packages/propel/src/charts/bar-chart/root.tsx around lines 101 to 104, the
X-axis TickComponent is rendered without forwarding the axis label formatter
(xAxis.getLabel), which regresses behavior; update the tick render to pass
through the xAxis.getLabel (e.g. include getLabel: xAxis.getLabel in the props
spread passed to TickComponent) so custom and default ticks receive the label
formatter while keeping all existing props intact.

Comment on lines +104 to +107
tick={(props) => {
const TickComponent = customTicks?.x || CustomXAxisTick;
return <TickComponent {...props} />;
}}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Regression: X-axis tick formatter (getLabel) no longer applied.

CustomXAxisTick expects getLabel; without passing it, labels won’t be formatted.

Apply:

-            tick={(props) => {
-              const TickComponent = customTicks?.x || CustomXAxisTick;
-              return <TickComponent {...props} />;
-            }}
+            tick={(props) => {
+              const TickComponent = customTicks?.x || CustomXAxisTick;
+              return <TickComponent {...props} getLabel={xAxis.getLabel} />;
+            }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
tick={(props) => {
const TickComponent = customTicks?.x || CustomXAxisTick;
return <TickComponent {...props} />;
}}
tick={(props) => {
const TickComponent = customTicks?.x || CustomXAxisTick;
return <TickComponent {...props} getLabel={xAxis.getLabel} />;
}}
🤖 Prompt for AI Agents
In packages/propel/src/charts/line-chart/root.tsx around lines 104 to 107, the
tick renderer calls the TickComponent but does not pass the getLabel formatter
through, so CustomXAxisTick never receives getLabel; update the tick callback to
pass getLabel (preferably from customTicks.x if present, otherwise from the
current component props) along with the existing props so the TickComponent
receives and applies the label formatter.

@JayashTripathy JayashTripathy changed the title [WEB-4855] improvement: bar chart improvements [WEB-4855] refactor: bar chart improvements Sep 7, 2025
@JayashTripathy JayashTripathy deleted the refactor-bar-chart branch September 15, 2025 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants