Skip to content

fix: implement reverseStackOrder prop in v3 Redux architecture#6644

Merged
ckifer merged 1 commit intorecharts:mainfrom
j-shimizu111:fix/reverse-stack-order-v3
Nov 18, 2025
Merged

fix: implement reverseStackOrder prop in v3 Redux architecture#6644
ckifer merged 1 commit intorecharts:mainfrom
j-shimizu111:fix/reverse-stack-order-v3

Conversation

@j-shimizu111
Copy link
Contributor

@j-shimizu111 j-shimizu111 commented Nov 17, 2025

Description

The reverseStackOrder prop was defined in types but not implemented in the v3 Redux-based architecture, causing it to have no effect. This PR restores the functionality that worked correctly in v2.15.4.

Changes

This PR implements reverseStackOrder throughout the Redux architecture:

  • Redux State: Added reverseStackOrder to UpdatableChartOptions in rootPropsSlice.ts
  • Chart Props Flow: Updated CartesianChart and PolarChart to pass reverseStackOrder through ReportChartProps
  • Selector Logic: Modified combineStackGroups in axisSelectors.ts to reverse stack order when enabled
  • Selector Integration: Updated tooltipSelectors.ts and radialBarSelectors.ts to include reverseStackOrder parameter
  • Storybook: Added reverseStackOrder control to BarChart Stacked story for easy testing
  • Tests: Added comprehensive test coverage for both reverseStackOrder={true} and reverseStackOrder={false} cases

Visual Demonstration

The fix can be tested in Storybook by navigating to API > chart > BarChart > Stacked and toggling the reverseStackOrder control. When enabled, the stacked bars render in reverse order (affecting SVG layering).

Before (v3 without fix)

2025-11-17.13.16.40.mov

After (v3 with fix)

2025-11-17.13.45.16.mov

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • I have added a storybook story or VR test, or extended an existing story or VR test to show my changes

🤖 Generated with Claude Code

Co-Authored-By: Claude noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • Stacked bar and radial charts gain a new "reverse stack order" option to invert the draw/order of stacked series.
  • Documentation

    • Storybook examples updated to showcase the new stack-order option.
  • Tests

    • Unit and visual tests added to verify behavior with reverse stack order enabled and disabled.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 17, 2025

Walkthrough

Adds a boolean reverseStackOrder root prop: persisted in Redux, exposed via a selector, forwarded through chart components into ReportChartProps, used by stack-group combiners to optionally reverse graphical item order; tests and a story were added.

Changes

Cohort / File(s) Change Summary
Redux state & slice
src/state/rootPropsSlice.ts
Added reverseStackOrder: boolean to UpdatableChartOptions, initialized it in initialState, and applied it in the updateOptions reducer.
Root selectors
src/state/selectors/rootPropsSelectors.ts
Added exported selector selectReverseStackOrder(state) returning state.rootProps.reverseStackOrder.
Stacking selectors & logic
src/state/selectors/axisSelectors.ts, src/state/selectors/radialBarSelectors.ts, src/state/selectors/tooltipSelectors.ts
Imported selectReverseStackOrder; updated selectStackGroups inputs to include it; changed combineStackGroups signature to accept reverseStackOrder and reverse graphicalItems/dataKeys when true.
Chart components
src/chart/CartesianChart.tsx, src/chart/PolarChart.tsx
Forwarded reverseStackOrder from chart/root props into ReportChartProps usages.
Stories
storybook/stories/API/chart/BarChart.stories.tsx
Added reverseStackOrder: false to the Stacked story args.
Unit & visual tests
test/state/selectors/selectStackGroups.spec.tsx, test-vr/tests/BarChart.reverseStackOrder.spec-vr.tsx
Added selector tests for reverseStackOrder true/false and two Playwright CT visual tests comparing screenshots with the flag off and on.

Sequence Diagram(s)

sequenceDiagram
    participant UI as Chart Component
    participant Redux as Redux State
    participant Selectors as selectStackGroups
    participant Combiner as combineStackGroups
    participant Renderer as ReportChart / Renderer

    UI->>Redux: updateOptions({ reverseStackOrder })
    UI->>Redux: read rootProps (incl. reverseStackOrder)
    Redux->>Selectors: selectStackGroups(state, ...)
    Selectors->>Combiner: (displayedData, items, stackOffsetType, reverseStackOrder)
    alt reverseStackOrder = true
        Note right of Combiner `#f8d7da`: Reverse graphicalItems before computing dataKeys
        Combiner->>Renderer: StackGroup[] (reversed order)
    else reverseStackOrder = false
        Note right of Combiner `#d1e7dd`: Keep original graphical order
        Combiner->>Renderer: StackGroup[] (original order)
    end
    Renderer->>UI: rendered chart
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review combineStackGroups for correct handling of empty/single-item stacks and index/key stability.
  • Verify all selector dependency arrays and memoization include selectReverseStackOrder.
  • Confirm ReportChartProps type updated consistently where used and prop forwarded in all chart entry points.

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • ckifer
  • PavelVanecek

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: implementing the reverseStackOrder prop within the v3 Redux architecture. It accurately reflects the primary objective of restoring previously-defined but non-functional behavior.
Description check ✅ Passed The description follows the template structure well, includes detailed explanation of changes across multiple files, provides visual demonstrations with before/after video links, completes the checklist, and specifies the type of change (bug fix). All required sections are addressed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 48b39f1 and c3ae91a.

⛔ Files ignored due to path filters (6)
  • test-vr/__snapshots__/tests/BarChart.reverseStackOrder.spec-vr.tsx-snapshots/StackedBarChart-with-reverseStackOrder-false-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/BarChart.reverseStackOrder.spec-vr.tsx-snapshots/StackedBarChart-with-reverseStackOrder-false-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/BarChart.reverseStackOrder.spec-vr.tsx-snapshots/StackedBarChart-with-reverseStackOrder-false-1-webkit-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/BarChart.reverseStackOrder.spec-vr.tsx-snapshots/StackedBarChart-with-reverseStackOrder-true-1-chromium-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/BarChart.reverseStackOrder.spec-vr.tsx-snapshots/StackedBarChart-with-reverseStackOrder-true-1-firefox-linux.png is excluded by !**/*.png
  • test-vr/__snapshots__/tests/BarChart.reverseStackOrder.spec-vr.tsx-snapshots/StackedBarChart-with-reverseStackOrder-true-1-webkit-linux.png is excluded by !**/*.png
📒 Files selected for processing (10)
  • src/chart/CartesianChart.tsx (1 hunks)
  • src/chart/PolarChart.tsx (1 hunks)
  • src/state/rootPropsSlice.ts (3 hunks)
  • src/state/selectors/axisSelectors.ts (4 hunks)
  • src/state/selectors/radialBarSelectors.ts (2 hunks)
  • src/state/selectors/rootPropsSelectors.ts (1 hunks)
  • src/state/selectors/tooltipSelectors.ts (2 hunks)
  • storybook/stories/API/chart/BarChart.stories.tsx (1 hunks)
  • test-vr/tests/BarChart.reverseStackOrder.spec-vr.tsx (1 hunks)
  • test/state/selectors/selectStackGroups.spec.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/state/selectors/rootPropsSelectors.ts
  • src/state/selectors/axisSelectors.ts
  • src/state/selectors/radialBarSelectors.ts
  • test/state/selectors/selectStackGroups.spec.tsx
  • src/chart/CartesianChart.tsx
  • src/state/rootPropsSlice.ts
🧰 Additional context used
🧬 Code graph analysis (2)
src/state/selectors/tooltipSelectors.ts (1)
src/state/selectors/rootPropsSelectors.ts (2)
  • selectStackOffsetType (11-11)
  • selectReverseStackOrder (12-12)
test-vr/tests/BarChart.reverseStackOrder.spec-vr.tsx (1)
storybook/stories/data/Page.ts (1)
  • pageData (259-259)
🔇 Additional comments (6)
storybook/stories/API/chart/BarChart.stories.tsx (1)

101-101: LGTM! Storybook control added for manual testing.

The addition of reverseStackOrder: false to the Stacked story args enables interactive testing of the new prop. Since getStoryArgsFromArgsTypesObject(BarChartProps) is used, the control should be automatically generated in the Storybook UI, allowing users to toggle between true/false values.

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

54-54: LGTM! Selector import added correctly.

The import of selectReverseStackOrder from rootPropsSelectors is properly added to support the tooltip stack groups calculation.


173-175: LGTM! Tooltip stack groups now respect reverseStackOrder.

The selectReverseStackOrder selector is correctly added to the dependency array, ensuring that combineStackGroups receives the reverseStackOrder flag to properly compute tooltip stack group ordering. This integration follows the same pattern used in axisSelectors.ts and radialBarSelectors.ts.

test-vr/tests/BarChart.reverseStackOrder.spec-vr.tsx (1)

6-34: LGTM! Comprehensive visual regression tests for reverseStackOrder.

The two VR tests provide complete coverage for the reverseStackOrder feature:

  • Test 1 verifies the default behavior with reverseStackOrder={false}
  • Test 2 verifies the reversed behavior with reverseStackOrder (truthy shorthand)

Both tests use identical chart configurations (same data, Bar components, and layout), ensuring that the screenshots will clearly capture the visual differences in SVG layering caused by the prop. The use of explicit false in line 8 vs. truthy shorthand in line 23 is idiomatic React and perfectly acceptable.

src/chart/PolarChart.tsx (2)

25-25: LGTM! Default value consistently set to false.

The reverseStackOrder: false default is properly defined in the defaultProps object, ensuring backward-compatible behavior for existing charts.


94-94: LGTM! Prop correctly forwarded to ReportChartProps.

The reverseStackOrder prop is properly threaded through to ReportChartProps, following the same pattern as other chart props like stackOffset and barCategoryGap. This ensures the Redux state receives the prop value for use in stack group calculations.


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: 0

🧹 Nitpick comments (1)
src/state/selectors/axisSelectors.ts (1)

612-647: Implementation looks correct.

The reversal logic properly creates a shallow copy before reversing, ensuring no mutation of the original array. The orderedGraphicalItems variable is used consistently for both dataKeys derivation and the final result.

Consider adding JSDoc documentation for the reverseStackOrder parameter to help future maintainers understand its purpose:

+/**
+ * Combines stack groups from graphical items.
+ * @param displayedData - The displayed stacked data
+ * @param items - Stacked graphical items to group
+ * @param stackOffsetType - The stack offset type (e.g., 'expand', 'silhouette')
+ * @param reverseStackOrder - When true, reverses the order of items within each stack
+ * @returns All stack groups indexed by stack ID
+ */
 export const combineStackGroups = (
   displayedData: DisplayedStackedData,
   items: ReadonlyArray<DefinitelyStackedGraphicalItem>,
   stackOffsetType: StackOffsetType,
   reverseStackOrder: boolean,
 ): AllStackGroups => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d92152 and 975faa4.

📒 Files selected for processing (9)
  • src/chart/CartesianChart.tsx (1 hunks)
  • src/chart/PolarChart.tsx (1 hunks)
  • src/state/rootPropsSlice.ts (3 hunks)
  • src/state/selectors/axisSelectors.ts (4 hunks)
  • src/state/selectors/radialBarSelectors.ts (2 hunks)
  • src/state/selectors/rootPropsSelectors.ts (1 hunks)
  • src/state/selectors/tooltipSelectors.ts (2 hunks)
  • storybook/stories/API/chart/BarChart.stories.tsx (1 hunks)
  • test/state/selectors/selectStackGroups.spec.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
src/state/selectors/rootPropsSelectors.ts (1)
src/state/store.ts (1)
  • RechartsRootState (94-94)
test/state/selectors/selectStackGroups.spec.tsx (5)
src/context/PanoramaContext.tsx (1)
  • useIsPanorama (6-6)
test/helper/selectorTestHelpers.tsx (1)
  • useAppSelectorWithStableTest (86-93)
src/state/selectors/axisSelectors.ts (1)
  • selectStackGroups (654-662)
test/_data.ts (1)
  • PageData (4-11)
test/helper/expectLastCalledWith.ts (1)
  • expectLastCalledWith (14-34)
src/state/selectors/radialBarSelectors.ts (1)
src/state/selectors/rootPropsSelectors.ts (2)
  • selectStackOffsetType (11-11)
  • selectReverseStackOrder (12-12)
src/state/selectors/axisSelectors.ts (3)
src/util/stacks/getStackSeriesIdentifier.ts (1)
  • getStackSeriesIdentifier (14-18)
src/util/ChartUtils.ts (1)
  • getStackedData (427-441)
src/state/selectors/rootPropsSelectors.ts (2)
  • selectStackOffsetType (11-11)
  • selectReverseStackOrder (12-12)
src/state/selectors/tooltipSelectors.ts (1)
src/state/selectors/rootPropsSelectors.ts (2)
  • selectStackOffsetType (11-11)
  • selectReverseStackOrder (12-12)
🔇 Additional comments (14)
src/chart/CartesianChart.tsx (1)

77-77: LGTM! Prop forwarding is consistent.

The reverseStackOrder prop is correctly forwarded to ReportChartProps, following the same pattern as other chart options.

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

31-31: LGTM! Selector import is correct.

The selectReverseStackOrder import follows the established pattern for root props selectors.


352-354: LGTM! Selector dependency correctly wired.

The selectReverseStackOrder is properly added to the selectStackGroups dependency list, enabling combineStackGroups to access the reverse stacking flag. This change is consistent with similar updates in axisSelectors.ts and tooltipSelectors.ts.

storybook/stories/API/chart/BarChart.stories.tsx (1)

101-101: LGTM! Storybook control properly configured.

The reverseStackOrder control is appropriately added to the Stacked story with the correct default value, enabling manual testing of the feature.

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

54-54: LGTM! Import correctly added.

The selectReverseStackOrder import is properly placed with other root props selectors.


173-175: LGTM! Tooltip stack groups will respect reverse order.

The selectReverseStackOrder is correctly added to selectTooltipStackGroups dependencies, ensuring tooltips display stacked data in the correct order when the flag is enabled.

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

319-464: LGTM! Comprehensive test coverage for reverseStackOrder.

The test suite thoroughly validates both reverseStackOrder={true} and reverseStackOrder={false} scenarios, verifying that:

  • Graphical items order is correctly reversed/maintained
  • Stacked data order matches the graphical items order
  • The expected stacked values are accurate

The tests follow established patterns from the existing test suite and provide solid coverage for the new feature.

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

12-12: LGTM! Selector correctly implemented.

The selectReverseStackOrder selector follows the established pattern for root props selectors and has the correct type signature.

src/chart/PolarChart.tsx (1)

94-94: LGTM! Prop forwarding is consistent with CartesianChart.

The reverseStackOrder prop is correctly forwarded to ReportChartProps, maintaining consistency with the CartesianChart implementation.

src/state/rootPropsSlice.ts (3)

28-32: LGTM! Clear documentation for the new field.

The JSDoc comment clearly explains the reverseStackOrder behavior, helpfully clarifying that it affects SVG layering rather than x position.


46-46: LGTM! Initial state correctly set.

The default value of false is appropriate, maintaining backward compatibility with existing behavior.


64-64: LGTM! Reducer correctly propagates the value.

The updateOptions reducer properly assigns the reverseStackOrder value, following the established pattern for other updatable chart options.

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

75-80: LGTM!

The import of selectReverseStackOrder is correctly structured and follows the existing pattern for similar selectors.


654-662: LGTM!

The selector integration correctly adds selectReverseStackOrder as an input dependency and passes it to combineStackGroups. The wiring is clean and follows the existing selector pattern.

@codecov
Copy link

codecov bot commented Nov 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.17%. Comparing base (7d92152) to head (c3ae91a).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6644   +/-   ##
=======================================
  Coverage   94.17%   94.17%           
=======================================
  Files         494      494           
  Lines       41666    41673    +7     
  Branches     4823     4824    +1     
=======================================
+ Hits        39240    39247    +7     
  Misses       2421     2421           
  Partials        5        5           

☔ 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.

@PavelVanecek
Copy link
Collaborator

Thanks @j-shimizu111 . Can you please add a new VR test too? There are examples in the tests-vr directory

@j-shimizu111 j-shimizu111 force-pushed the fix/reverse-stack-order-v3 branch from 975faa4 to 48b39f1 Compare November 17, 2025 05:22
j-shimizu111

This comment was marked as duplicate.

@j-shimizu111
Copy link
Contributor Author

/update-snapshots

@j-shimizu111
Copy link
Contributor Author

@PavelVanecek
Thanks for the quick feedback!
I tried triggering /update-snapshots but it seems to fail because the workflow cannot access the branch from my fork. Could you please help update the VR snapshots, or let me know if there's another way I should handle this for forked PRs?

@PavelVanecek
Copy link
Collaborator

You can generate the screenshots with npm run test-vr:prepare && npm run test-vr:update, requires Docker.

@PavelVanecek
Copy link
Collaborator

The reverseStackOrder prop was defined in types but not implemented
in the v3 Redux-based architecture, causing it to have no effect.

This change:
- Adds reverseStackOrder to Redux state (UpdatableChartOptions)
- Passes reverseStackOrder through ReportChartProps in CartesianChart and PolarChart
- Implements stack reversal logic in combineStackGroups selector
- Adds comprehensive tests for reverseStackOrder behavior
- Updates Storybook story to expose reverseStackOrder control

Fixes the regression from v2.15.4 where reverseStackOrder worked correctly.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@j-shimizu111 j-shimizu111 force-pushed the fix/reverse-stack-order-v3 branch from 48b39f1 to c3ae91a Compare November 17, 2025 06:22
@j-shimizu111
Copy link
Contributor Author

@PavelVanecek

Thanks! I've added the VR tests and generated all snapshots locally with Docker as you suggested.

All changes have been committed and pushed. The CI workflow is waiting for approval to run. Could you please approve it when you have a chance?

@codecov
Copy link

codecov bot commented Nov 17, 2025

Bundle Report

Changes will increase total bundle size by 660 bytes (0.03%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
recharts/bundle-cjs 1.13MB 660 bytes (0.06%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: recharts/bundle-cjs

Assets Changed:

Asset Name Size Change Total Size Change (%)
state/selectors/axisSelectors.js 194 bytes 63.36kB 0.31%
state/selectors/tooltipSelectors.js 45 bytes 16.33kB 0.28%
state/selectors/radialBarSelectors.js 45 bytes 12.7kB 0.36%
chart/PolarChart.js 58 bytes 5.35kB 1.1%
chart/CartesianChart.js 57 bytes 3.91kB 1.48%
state/rootPropsSlice.js 94 bytes 1.71kB 5.83% ⚠️
state/selectors/rootPropsSelectors.js 167 bytes 1.61kB 11.59% ⚠️

Copy link
Member

@ckifer ckifer left a comment

Choose a reason for hiding this comment

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

thanks!

@ckifer ckifer merged commit 055848c into recharts:main Nov 18, 2025
23 checks passed
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.

3 participants