Skip to content

Split scale definition into two parts#6783

Merged
PavelVanecek merged 1 commit intomainfrom
ts-strict
Dec 17, 2025
Merged

Split scale definition into two parts#6783
PavelVanecek merged 1 commit intomainfrom
ts-strict

Conversation

@PavelVanecek
Copy link
Collaborator

@PavelVanecek PavelVanecek commented Dec 16, 2025

Description

I like how ScaleHelper (

export class ScaleHelper {
) encapsulates scales and adds new functionality on top, so let's have the same for all scales!

Because we accept the function from the outside as props, we can't just add new methods and new arguments to it. So step one is to split the scale function type into two: the internal one, and external one. External one stays stable, internal one will have new methods.

So I did that and fixed all violations - there were again quite a few any hiding undefineds. You can see on the screenshot that we got rid of mysterious y: 0 error bars too.

Related Issue

#6645

Having new methods on the internal scale will also allow fix for #5262

Motivation and Context

No any

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for custom scale definitions, enabling more flexible scale configurations across charts.
  • Bug Fixes

    • Improved null-safety handling for scale calculations in Area, Bar, ErrorBar, Line, and Scatter charts.
    • Enhanced scale validation with null coalescing to prevent undefined coordinate values.
    • Fixed radius calculations in scatter plots when size values are missing.
  • Chores

    • Updated scale utility organization and type definitions for better maintainability.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

Walkthrough

This PR refactors Recharts' scale abstraction system by introducing new CustomScaleDefinition and RechartsScale interfaces, reorganizing scale utilities into a dedicated module, and updating axis/selector types and control flow throughout the codebase. Import paths shift from centralized ChartUtils to the new util/scale/ structure, with defensive null checks added to coordinate calculations.

Changes

Cohort / File(s) Summary
Snapshot Manifest Files
scripts/snapshots/es6Files.txt, scripts/snapshots/libFiles.txt, scripts/snapshots/typesFiles.txt
Added build artifacts for two new scale utilities: CustomScaleDefinition and RechartsScale files across es6, lib, and types output directories.
New Scale Utility Interfaces
src/util/scale/CustomScaleDefinition.ts, src/util/scale/RechartsScale.ts
Introduced CustomScaleDefinition<Domain> public interface for immutable external scale definitions and RechartsScale<Domain> public interface with makeRechartsScale() factory function for unified scale construction and d3-scale integration.
Type System Updates
src/util/types.ts
Added D3ScaleType and CategoricalDomainItem types; updated ScaleType alias to 'auto' | D3ScaleType; updated BaseAxisProps.scale to accept ScaleType | CustomScaleDefinition; replaced RechartsScale import with CustomScaleDefinition.
State Type Definitions
src/state/cartesianAxisSlice.ts
Updated BaseCartesianAxis.scale from ScaleType | RechartsScale to ScaleType | CustomScaleDefinition; added CustomScaleDefinition import.
Axis Selector Updates
src/state/selectors/axisSelectors.ts
Updated BaseAxisWithScale and ZAxisWithScale to use Omit<..., 'scale'> & { scale: RechartsScale }; refined combineRealScaleType return type to ScaleType | undefined; changed combineScaleFunction parameter to D3ScaleType | undefined; added makeRechartsScale invocation for unified scale construction.
Polar Selector Updates
src/state/selectors/polarScaleSelectors.ts, src/state/selectors/radarSelectors.ts, src/state/selectors/radialBarSelectors.ts
Updated RechartsScale import paths from ChartUtils to util/scale/RechartsScale; no functional logic changes.
Tooltip Selector & Utilities
src/state/selectors/tooltipSelectors.ts, src/util/ChartUtils.ts
Added numeric safety checks in tick generation using isWellBehavedNumber guards; added CategoricalDomainItem type usage; updated getTicksOfAxis and related functions to filter out invalid scale results; updated getCateCoordinateOfLine and getCateCoordinateOfBar to accept RechartsScale type and add null checks.
Cartesian Component Nullish Safety
src/cartesian/Area.tsx, src/cartesian/Bar.tsx, src/cartesian/ErrorBar.tsx, src/cartesian/Line.tsx, src/cartesian/Scatter.tsx
Added nullish coalescing operators (?? null, ?? 0) and null checks for scale computation results; added BaseValueCoordinate type in Area; made scale result guards explicit to prevent undefined coordinates; updated stackedBarStart type to number | undefined.
Cartesian Reference Component
src/cartesian/ReferenceArea.tsx
Updated RechartsScale import path from ../util/ChartUtils to ../util/scale/RechartsScale.
Polar/Radial Component Updates
src/polar/PolarAngleAxis.tsx, src/polar/PolarRadiusAxis.tsx, src/polar/Radar.tsx, src/polar/RadialBar.tsx
Updated PolarAngleAxisProps.scale to accept CustomScaleDefinition instead of RechartsScale; added nullish fallbacks (?? 0) for angle and radius scale results; updated RechartsScale import paths; added explicit type annotations and null guards in computeRadialBarDataItems with conditional logic for angle/radius calculations.
Public API Exports
src/index.ts
Added public type export: CustomScaleDefinition from ./util/scale/CustomScaleDefinition.
ZAxis Type Updates
src/cartesian/ZAxis.tsx
Updated Props.scale type from ScaleType | RechartsScale to ScaleType | CustomScaleDefinition; updated imports accordingly.
Storybook Inspector
storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx
Updated RechartsScale import path from ChartUtils to util/scale/RechartsScale.
Test Snapshot & Expectations
test/cartesian/Area.spec.tsx, test/component/Tooltip/itemSorter.spec.tsx, test/state/selectors/selectAxisScale.spec.tsx, test/util/ChartUtils/checkDomainOfScale.spec.ts
Added @ts-expect-error suppressions for incomplete mocks; updated expected startAngle values from undefined to 0 in test payloads; removed call-count verification in scale selector test; added domain stability assertions.
Test Type Updates
test/cartesian/CartesianAxis.spec.tsx, test/helper/mockAxes.ts, test/helper/expectScale.ts, test/helper/toBeRechartsScale.ts, test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
Updated scale type from RechartsScale to CustomScaleDefinition<number> in mock/test fixtures; updated import paths for scale types; removed @ts-expect-error comments after type alignment.
Test Selector & Utilities
test/state/selectors/axisSelectors.spec.tsx, test/util/ChartUtils.spec.tsx
Updated type annotations to use Omit<XAxisSettings, 'scale'> & BaseAxisWithScale; expanded BaseAxisWithScale test assertions with additional public fields; imported defaultAxisId and CustomScaleDefinition in tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring extra attention:

  • New scale abstraction layer: Verify CustomScaleDefinition interface design aligns with d3-scale contract expectations and immutability requirements; review makeRechartsScale() factory logic for proper scale type resolution and domain/range configuration.
  • Type signature changes in axis selectors (src/state/selectors/axisSelectors.ts): Complex refactoring with Omit<..., 'scale'> patterns and makeRechartsScale invocation; ensure selector composition and return types are correctly applied downstream.
  • Nullish safety patterns in cartesian components (Area, Bar, ErrorBar, Line, Scatter, RadialBar): Verify defensive null checks and coalescing operators don't inadvertently suppress legitimate errors; confirm coordinate calculations remain correct with fallback values.
  • RadialBar control flow changes: Complex conditional logic added for angle/radius angle calculations and minPointSize handling; verify startAngle/endAngle computations and backgroundSector assignment cover all cases.
  • Import path migration: Confirm all references to scale utilities have been consistently updated from ChartUtils to dedicated util/scale/* paths; verify no stale imports remain.
  • Test expectations alignment: Review updated test type annotations and payload expectations (especially startAngle: 0 changes) to ensure they reflect actual component behavior after refactoring.

Possibly related PRs

  • More undefined checks #6747: Overlapping changes in cartesian component coordinate calculations (Area, Bar, ErrorBar, Line, Scatter) with null/undefined handling and typing refinements.
  • Ts strict #6750: Direct code-level overlap in scale type imports and axis/tooltip selector type signature updates across axisSelectors and tooltipSelectors.
  • Fix stacked Bar animation #6593: Related changes to Bar component and stacked bar coordinate handling with scale guards and stackedBarStart typing.

Suggested labels

typescript, refactor

Suggested reviewers

  • ckifer

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.88% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description provides clear motivation, context, and links to related issues, but lacks explicit sections for 'Related Issue', 'How Has This Been Tested', and 'Types of changes' checkboxes as specified in the template. Fill in the template sections: explicitly use the 'Related Issue' heading with the issue link, document testing approach under 'How Has This Been Tested', and mark applicable checkboxes under 'Types of changes'.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Split scale definition into two parts' clearly and specifically summarizes the main change: separating the scale function type into external and internal variants.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ts-strict

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
Collaborator Author

Choose a reason for hiding this comment

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

@ckifer this is an important one to review - the external interface will be locked for major versions

Copy link
Member

Choose a reason for hiding this comment

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

does this break if someone uses a method from a d3 scale prior to passing it in and then pass it in?

It shouldn't

Something that I've done in the past is used https://d3js.org/d3-scale/linear#linear_invert

In this case I would define my scale with a given domain/range and then because recharts is using that same scale use it to convert X and Y values to my scale. This should still work, cool

Copy link
Member

Choose a reason for hiding this comment

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

and its always easier to add more later

Copy link
Member

Choose a reason for hiding this comment

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

what happens if D3 breaks us here?

Copy link
Collaborator Author

@PavelVanecek PavelVanecek Dec 17, 2025

Choose a reason for hiding this comment

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

does this break if someone uses a method from a d3 scale prior to passing it in and then pass it in?

They can do whatever with the scale, this interface is the list of methods we require inside Recharts. It doesn't even need to be imported from d3, as long as it implements this interface.

and its always easier to add more later

That's the thing, adding more methods here will be a breaking change. If someone does have a custom implementation (so, skips d3) then having a new required method will break their code.

This is in contrast to the internal interface where we can add new stuff anytime. We can return it from a hook and make it external that way - and because there it's in a consumer position, adding new methods in that context will not break anyone.

what happens if D3 breaks us here?

Then that triggers a major version for Recharts ¯\_(ツ)_/¯

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

And yes the invert method will be one of the things we export from a hook. I would prefer to keep it simple however, so perhaps we will export only a single method (invert) instead of the whole scale.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@ckifer this will be internal only, and we will be free to change it. First step will be to add the apply method from ScaleHelper


describe('getTicksForAxis', () => {
const Y_AXIS_EXAMPLE: AxisPropsNeededForTicksGenerator = {
// @ts-expect-error we need to wrap the d3 scales in unified interface
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We did wrap d3 scale in unified interface now!

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 (1)
src/polar/RadialBar.tsx (1)

640-654: Potential issue: endAngle may be undefined at return.

The @ts-expect-error comment indicates that endAngle might not be assigned in all code paths. Specifically, if both the radial and non-radial layout guards fail (e.g., innerRadius is null), endAngle remains unassigned.

Consider providing a fallback value for endAngle in the return object:

       startAngle,
-      // @ts-expect-error endAngle is used before assigned (?)
-      endAngle,
+      endAngle: endAngle ?? rootEndAngle,
       ...(cells && cells[index] && cells[index].props),

Alternatively, initialize endAngle with a default value at declaration (line 574):

-      endAngle: number,
+      endAngle: number = rootEndAngle,
🧹 Nitpick comments (4)
src/state/selectors/tooltipSelectors.ts (1)

390-397: Helpful documentation noting related implementations.

This comment documenting the four tick generation implementations is valuable for maintainability. Consider opening an issue to consolidate these if they share significant logic.

src/cartesian/Area.tsx (1)

81-84: Avoid using any type for payload.

The payload property uses any, which violates the coding guidelines. Consider using a generic type parameter or unknown with proper type guards.

-type BaseValueCoordinate = NullableCoordinate & { payload: any };
+type BaseValueCoordinate = NullableCoordinate & { payload: unknown };

As per coding guidelines, any should be avoided in TypeScript code.

src/util/scale/RechartsScale.ts (1)

54-67: Type verification could be improved in getD3ScaleFromType.

The two @ts-expect-error comments indicate weak type verification. Consider adding runtime validation or a type map for better safety.

A type-safe approach could use a mapping object:

const scaleFactories: Partial<Record<D3ScaleType, () => CustomScaleDefinition>> = {
  linear: d3Scales.scaleLinear,
  band: d3Scales.scaleBand,
  point: d3Scales.scalePoint,
  // ... etc
};

This would eliminate the @ts-expect-error comments and provide compile-time safety.

src/state/selectors/axisSelectors.ts (1)

1089-1091: Consider using a more robust scale name validation.

The current check name in d3Scales will return true for any property on the d3Scales object, including inherited properties. While this works for the expected d3 scale names like scaleLinear, it could potentially match unintended properties.

Consider using Object.hasOwn for stricter property checking:

 function isSupportedScaleName(name: string): name is ScaleType {
-  return name in d3Scales;
+  return Object.hasOwn(d3Scales, name);
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9835fe and e63e825.

⛔ Files ignored due to path filters (13)
  • package-lock.json is excluded by !**/package-lock.json
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ComposedChart-vertical-both-directions-item-data-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ComposedChart-vertical-both-directions-item-data-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ComposedChart-vertical-both-directions-item-data-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ComposedChart-vertical-both-directions-root-data-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ComposedChart-vertical-both-directions-root-data-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ComposedChart-vertical-both-directions-root-data-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ScatterChart-vertical-both-directions-item-data-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ScatterChart-vertical-both-directions-item-data-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ScatterChart-vertical-both-directions-item-data-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ScatterChart-vertical-both-directions-root-data-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ScatterChart-vertical-both-directions-root-data-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/ErrorBar.Scatter.spec-vr.tsx-snapshots/ScatterChart-vertical-both-directions-root-data-1-webkit-linux.png is excluded by !**/*.png
📒 Files selected for processing (37)
  • scripts/snapshots/es6Files.txt (1 hunks)
  • scripts/snapshots/libFiles.txt (1 hunks)
  • scripts/snapshots/typesFiles.txt (1 hunks)
  • src/cartesian/Area.tsx (3 hunks)
  • src/cartesian/Bar.tsx (3 hunks)
  • src/cartesian/ErrorBar.tsx (2 hunks)
  • src/cartesian/Line.tsx (1 hunks)
  • src/cartesian/ReferenceArea.tsx (1 hunks)
  • src/cartesian/Scatter.tsx (1 hunks)
  • src/cartesian/ZAxis.tsx (2 hunks)
  • src/index.ts (1 hunks)
  • src/polar/PolarAngleAxis.tsx (2 hunks)
  • src/polar/PolarRadiusAxis.tsx (1 hunks)
  • src/polar/Radar.tsx (4 hunks)
  • src/polar/RadialBar.tsx (5 hunks)
  • src/state/cartesianAxisSlice.ts (2 hunks)
  • src/state/selectors/axisSelectors.ts (13 hunks)
  • src/state/selectors/polarScaleSelectors.ts (1 hunks)
  • src/state/selectors/radarSelectors.ts (1 hunks)
  • src/state/selectors/radialBarSelectors.ts (2 hunks)
  • src/state/selectors/tooltipSelectors.ts (4 hunks)
  • src/util/ChartUtils.ts (6 hunks)
  • src/util/scale/CustomScaleDefinition.ts (1 hunks)
  • src/util/scale/RechartsScale.ts (1 hunks)
  • src/util/types.ts (5 hunks)
  • storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx (1 hunks)
  • test/cartesian/Area.spec.tsx (7 hunks)
  • test/cartesian/CartesianAxis.spec.tsx (2 hunks)
  • test/component/Tooltip/itemSorter.spec.tsx (12 hunks)
  • test/helper/expectScale.ts (1 hunks)
  • test/helper/mockAxes.ts (1 hunks)
  • test/helper/toBeRechartsScale.ts (1 hunks)
  • test/state/selectors/axisSelectors.spec.tsx (1 hunks)
  • test/state/selectors/selectAxisScale.spec.tsx (1 hunks)
  • test/util/ChartUtils.spec.tsx (3 hunks)
  • test/util/ChartUtils/checkDomainOfScale.spec.ts (1 hunks)
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx}: Never use any type (implicit or explicit) in TypeScript code
Prefer unknown over any and refine the type in TypeScript
Type function parameters and return values explicitly in TypeScript, do not rely on implicit any or inference; exceptions are React components and trivial functions
Do not use as type assertions in TypeScript; the only exception is as const

Files:

  • test/util/ChartUtils/checkDomainOfScale.spec.ts
  • src/state/cartesianAxisSlice.ts
  • test/state/selectors/axisSelectors.spec.tsx
  • src/state/selectors/radialBarSelectors.ts
  • src/util/scale/CustomScaleDefinition.ts
  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx
  • test/cartesian/CartesianAxis.spec.tsx
  • src/util/scale/RechartsScale.ts
  • src/polar/PolarRadiusAxis.tsx
  • src/polar/PolarAngleAxis.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • src/cartesian/Bar.tsx
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • src/cartesian/ReferenceArea.tsx
  • src/util/ChartUtils.ts
  • src/index.ts
  • src/cartesian/Scatter.tsx
  • src/polar/RadialBar.tsx
  • src/state/selectors/radarSelectors.ts
  • test/helper/expectScale.ts
  • test/component/Tooltip/itemSorter.spec.tsx
  • src/cartesian/ZAxis.tsx
  • src/cartesian/Line.tsx
  • src/state/selectors/polarScaleSelectors.ts
  • src/cartesian/Area.tsx
  • src/cartesian/ErrorBar.tsx
  • src/polar/Radar.tsx
  • src/util/types.ts
  • src/state/selectors/tooltipSelectors.ts
  • test/util/ChartUtils.spec.tsx
  • src/state/selectors/axisSelectors.ts
test/**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Aim for 100% unit test code coverage when writing new code

Files:

  • test/util/ChartUtils/checkDomainOfScale.spec.ts
  • test/state/selectors/axisSelectors.spec.tsx
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • test/cartesian/CartesianAxis.spec.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • test/cartesian/Area.spec.tsx
  • test/component/Tooltip/itemSorter.spec.tsx
  • test/util/ChartUtils.spec.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Ensure code lints by running npm run lint and follows Airbnb's Style Guide

Files:

  • test/util/ChartUtils/checkDomainOfScale.spec.ts
  • src/state/cartesianAxisSlice.ts
  • test/state/selectors/axisSelectors.spec.tsx
  • src/state/selectors/radialBarSelectors.ts
  • src/util/scale/CustomScaleDefinition.ts
  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx
  • test/cartesian/CartesianAxis.spec.tsx
  • src/util/scale/RechartsScale.ts
  • src/polar/PolarRadiusAxis.tsx
  • src/polar/PolarAngleAxis.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • src/cartesian/Bar.tsx
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • src/cartesian/ReferenceArea.tsx
  • src/util/ChartUtils.ts
  • src/index.ts
  • src/cartesian/Scatter.tsx
  • src/polar/RadialBar.tsx
  • src/state/selectors/radarSelectors.ts
  • test/helper/expectScale.ts
  • test/component/Tooltip/itemSorter.spec.tsx
  • src/cartesian/ZAxis.tsx
  • src/cartesian/Line.tsx
  • src/state/selectors/polarScaleSelectors.ts
  • src/cartesian/Area.tsx
  • src/cartesian/ErrorBar.tsx
  • src/polar/Radar.tsx
  • src/util/types.ts
  • src/state/selectors/tooltipSelectors.ts
  • test/util/ChartUtils.spec.tsx
  • src/state/selectors/axisSelectors.ts
test/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (test/README.md)

test/**/*.{test,spec}.{ts,tsx}: Aim for 100% unit test code coverage when writing new code
Prefer to use the createSelectorTestCase helper function when writing or modifying tests
Use the expectLastCalledWith helper function instead of expect(spy).toHaveBeenLastCalledWith(...) for better typing and autocompletion
Verify the number of selector calls using the spy object from createSelectorTestCase to spot unnecessary re-renders and improve performance
Mock getBoundingClientRect in tests using the helper function provided in test/helper/MockGetBoundingClientRect.ts
Use vi.useFakeTimers() in all tests due to Redux autoBatchEnhancer dependency on timers and requestAnimationFrame
Call vi.runOnlyPendingTimers() to advance timers after renders when not using createSelectorTestCase helper, and avoid vi.runAllTimers() to prevent infinite loops
Use userEvent.setup({ advanceTimers: vi.runOnlyPendingTimers }) or the userEventSetup helper function from test/helper/userEventSetup.ts when creating userEvent instances
When testing tooltips on hover, use vi.runOnlyPendingTimers() after each userEvent.hover() call or use the showTooltip helper function from tooltipTestHelpers.ts to account for requestAnimationFrame delays

Files:

  • test/util/ChartUtils/checkDomainOfScale.spec.ts
  • test/state/selectors/axisSelectors.spec.tsx
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • test/cartesian/CartesianAxis.spec.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • test/cartesian/Area.spec.tsx
  • test/component/Tooltip/itemSorter.spec.tsx
  • test/util/ChartUtils.spec.tsx
**/*.spec.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

When running unit tests, prefer to run a single test file using npm run test -- path/to/TestFile.spec.tsx rather than running all tests with npm test

Files:

  • test/util/ChartUtils/checkDomainOfScale.spec.ts
  • test/state/selectors/axisSelectors.spec.tsx
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • test/cartesian/CartesianAxis.spec.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • test/cartesian/Area.spec.tsx
  • test/component/Tooltip/itemSorter.spec.tsx
  • test/util/ChartUtils.spec.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (DEVELOPING.md)

All imports from recharts must use the public API entry point; imports from internal paths like recharts/types/* or recharts/src/* are not allowed

Files:

  • test/util/ChartUtils/checkDomainOfScale.spec.ts
  • src/state/cartesianAxisSlice.ts
  • test/state/selectors/axisSelectors.spec.tsx
  • src/state/selectors/radialBarSelectors.ts
  • src/util/scale/CustomScaleDefinition.ts
  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx
  • test/cartesian/CartesianAxis.spec.tsx
  • src/util/scale/RechartsScale.ts
  • src/polar/PolarRadiusAxis.tsx
  • src/polar/PolarAngleAxis.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • src/cartesian/Bar.tsx
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • src/cartesian/ReferenceArea.tsx
  • src/util/ChartUtils.ts
  • src/index.ts
  • src/cartesian/Scatter.tsx
  • src/polar/RadialBar.tsx
  • src/state/selectors/radarSelectors.ts
  • test/helper/expectScale.ts
  • test/component/Tooltip/itemSorter.spec.tsx
  • src/cartesian/ZAxis.tsx
  • src/cartesian/Line.tsx
  • src/state/selectors/polarScaleSelectors.ts
  • src/cartesian/Area.tsx
  • src/cartesian/ErrorBar.tsx
  • src/polar/Radar.tsx
  • src/util/types.ts
  • src/state/selectors/tooltipSelectors.ts
  • test/util/ChartUtils.spec.tsx
  • src/state/selectors/axisSelectors.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Do not hardcode any strings or formatting choices in library code; users should provide localized strings as desired

Files:

  • src/state/cartesianAxisSlice.ts
  • src/state/selectors/radialBarSelectors.ts
  • src/util/scale/CustomScaleDefinition.ts
  • src/util/scale/RechartsScale.ts
  • src/polar/PolarRadiusAxis.tsx
  • src/polar/PolarAngleAxis.tsx
  • src/cartesian/Bar.tsx
  • src/cartesian/ReferenceArea.tsx
  • src/util/ChartUtils.ts
  • src/index.ts
  • src/cartesian/Scatter.tsx
  • src/polar/RadialBar.tsx
  • src/state/selectors/radarSelectors.ts
  • src/cartesian/ZAxis.tsx
  • src/cartesian/Line.tsx
  • src/state/selectors/polarScaleSelectors.ts
  • src/cartesian/Area.tsx
  • src/cartesian/ErrorBar.tsx
  • src/polar/Radar.tsx
  • src/util/types.ts
  • src/state/selectors/tooltipSelectors.ts
  • src/state/selectors/axisSelectors.ts
test/component/**/*.spec.tsx

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use React Testing Library for testing component interactions and behavior upon rendering

Files:

  • test/component/Tooltip/itemSorter.spec.tsx
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-06T03:36:59.377Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : All imports from `recharts` must use the public API entry point; imports from internal paths like `recharts/types/*` or `recharts/src/*` are not allowed
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6771
File: src/shape/Curve.tsx:39-40
Timestamp: 2025-12-14T13:58:49.197Z
Learning: In the recharts codebase, `useAppSelector` and hooks like `useChartLayout()` are designed to return `undefined` when used outside Redux Provider context, rather than throwing errors. This allows components like `Curve` that call these hooks to work standalone by falling back to prop values.
📚 Learning: 2025-12-06T03:36:59.377Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: DEVELOPING.md:0-0
Timestamp: 2025-12-06T03:36:59.377Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : All imports from `recharts` must use the public API entry point; imports from internal paths like `recharts/types/*` or `recharts/src/*` are not allowed

Applied to files:

  • scripts/snapshots/typesFiles.txt
  • scripts/snapshots/libFiles.txt
  • src/state/cartesianAxisSlice.ts
  • src/state/selectors/radialBarSelectors.ts
  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx
  • test/cartesian/CartesianAxis.spec.tsx
  • src/util/scale/RechartsScale.ts
  • src/polar/PolarRadiusAxis.tsx
  • src/polar/PolarAngleAxis.tsx
  • test/helper/toBeRechartsScale.ts
  • src/cartesian/ReferenceArea.tsx
  • src/util/ChartUtils.ts
  • src/index.ts
  • src/state/selectors/radarSelectors.ts
  • test/helper/expectScale.ts
  • scripts/snapshots/es6Files.txt
  • src/state/selectors/polarScaleSelectors.ts
  • src/polar/Radar.tsx
  • src/util/types.ts
  • src/state/selectors/tooltipSelectors.ts
  • test/util/ChartUtils.spec.tsx
  • src/state/selectors/axisSelectors.ts
📚 Learning: 2025-11-23T13:30:10.395Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6669
File: www/src/docs/exampleComponents/ScatterChart/ScatterChartWithLabels.tsx:2-2
Timestamp: 2025-11-23T13:30:10.395Z
Learning: The `TooltipIndex` type from recharts is defined in `src/state/tooltipSlice.ts` but is not currently exported from the public API entry points. It should not be imported from `recharts/types/state/tooltipSlice` as this is an internal implementation path. An ESLint rule is needed to prevent regressions.

Applied to files:

  • scripts/snapshots/typesFiles.txt
  • src/state/cartesianAxisSlice.ts
  • src/state/selectors/radialBarSelectors.ts
  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx
  • test/cartesian/CartesianAxis.spec.tsx
  • src/util/scale/RechartsScale.ts
  • src/polar/PolarRadiusAxis.tsx
  • src/polar/PolarAngleAxis.tsx
  • test/helper/toBeRechartsScale.ts
  • src/cartesian/ReferenceArea.tsx
  • src/util/ChartUtils.ts
  • src/index.ts
  • src/state/selectors/radarSelectors.ts
  • test/helper/expectScale.ts
  • test/component/Tooltip/itemSorter.spec.tsx
  • src/cartesian/ZAxis.tsx
  • src/state/selectors/polarScaleSelectors.ts
  • src/polar/Radar.tsx
  • src/util/types.ts
  • src/state/selectors/tooltipSelectors.ts
  • test/util/ChartUtils.spec.tsx
  • src/state/selectors/axisSelectors.ts
📚 Learning: 2025-12-14T13:58:49.197Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6771
File: src/shape/Curve.tsx:39-40
Timestamp: 2025-12-14T13:58:49.197Z
Learning: In the recharts codebase, `useAppSelector` and hooks like `useChartLayout()` are designed to return `undefined` when used outside Redux Provider context, rather than throwing errors. This allows components like `Curve` that call these hooks to work standalone by falling back to prop values.

Applied to files:

  • scripts/snapshots/libFiles.txt
  • src/state/cartesianAxisSlice.ts
  • src/state/selectors/radialBarSelectors.ts
  • test/helper/mockAxes.ts
  • storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx
  • src/util/ChartUtils.ts
  • src/state/selectors/radarSelectors.ts
  • src/state/selectors/polarScaleSelectors.ts
  • src/util/types.ts
  • src/state/selectors/tooltipSelectors.ts
  • src/state/selectors/axisSelectors.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Verify the number of selector calls using the spy object from `createSelectorTestCase` to spot unnecessary re-renders and improve performance

Applied to files:

  • test/state/selectors/axisSelectors.spec.tsx
  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • test/cartesian/CartesianAxis.spec.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • src/state/selectors/radarSelectors.ts
  • test/helper/expectScale.ts
  • test/component/Tooltip/itemSorter.spec.tsx
  • src/state/selectors/tooltipSelectors.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Prefer to use the `createSelectorTestCase` helper function when writing or modifying tests

Applied to files:

  • test/state/selectors/axisSelectors.spec.tsx
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • test/cartesian/CartesianAxis.spec.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • test/helper/expectScale.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Use the `expectLastCalledWith` helper function instead of `expect(spy).toHaveBeenLastCalledWith(...)` for better typing and autocompletion

Applied to files:

  • test/state/selectors/axisSelectors.spec.tsx
  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • test/state/selectors/selectAxisScale.spec.tsx
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • test/helper/expectScale.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Call `vi.runOnlyPendingTimers()` to advance timers after renders when not using `createSelectorTestCase` helper, and avoid `vi.runAllTimers()` to prevent infinite loops

Applied to files:

  • test/state/selectors/axisSelectors.spec.tsx
  • test/cartesian/CartesianAxis.spec.tsx
  • test/state/selectors/selectAxisScale.spec.tsx
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Mock `getBoundingClientRect` in tests using the helper function provided in `test/helper/MockGetBoundingClientRect.ts`

Applied to files:

  • test/helper/mockAxes.ts
  • test/util/ChartUtils/getCateCoordinateOfLine.spec.ts
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • test/helper/expectScale.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : Use `vi.useFakeTimers()` in all tests due to Redux autoBatchEnhancer dependency on timers and `requestAnimationFrame`

Applied to files:

  • test/helper/mockAxes.ts
  • test/state/selectors/selectAxisScale.spec.tsx
  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
📚 Learning: 2025-11-25T01:22:59.729Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to test/component/**/*.spec.tsx : Use React Testing Library for testing component interactions and behavior upon rendering

Applied to files:

  • test/cartesian/CartesianAxis.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • test/helper/expectScale.ts
📚 Learning: 2025-12-14T13:58:49.197Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6771
File: src/shape/Curve.tsx:39-40
Timestamp: 2025-12-14T13:58:49.197Z
Learning: In the recharts codebase, hooks like useAppSelector and other hooks (e.g., useChartLayout()) return undefined when used outside Redux Provider context, instead of throwing. This enables components that call these hooks, such as Curve, to operate in standalone mode by falling back to prop values. During code reviews, ensure TSX files gracefully handle undefined results from hooks and implement fallbacks (e.g., via default props or explicit prop-based values) rather than assuming the hook is always within Provider.

Applied to files:

  • src/polar/PolarRadiusAxis.tsx
  • src/polar/PolarAngleAxis.tsx
  • src/cartesian/Bar.tsx
  • src/cartesian/ReferenceArea.tsx
  • src/cartesian/Scatter.tsx
  • src/polar/RadialBar.tsx
  • src/cartesian/ZAxis.tsx
  • src/cartesian/Line.tsx
  • src/cartesian/Area.tsx
  • src/cartesian/ErrorBar.tsx
  • src/polar/Radar.tsx
📚 Learning: 2025-11-19T14:08:01.728Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6659
File: www/src/components/GuideView/Performance/index.tsx:232-250
Timestamp: 2025-11-19T14:08:01.728Z
Learning: In Recharts version 3.4.2, object-as-prop optimizations were introduced to reduce unnecessary re-renders when new object references are passed as props. This affects the recommendation for the `react-perf/jsx-no-new-object-as-prop` ESLint rule.

Applied to files:

  • src/polar/PolarAngleAxis.tsx
  • src/cartesian/ReferenceArea.tsx
  • src/state/selectors/tooltipSelectors.ts
📚 Learning: 2025-11-25T01:23:08.250Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: test/README.md:0-0
Timestamp: 2025-11-25T01:23:08.250Z
Learning: Applies to test/**/*.{test,spec}.{ts,tsx} : When testing tooltips on hover, use `vi.runOnlyPendingTimers()` after each `userEvent.hover()` call or use the `showTooltip` helper function from `tooltipTestHelpers.ts` to account for requestAnimationFrame delays

Applied to files:

  • test/state/selectors/selectAxisScale.spec.tsx
  • test/component/Tooltip/itemSorter.spec.tsx
  • src/state/selectors/tooltipSelectors.ts
📚 Learning: 2025-11-25T01:22:59.729Z
Learnt from: CR
Repo: recharts/recharts PR: 0
File: CONTRIBUTING.md:0-0
Timestamp: 2025-11-25T01:22:59.729Z
Learning: Applies to storybook/stories/**/*.stories.tsx : Update Storybook stories when APIs have been changed to ensure they work as expected

Applied to files:

  • test/cartesian/Area.spec.tsx
  • test/helper/toBeRechartsScale.ts
  • test/helper/expectScale.ts
📚 Learning: 2025-12-08T08:23:26.261Z
Learnt from: PavelVanecek
Repo: recharts/recharts PR: 6750
File: src/state/selectors/axisSelectors.ts:593-602
Timestamp: 2025-12-08T08:23:26.261Z
Learning: In the recharts codebase, `DataKey<any>` is an intentional exception to the "no any" rule while proper typing is being developed. This should not be flagged in reviews.

Applied to files:

  • src/util/ChartUtils.ts
🧬 Code graph analysis (16)
test/util/ChartUtils/checkDomainOfScale.spec.ts (1)
src/util/ChartUtils.ts (1)
  • checkDomainOfScale (283-300)
src/state/cartesianAxisSlice.ts (3)
src/util/types.ts (1)
  • ScaleType (182-182)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/scale/CustomScaleDefinition.ts (1)
  • CustomScaleDefinition (13-63)
test/state/selectors/axisSelectors.spec.tsx (2)
src/state/cartesianAxisSlice.ts (1)
  • XAxisSettings (78-82)
src/state/selectors/axisSelectors.ts (1)
  • BaseAxisWithScale (2051-2051)
src/util/scale/CustomScaleDefinition.ts (2)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/types.ts (1)
  • CategoricalDomainItem (732-732)
test/util/ChartUtils/getCateCoordinateOfLine.spec.ts (2)
test/helper/mockAxes.ts (1)
  • mockScale (5-5)
src/util/scale/RechartsScale.ts (1)
  • RechartsScale (15-52)
test/cartesian/CartesianAxis.spec.tsx (2)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/scale/CustomScaleDefinition.ts (1)
  • CustomScaleDefinition (13-63)
src/util/scale/RechartsScale.ts (6)
src/util/types.ts (2)
  • CategoricalDomainItem (732-732)
  • D3ScaleType (160-175)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/scale/CustomScaleDefinition.ts (1)
  • CustomScaleDefinition (13-63)
src/util/DataUtils.ts (1)
  • upperFirst (189-195)
src/state/selectors/axisSelectors.ts (1)
  • AxisRange (1415-1415)
src/util/ChartUtils.ts (1)
  • checkDomainOfScale (283-300)
src/polar/PolarAngleAxis.tsx (3)
src/util/types.ts (1)
  • ScaleType (182-182)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/scale/CustomScaleDefinition.ts (1)
  • CustomScaleDefinition (13-63)
src/util/ChartUtils.ts (4)
src/util/types.ts (2)
  • TickItem (827-832)
  • CategoricalDomainItem (732-732)
src/util/isWellBehavedNumber.ts (1)
  • isWellBehavedNumber (1-3)
src/util/DataUtils.ts (3)
  • isNotNil (202-204)
  • isNullish (180-182)
  • isNumber (24-25)
src/util/scale/RechartsScale.ts (1)
  • RechartsScale (15-52)
src/polar/RadialBar.tsx (1)
src/util/DataUtils.ts (1)
  • mathSign (5-14)
src/cartesian/ZAxis.tsx (3)
src/util/types.ts (1)
  • ScaleType (182-182)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/scale/CustomScaleDefinition.ts (1)
  • CustomScaleDefinition (13-63)
src/cartesian/Area.tsx (3)
src/util/types.ts (1)
  • NullableCoordinate (105-108)
src/util/ChartUtils.ts (1)
  • getCateCoordinateOfLine (503-542)
src/state/selectors/areaSelectors.ts (1)
  • AreaPointItem (24-29)
src/polar/Radar.tsx (1)
src/util/DataUtils.ts (1)
  • isNullish (180-182)
src/util/types.ts (2)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/scale/CustomScaleDefinition.ts (1)
  • CustomScaleDefinition (13-63)
src/state/selectors/tooltipSelectors.ts (3)
src/util/types.ts (2)
  • TickItem (827-832)
  • CategoricalDomainItem (732-732)
src/util/isWellBehavedNumber.ts (1)
  • isWellBehavedNumber (1-3)
src/util/DataUtils.ts (1)
  • isNotNil (202-204)
test/util/ChartUtils.spec.tsx (5)
src/index.ts (1)
  • CustomScaleDefinition (97-97)
src/util/scale/CustomScaleDefinition.ts (1)
  • CustomScaleDefinition (13-63)
src/util/ChartUtils.ts (2)
  • AxisPropsNeededForTicksGenerator (152-167)
  • getBandSizeOfAxis (650-678)
src/state/cartesianAxisSlice.ts (1)
  • defaultAxisId (12-12)
src/state/selectors/axisSelectors.ts (1)
  • BaseAxisWithScale (2051-2051)
⏰ 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). (2)
  • GitHub Check: Build, Test, Pack
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (69)
test/util/ChartUtils/checkDomainOfScale.spec.ts (1)

168-178: LGTM!

The test correctly verifies that checkDomainOfScale normalizes domains with more than 2 elements while preserving domains with 2 or fewer elements. The before/after comparison logic is sound.

test/util/ChartUtils/getCateCoordinateOfLine.spec.ts (1)

3-6: LGTM!

The import path update aligns with the scale definition refactor. The typed mock with @ts-expect-error is appropriate for test purposes, as the mock implements only the call signature without the full RechartsScale interface (which requires domain(), range(), etc.).

src/state/selectors/polarScaleSelectors.ts (1)

27-27: LGTM!

Import path update aligns with the scale definition refactor, moving RechartsScale to its dedicated module.

test/helper/toBeRechartsScale.ts (1)

3-4: LGTM!

Import path update aligns with the scale definition refactor.

src/polar/PolarRadiusAxis.tsx (1)

27-27: LGTM!

Import path update aligns with the scale definition refactor.

test/state/selectors/selectAxisScale.spec.tsx (1)

40-40: Clarify why the call count assertion was removed.

The commented-out call count assertion removes an important performance check. Per coding guidelines, verifying selector call counts helps spot unnecessary re-renders.

If the call count intentionally changed due to the scale refactor, please:

  1. Document why the call count changed
  2. Update the assertion with the new expected count instead of removing it
  3. Consider whether the change indicates a performance regression

If this assertion is no longer valid, please remove the commented line entirely rather than leaving it in the code.

src/cartesian/ReferenceArea.tsx (1)

22-22: LGTM!

Import path update aligns with the scale definition refactor.

storybook/storybook-addon-recharts/inspectors/generic/ScaleInspector.tsx (1)

3-3: LGTM: Import path updated to new scale module.

The import path has been correctly updated to reference the new dedicated RechartsScale module, aligning with the PR's refactoring of scale definitions.

scripts/snapshots/es6Files.txt (1)

240-241: LGTM: Snapshot correctly tracks new scale modules.

The snapshot file properly includes the new CustomScaleDefinition and RechartsScale modules under the es6/util/scale/ directory, ensuring build consistency.

src/index.ts (1)

97-97: LGTM: CustomScaleDefinition added to public API.

The new CustomScaleDefinition type is correctly exported as part of the public API, enabling users to provide custom scale implementations while maintaining a stable external interface.

src/polar/PolarAngleAxis.tsx (2)

26-27: LGTM: Imports updated for scale type split.

The addition of both RechartsScale and CustomScaleDefinition imports supports the external/internal scale type separation pattern.


66-66: LGTM: Public prop correctly uses CustomScaleDefinition.

The scale prop type has been appropriately changed to use CustomScaleDefinition for the public API. Meanwhile, InsideProps at line 107 correctly retains RechartsScale for internal use. This demonstrates the intended pattern: stable external types for users, flexible internal types for implementation.

test/helper/expectScale.ts (1)

4-4: LGTM: Test helper import updated to new scale module.

The import path has been correctly updated to reference the dedicated RechartsScale module. Test helpers appropriately use the internal RechartsScale type for validation.

src/state/selectors/radarSelectors.ts (1)

12-12: LGTM: Imports reorganized for scale module separation.

The imports have been appropriately split: utility functions remain imported from ChartUtils while RechartsScale is imported from its dedicated module. Selector logic remains unchanged.

Also applies to: 16-16

scripts/snapshots/libFiles.txt (1)

240-241: LGTM: Snapshot correctly tracks new CommonJS scale modules.

The snapshot file properly includes the new CustomScaleDefinition and RechartsScale modules in the lib (CommonJS) build output, ensuring build consistency across module formats.

scripts/snapshots/typesFiles.txt (1)

240-241: LGTM: Snapshot correctly tracks new type declarations.

The snapshot file properly includes the type declaration files for CustomScaleDefinition and RechartsScale, ensuring TypeScript consumers have access to proper type definitions for the new scale modules.

test/state/selectors/axisSelectors.spec.tsx (1)

2453-2484: expectedXAxis typing matches new BaseAxisWithScale contract

Using Omit<XAxisSettings, 'scale'> & BaseAxisWithScale correctly avoids a duplicate scale property while asserting the richer internal axis+scale shape the selector returns. The structure matches the asserted object below, so this refinement looks good.

src/cartesian/Line.tsx (1)

923-936: Coercing undefined scale outputs to null is correct

Changing the horizontal-branch point construction to y: y ?? null ensures LinePointItem.y is always number | null even when the scale returns undefined, aligning with the type and gap-handling semantics without affecting valid numeric cases.

test/cartesian/Area.spec.tsx (1)

973-980: OK to suppress type errors for intentionally incomplete axis mocks

The added // @ts-expect-error incomplete mock annotations around scale (and type) on BaseAxisWithScale test doubles are appropriate here: these tests exercise getBaseValue’s runtime behavior with minimal axis mocks and don’t warrant fully populating the axis shape after the RechartsScale typing changes.

Also applies to: 1029-1035, 1047-1053, 1104-1110, 1121-1127, 1181-1187, 1198-1204

test/component/Tooltip/itemSorter.spec.tsx (1)

1311-1434: Aligning radial tooltip payload expectations with explicit startAngle: 0

Updating the expected tooltip payloads to include startAngle: 0 for RadialBar-derived entries matches the new sector metadata shape while keeping the rest of the assertions intact. This keeps the tests faithful to the runtime objects without changing itemSorter behavior.

Also applies to: 1475-1597, 1628-1760, 1789-1917

src/state/selectors/radialBarSelectors.ts (1)

14-15: RechartsScale import refactor preserves selector behavior

Switching RechartsScale to the dedicated util/scale/RechartsScale module and narrowing the ChartUtils import list keeps the scale typing consistent with the new abstraction without altering how selectRadiusAxisWithScale/selectAngleAxisWithScale build BaseAxisWithScale. No further changes needed.

Also applies to: 37-51, 73-90

src/cartesian/ZAxis.tsx (1)

3-9: ZAxis scale typing correctly migrated to CustomScaleDefinition

Allowing scale?: ScaleType | CustomScaleDefinition | undefined and importing CustomScaleDefinition from the shared scale module aligns ZAxis with the new external scale contract, while remaining backward compatible with string scale types and implicit defaults.

Also applies to: 61-71

src/cartesian/ErrorBar.tsx (1)

169-188: Guarding against null scale outputs in error bar segments

The added xMin/xMax and yMin/yMax null checks ensure error bar segments are only rendered when the scale returns valid numeric coordinates, avoiding lines with undefined attributes while preserving existing behavior for well-formed data.

Also applies to: 189-207

test/cartesian/CartesianAxis.spec.tsx (1)

5-6: Tests now validate CartesianAxis against CustomScaleDefinition

Typing exampleScale as CustomScaleDefinition<number> and importing it from the public entry point updates the tests to reflect the new external scale contract. Using scaleLinear() as the concrete implementation remains appropriate and structurally compatible.

Also applies to: 20-20

test/helper/mockAxes.ts (1)

3-5: LGTM!

The import correctly uses the public API entry point ('../../src' resolves to src/index.ts), and CustomScaleDefinition<number> is the appropriate type for user-provided scales. The d3 scaleLinear() function returns a scale compatible with this interface.

src/polar/Radar.tsx (2)

239-241: LGTM!

The nullish coalescing operators (?? 0) correctly handle the case where scale() returns undefined (as per the CustomScaleDefinition interface). The isNullish(pointValue) guard provides an early fallback to 0 for null/undefined values before invoking the scale, which is appropriate defensive coding.


264-276: LGTM!

The null-safety pattern for baseValue radius calculation is consistent with the earlier pointValue handling at line 241. This ensures robust behavior when scale returns undefined.

src/state/cartesianAxisSlice.ts (1)

20-25: LGTM!

The type change from RechartsScale to CustomScaleDefinition for BaseCartesianAxis.scale correctly reflects the PR's objective: CustomScaleDefinition is the external/public type for user-provided props, while RechartsScale is the internal type. The updated documentation clarifies this is user-defined axis settings.

src/cartesian/Bar.tsx (1)

976-1006: LGTM!

The null checks for baseValueScale and currentValueScale in both horizontal (lines 976-980) and vertical (lines 1002-1006) code paths correctly handle the case where scale() returns undefined. The early return of null ensures bars with uncomputable coordinates are filtered out via .filter(Boolean) at line 1047.

src/state/selectors/tooltipSelectors.ts (2)

355-368: LGTM!

The tick generation now correctly guards against invalid scale results using isWellBehavedNumber (which checks Number.isFinite). This filters out undefined, NaN, and Infinity values that could result from the scale function, ensuring only valid numeric coordinates are used for ticks.


372-388: LGTM!

The domain-based tick generation mirrors the categorical domain pattern with the same isWellBehavedNumber guard. The CategoricalDomainItem type annotation provides proper typing for the domain entries.

src/cartesian/Area.tsx (3)

1030-1030: Good null-safety improvement for scale results.

The ?? null fallback correctly handles the case where yAxis.scale(value1) returns undefined, ensuring consistent null values for missing coordinates.


1037-1037: Consistent null-safety for vertical layout.

Same defensive pattern applied correctly for the x-coordinate in vertical layout.


1044-1067: Proper handling of baseLine with null-safety and fallback.

The expanded baseLine type now correctly accounts for undefined, and the mapping logic properly applies ?? null for scale results. The final baseLine ?? 0 ensures a valid fallback is always returned.

src/util/scale/CustomScaleDefinition.ts (1)

1-63: Well-designed public scale interface.

The CustomScaleDefinition interface is cleanly designed with:

  • Clear separation of getter/setter overloads for domain and range
  • Proper documentation about immutability concerns
  • Optional methods for scale-specific features (bandwidth, ticks)
  • Correct return type number | undefined for the callable signature
src/polar/RadialBar.tsx (4)

570-575: Good explicit type annotations for local variables.

The explicit types for value, innerRadius, outerRadius, startAngle, endAngle, and backgroundSector improve readability and maintainability.


588-589: Good fallback handling for scale results.

Using ?? rootStartAngle and ?? rootEndAngle as fallbacks ensures the angles have sensible defaults when the scale returns undefined.


598-617: Properly guarded computation block.

The null checks for innerRadius, endAngle, and startAngle before computing derived values prevent arithmetic on null/undefined values.


629-637: Consistent null-safety for non-radial layout.

Same defensive pattern applied for the arc layout path.

test/util/ChartUtils.spec.tsx (2)

35-39: Good explicit typing for scale in tests.

Using CustomScaleDefinition<string> provides clear type annotation for the string-domain scale, improving test clarity and type safety.


114-126: Expanded axis mock objects improve type coverage.

Adding all required properties for BaseAxisWithScale ensures the test objects properly match the expected interface shape.

src/util/scale/RechartsScale.ts (3)

8-52: Well-documented internal scale interface.

The RechartsScale interface is properly designed as an immutable internal representation:

  • Clear documentation about immutability constraints
  • No setter methods exposed
  • Forward-looking comment about better typing in 4.0

75-99: Good encapsulation of scale creation logic.

The makeRechartsScale function properly:

  1. Uses copy() to avoid mutating user-provided scales (line 81)
  2. Returns undefined for invalid inputs
  3. Encapsulates the mutation from checkDomainOfScale (acknowledged in comment)

The mutation on line 90 is intentional and well-documented. The internal mutation is acceptable since getD3ScaleFromType creates a fresh scale instance.


80-81: The chained method return type is compatible with RechartsScale<Domain>. D3 scales follow the method chaining pattern where setter methods return the scale itself, and the returned d3-scale is structurally compatible with the RechartsScale<Domain> interface, which requires domain(), range(), and a callable function signature—all of which d3-scale instances provide.

src/util/types.ts (4)

35-35: LGTM!

The import of CustomScaleDefinition from the new scale module is correctly structured and aligns with the PR's goal of separating external/public scale types from internal ones.


160-182: Well-structured type definitions for scale types.

The separation of D3ScaleType (listing d3-scale string literals) and ScaleType (adding 'auto') provides a clean public API. The JSDoc comment appropriately references CustomScaleDefinition for users who need custom scales.


732-734: Good addition of categorical domain types.

CategoricalDomainItem correctly captures the possible domain value types (number, string, Date), and CategoricalDomain as a ReadonlyArray enforces immutability appropriately.


755-755: LGTM!

The updated scale prop type correctly accepts either a string-based ScaleType or a user-provided CustomScaleDefinition function, which is the core goal of this PR.

src/state/selectors/axisSelectors.ts (11)

18-25: LGTM!

The new type imports (CategoricalDomainItem, D3ScaleType, ScaleType) are correctly sourced from ../../util/types and align with the updated type definitions.


89-89: LGTM!

The import of makeRechartsScale and RechartsScale from the new dedicated scale module follows the PR's refactoring pattern of centralizing scale utilities.


1093-1133: LGTM!

The updated combineRealScaleType function correctly returns ScaleType | undefined and properly uses isSupportedScaleName to validate the generated scale name before returning it.


1144-1158: Good centralization of scale construction.

The updated combineScaleFunction properly delegates scale construction to makeRechartsScale, which handles both user-provided custom scales and string-based scale types. This aligns well with the PR's goal of separating scale definition concerns.


1829-1836: Helpful documentation for related implementations.

The JSDoc comments documenting the "four horsemen of tick generation" provide useful navigation for developers working with tick generation logic across the codebase.

Also applies to: 1953-1960


1870-1885: Good defensive null-safety for tick coordinate calculation.

The added isWellBehavedNumber check properly handles cases where the scale returns undefined (as now specified by the RechartsScale interface), preventing NaN coordinates from propagating into tick items.


1890-1904: Consistent null-safety pattern applied.

The categorical domain tick mapping correctly applies the same isWellBehavedNumber validation and isNotNil filtering pattern.


1916-1932: Consistent null-safety in domain-based tick generation.

The fallback path for generating ticks from scale.domain() properly validates scaled values and filters out invalid entries.


1984-1997: Parallel null-safety implementation in combineGraphicalItemTicks.

The same defensive patterns are correctly applied in combineGraphicalItemTicks, maintaining consistency with combineAxisTicks.

Also applies to: 2010-2026


2046-2051: Clear type definition for internal axis representation.

The BaseAxisWithScale type correctly documents that it represents an axis with an already-computed scale function, replacing the union type with just RechartsScale.


2082-2082: Consistent type pattern for ZAxis.

ZAxisWithScale follows the same pattern as BaseAxisWithScale, maintaining type consistency across axis types.

src/util/ChartUtils.ts (10)

15-15: LGTM!

The updated import correctly includes isNotNil which is used for filtering null values from tick arrays.


23-23: LGTM!

The CategoricalDomainItem import aligns with the new type definitions and is used appropriately in the tick generation functions.


42-42: LGTM!

The import of RechartsScale from the new dedicated module follows the PR's refactoring pattern.


170-176: Helpful cross-reference documentation.

The JSDoc listing the four related tick generation implementations aids maintainability.


210-230: Good null-safety for grid tick generation.

The validation using isWellBehavedNumber properly handles cases where the scale returns undefined, preventing invalid coordinates from being included in the result.


234-248: Consistent null-safety in categorical domain handling.

The same defensive pattern is correctly applied to the categorical domain branch.


250-261: LGTM!

The numeric ticks branch correctly validates scale results before constructing tick items.


264-280: Consistent handling for domain-based ticks.

The fallback path using scale.domain() properly validates and filters invalid entries, completing the null-safety implementation across all tick generation paths in this function.


515-515: LGTM!

The axis scale property is correctly typed as RechartsScale, aligning with the internal type representation.


564-571: Good defensive handling for bar coordinate calculation.

The added null checks for both the value and scaled result properly handle edge cases where the scale returns undefined. The use of isNumber is appropriate here to validate the scaled output before performing arithmetic operations.

const stackedDomain: ReadonlyArray<number> = stackedData ? numericAxis.scale.domain() : null;
const baseValue = getBaseValueOfBar({ numericAxis });
const stackedBarStart: number = numericAxis.scale(baseValue);
const stackedBarStart: number | undefined = numericAxis.scale(baseValue);
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 | 🟠 Major

Type mismatch: stackedBarStart may be undefined but BarRectangleItem requires number.

After this change, numericAxis.scale(baseValue) can return undefined, making stackedBarStart: number | undefined. However, the BarRectangleItem interface at line 111 declares stackedBarStart: number (non-optional). This creates a type mismatch when constructing the barRectangleItem at line 1032.

Consider either:

  1. Updating BarRectangleItem.stackedBarStart to be number | undefined, or
  2. Adding a fallback: const stackedBarStart: number = numericAxis.scale(baseValue) ?? 0;
-  const stackedBarStart: number | undefined = numericAxis.scale(baseValue);
+  const stackedBarStart: number = numericAxis.scale(baseValue) ?? 0;
📝 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
const stackedBarStart: number | undefined = numericAxis.scale(baseValue);
const stackedBarStart: number = numericAxis.scale(baseValue) ?? 0;
🤖 Prompt for AI Agents
In src/cartesian/Bar.tsx around line 952, numericAxis.scale(baseValue) can
return undefined so stackedBarStart is number | undefined which conflicts with
BarRectangleItem.stackedBarStart (declared as number); either (A) update the
BarRectangleItem type (where it's declared) to stackedBarStart: number |
undefined, or (B) keep the type and coerce the value at line 952 to a number by
providing a fallback (e.g., const stackedBarStart: number =
numericAxis.scale(baseValue) ?? 0) and ensure any downstream logic handles the
fallback appropriately.

});
const size = z !== '-' ? zAxis.scale(z) : defaultZ;
const radius = Math.sqrt(Math.max(size, 0) / Math.PI);
const radius = size == null ? 0 : Math.sqrt(Math.max(size, 0) / Math.PI);
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 | 🟡 Minor

Type inconsistency between runtime guard and interface definition.

The null check size == null ? 0 guards against nullish values, but ScatterPointItem.size is typed as number (Line 113), not nullable. If size can be null/undefined at runtime (e.g., when zAxis.scale(z) returns undefined), update the interface to reflect this.

Apply this diff to align the type with runtime behavior:

   /**
    * ScatterPointItem size is an abstract number that is used to calculate the radius of the point.
    * It's not the radius itself, but rather a value that is used to calculate the radius.
    * Interacts with the zAxis range.
    */
-  size: number;
+  size: number | undefined;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/cartesian/Scatter.tsx around line 741 (and update the ScatterPointItem
definition at line 113), the runtime uses a nullish guard for size but the
interface types size as a non-nullable number; change the ScatterPointItem.size
type to allow null/undefined (e.g., size?: number | null or size: number | null)
so it matches runtime behavior, update any related usages/props/types to handle
the optional value accordingly, and run type checks to fix any resulting
callsites that assume size is always a number.

@codecov
Copy link

codecov bot commented Dec 16, 2025

Codecov Report

❌ Patch coverage is 90.21739% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.75%. Comparing base (b9835fe) to head (e63e825).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/polar/RadialBar.tsx 68.75% 10 Missing ⚠️
src/util/ChartUtils.ts 90.32% 6 Missing ⚠️
src/state/selectors/axisSelectors.ts 94.93% 4 Missing ⚠️
src/util/scale/RechartsScale.ts 88.23% 4 Missing ⚠️
src/cartesian/Bar.tsx 81.81% 2 Missing ⚠️
src/polar/Radar.tsx 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6783      +/-   ##
==========================================
- Coverage   93.81%   93.75%   -0.06%     
==========================================
  Files         516      518       +2     
  Lines       43979    44094     +115     
  Branches     5005     5035      +30     
==========================================
+ Hits        41257    41340      +83     
- Misses       2716     2747      +31     
- Partials        6        7       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codecov
Copy link

codecov bot commented Dec 16, 2025

Bundle Report

Changes will increase total bundle size by 12.26kB (0.45%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.18MB 6.29kB (0.54%) ⬆️
recharts/bundle-es6 1.02MB 5.12kB (0.51%) ⬆️
recharts/bundle-umd 523.27kB 856 bytes (0.16%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-umd

Assets Changed:

Asset Name Size Change Total Size Change (%)
Recharts.js 856 bytes 523.27kB 0.16%
view changes for bundle: recharts/bundle-es6

Assets Changed:

Asset Name Size Change Total Size Change (%)
state/selectors/axisSelectors.js -45 bytes 53.64kB -0.08%
cartesian/Area.js 538 bytes 27.5kB 2.0%
cartesian/Bar.js 204 bytes 26.08kB 0.79%
cartesian/Line.js 38 bytes 24.74kB 0.15%
cartesian/Scatter.js 19 bytes 22.58kB 0.08%
polar/RadialBar.js 410 bytes 19.68kB 2.13%
util/ChartUtils.js 602 bytes 18.36kB 3.39%
polar/Radar.js 340 bytes 16.27kB 2.13%
state/selectors/tooltipSelectors.js 666 bytes 14.21kB 4.92%
cartesian/ErrorBar.js 184 bytes 9.18kB 2.04%
util/types.js 173 bytes 6.66kB 2.67%
state/cartesianAxisSlice.js 51 bytes 5.4kB 0.95%
util/scale/RechartsScale.js (New) 1.93kB 1.93kB 100.0% 🚀
util/scale/CustomScaleDefinition.js (New) 10 bytes 10 bytes 100.0% 🚀
view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
state/selectors/axisSelectors.js 111 bytes 63.55kB 0.17%
cartesian/Area.js 538 bytes 29.37kB 1.87%
cartesian/Bar.js 204 bytes 27.79kB 0.74%
cartesian/Line.js 38 bytes 26.35kB 0.14%
cartesian/Scatter.js 19 bytes 24.2kB 0.08%
polar/RadialBar.js 410 bytes 21.14kB 1.98%
util/ChartUtils.js 741 bytes 20.45kB 3.76%
polar/Radar.js 340 bytes 17.74kB 1.95%
state/selectors/tooltipSelectors.js 730 bytes 17.68kB 4.31%
cartesian/ErrorBar.js 184 bytes 10.19kB 1.84%
util/types.js 173 bytes 7.08kB 2.51%
state/cartesianAxisSlice.js 51 bytes 6.33kB 0.81%
util/scale/RechartsScale.js (New) 2.73kB 2.73kB 100.0% 🚀
util/scale/CustomScaleDefinition.js (New) 13 bytes 13 bytes 100.0% 🚀

@github-actions
Copy link
Contributor

Staging Deployment Details

These deployments will remain available for 30 days.

To update snapshots: Comment /update-snapshots on this PR to automatically update the baseline screenshots.

);

/**
* Of on four almost identical implementations of tick generation.
Copy link
Member

Choose a reason for hiding this comment

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

nit: one of?


/**
* Of on four almost identical implementations of tick generation.
* The four horsemen of tick generation are:
Copy link
Member

Choose a reason for hiding this comment

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

lmaooo

Copy link
Member

Choose a reason for hiding this comment

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

does this break if someone uses a method from a d3 scale prior to passing it in and then pass it in?

It shouldn't

Something that I've done in the past is used https://d3js.org/d3-scale/linear#linear_invert

In this case I would define my scale with a given domain/range and then because recharts is using that same scale use it to convert X and Y values to my scale. This should still work, cool

Copy link
Member

Choose a reason for hiding this comment

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

and its always easier to add more later

Copy link
Member

Choose a reason for hiding this comment

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

what happens if D3 breaks us here?

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