Skip to content

Charts: Add standalone Legend component #44245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 68 commits into from
Jul 25, 2025

Conversation

annacmc
Copy link
Contributor

@annacmc annacmc commented Jul 9, 2025

related to: CHARTS-50: Standalone Legend Component

Proposed changes:

This feature adds a flexible standalone Legend component that can work
independently with manual data or automatically integrate with charts through a
shared context system. The new useChartLegendData hook processes chart data
(SeriesData, DataPointPercentage) into legend format, while the Chart Context
allows legends to be shared between multiple charts using chartId props. All
existing chart components have been updated to support this system while
maintaining backward compatibility.

Other information:

  • Have you written new tests for your changes, if applicable? (Tests split to follow-up PR for easier review)
  • Have you checked the E2E test CI results, and verified that your changes do not break them?
  • Have you tested your changes on WordPress.com, if applicable (if so, you'll see a generated comment below with a script to run)?

Jetpack product discussion

Does this pull request change what data or activity we track or use?

No data tracking changes.

Testing instructions:

  - Storybook: npm run storybook
  - Tests: npm test
  - TypeScript: npm run typecheck
  - Build: npm run build

Storybook Testing

  • Navigate to Legend stories (JS Packages/Charts/Composites/Legend)
  • Test all chart stories: Line Chart, Bar Chart, Pie Chart, Pie Semi-Circle Chart
  • Verify legends render correctly in all orientations (horizontal/vertical)
  • Check console for errors or warnings
  • Test legend stories specifically to ensure legends still work properly

Core Functionality

  • Standalone legends: Display independently without charts using manual data
  • Context integration: Charts with showLegend={false} still provide data to
    standalone legends via chartId
  • Multiple charts: Verify multiple chart instances don't interfere with each other
  • Legend data accuracy: Colors, labels, values, and glyphs display correctly

Performance & Quality

  • Tests: npm test - all tests should pass
  • TypeScript: npm run typecheck - should pass without errors
  • Build: npm run build - completes without errors
  • Re-renders: No performance regressions, memoization working properly

Regression Testing

  • Visual consistency: Charts render as before (no visual changes)
  • Legend integration: Chart legends continue working when showLegend={true}
  • Chart context: Proper chart registration/unregistration
  • Cross-compatibility: All chart types work with new legend system
image

@annacmc annacmc self-assigned this Jul 9, 2025
@annacmc annacmc requested a review from Copilot July 9, 2025 13:36
Copy link
Contributor

github-actions bot commented Jul 9, 2025

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the add/charts-50-standalone-legend-component branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack add/charts-50-standalone-legend-component

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

Copy link
Contributor

github-actions bot commented Jul 9, 2025

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • 🔴 Add a "[Type]" label (Bug, Enhancement, Janitorial, Task).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!

@github-actions github-actions bot added the [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. label Jul 9, 2025
Copilot

This comment was marked as outdated.

Copy link

jp-launch-control bot commented Jul 9, 2025

Code Coverage Summary

Coverage changed in 5 files.

File Coverage Δ% Δ Uncovered
projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx 71/77 (92.21%) -0.94% 1 ❤️‍🩹
projects/js-packages/charts/src/components/line-chart/line-chart.tsx 98/104 (94.23%) -0.67% 1 ❤️‍🩹
projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx 51/55 (92.73%) -1.27% 1 ❤️‍🩹
projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx 52/52 (100.00%) 0.00% 0 💚
projects/js-packages/charts/src/providers/chart-context/chart-context.tsx 20/20 (100.00%) 0.00% 0 💚

2 files are newly checked for coverage.

File Coverage
projects/js-packages/charts/src/components/legend/use-chart-legend-data.ts 22/27 (81.48%) 💚
projects/js-packages/charts/src/components/legend/legend.tsx 7/8 (87.50%) 💚

Full summary · PHP report · JS report

Coverage check overridden by Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR .

@annacmc annacmc force-pushed the add/charts-50-standalone-legend-component branch 2 times, most recently from ce9977f to b018ace Compare July 11, 2025 10:07
@annacmc annacmc requested a review from Copilot July 14, 2025 23:51
Copilot

This comment was marked as outdated.

@annacmc annacmc requested a review from Copilot July 15, 2025 08:57
Copilot

This comment was marked as outdated.

annacmc and others added 14 commits July 16, 2025 09:23
- Create ChartLegendOptions interface with showValues, withGlyph, glyphSize, and renderGlyph options
- Add ChartLegendProps interface extending LegendProps with chartId for future context integration
- Implement useChartLegendData hook with overloads for SeriesData[] and DataPoint[]/DataPointPercentage[]
- Support both series data and point data with proper color, shape, and glyph handling
- Include valueDisplay preference for DataPointPercentage items
- Return properly typed LegendItemWithGlyph[] or LegendItemWithoutGlyph[] arrays
- Create ChartLegend component as a wrapper around BaseLegend
- Accept chartId prop for future context integration
- Pass through all legend props to BaseLegend for consistent behavior
- Enables standalone legend usage independent of chart showLegend prop
- Replace inline legend items creation with useChartLegendData hook
- Pass withGlyph and glyphSize options to maintain existing functionality
- Eliminates duplicate legend creation logic
- Maintains all existing legend behavior and styling
- Replace inline legend items creation with useChartLegendData hook
- Add useChartTheme hook to get provider theme for consistent legend colors
- Move hook call to proper position to avoid rules-of-hooks violation
- Remove duplicate legend creation logic
- Maintains all existing legend behavior and styling
- Replace inline legend items creation with useChartLegendData hook in both components
- Enable showValues option for both charts to display percentages in legend
- Move hook calls to proper position to avoid rules-of-hooks violations
- Remove duplicate legend creation logic
- Maintain valueDisplay support for properly formatted percentage values
- Keep all existing legend behavior and styling
- Export ChartLegend component and useChartLegendData hook from main index
- Export ChartLegendProps and ChartLegendOptions types
- Add chart-legend module index file with all exports
- Makes standalone legend functionality available to consumers
- Create multiple story examples showing different usage patterns
- Include stories for standalone usage, chart integration, and alignment options
- Add stories demonstrating usage with LineChart, BarChart, and PieChart
- Include examples for multiple charts sharing a legend
- Add comprehensive test suite for ChartLegend component and useChartLegendData hook
- Test both SeriesData and DataPointPercentage data types
- Test memoization, glyph handling, and value display functionality
- Fix TypeScript any usage in mock functions
- Resolve merge conflicts from chart context foundation PR
- Fix duplicate legendItems declarations in PieChart and PieSemiCircleChart
- Maintain custom color handling in PieSemiCircleChart using accessors
- Fix type-only import for AnnotationStyles
- Fix duplicate identifier in ChartLegend stories
- Add chart context integration to automatically retrieve legend data
- Support chartId prop for standalone usage
- Maintain fallback to items prop for manual data passing
- Add story demonstrating standalone usage with chartId
- Component works with showLegend=false charts
- Accepts all BaseLegend props through inheritance
- Create validateSeriesData for line/bar charts
- Create validatePercentageData for pie charts
- Create validateSemiCircleData for semi-circle charts
- Create validateBarChartData for bar-specific validation
- Eliminates ~60 lines of duplicated validation code
- Enhances existing Legend to support chartId prop
- Automatically retrieves legend data from chart context
- Falls back to manual items prop for backward compatibility
- Enables standalone legend usage with <Legend chartId="my-chart" />
- Extract formatPointValue for consistent value formatting
- Extract createBaseLegendItem for common legend item creation
- Extract processSeriesData and processPointData functions
- Eliminates ~50 lines of duplicated mapping logic
- Improves code readability and testability
- Split LegendProps into BaseLegendProps and LegendProps
- BaseLegendProps for direct usage (items required)
- LegendProps for context usage (items optional, chartId added)
- Export new Legend component alongside BaseLegend
- Export useChartLegendData and ChartLegendOptions
@annacmc
Copy link
Contributor Author

annacmc commented Jul 24, 2025

Thanks so much @adamwoodnz for such a thorough check and review, it's ended up being quite the mission of a PR to work through. I believe I've fixed up and addressed all of your comments with the exception of:

  • Better Storybook demos and docs
  • Vertical alignment legend issues

Both are coming in followups to this PR. If you get a chance, take another look through and see if you think this is okay enough now as it is to get it merged and keep moving forward 😄

@annacmc annacmc requested a review from adamwoodnz July 24, 2025 12:46
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
* @param options - Configuration options for legend generation
* @return Array of legend items ready for display
*/
export function useChartLegendData<
Copy link
Contributor

Choose a reason for hiding this comment

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

Love this hook 🪝

@@ -275,7 +287,7 @@ const PieSemiCircleChartInternal: FC< PieSemiCircleChartProps > = ( {
) }

{ showLegend && (
<Legend
<BaseLegend
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder why chartId is not passed here, which is not consistent with the implementation in line chart

@annacmc annacmc force-pushed the add/charts-50-standalone-legend-component branch from b022a55 to 701da72 Compare July 25, 2025 00:45
shapeStyle: group?.options?.legendShapeStyle,
} ) ),
[ dataSorted, getColor ]
// Memoize metadata to prevent unnecessary re-registration
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's centralize the logic to useChartRegistration so that it wouldn't have to be repeated every time.

@@ -347,17 +346,28 @@ const BarChartInternal: FC< BarChartProps > = ( {
className={ styles[ 'bar-chart__legend' ] }
shape={ legendShape }
ref={ legendRef }
chartId={ chartId }
Copy link
Contributor

Choose a reason for hiding this comment

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

I changed BaseLengend to Legend like what's happening in line chart. Please revert if this was intentional.

kangzj
kangzj previously approved these changes Jul 25, 2025
Copy link
Contributor

@kangzj kangzj left a comment

Choose a reason for hiding this comment

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

I went ahead a tweaked a couple of small things. Hope you don't mind.

Maybe it's worth to take another review from @adamwoodnz, but it otherwise looks good to me!

------UPDATE------
It's awesome to see the standalone legends. Really cool 👍

@kangzj
Copy link
Contributor

kangzj commented Jul 25, 2025

Notice some minor cutoff for pie chart with legend but I don't think it's related to the PR:

Screenshot 2025-07-25 at 12 38 56 PM

@kangzj
Copy link
Contributor

kangzj commented Jul 25, 2025

Hi @adamwoodnz & @annacmc, I'm curious to hear your thoughts - is it possible we consolidate the providers for themes, annotations (is this one internal) and legends to reduce the burden of chart lib adoption?

@annacmc
Copy link
Contributor Author

annacmc commented Jul 25, 2025

Notice some minor cutoff for pie chart with legend but I don't think it's related to the PR:

Screenshot 2025-07-25 at 12 38 56 PM

I believe this is specifically only a problem with the vertical legends, which a fix is coming in its own PR soon 😄

@adamwoodnz
Copy link
Contributor

adamwoodnz commented Jul 25, 2025

Hi @adamwoodnz & @annacmc, I'm curious to hear your thoughts - is it possible we consolidate the providers for themes, annotations (is this one internal) and legends to reduce the burden of chart lib adoption?

I initially tried adding the internal line chart context to the chart context, but it was complicated. I eventually decided I couldn't think of a reason another chart would need access to that information, so I kept it simple and scoped it to the chart instance. In terms of adoption friction; I don't think a consumer would ever need to deal with it as it currently stands, as it's constructed by the chart for the sole purpose of the annotations overlay.

I can see a benefit to the chart context providing the theme though.

Copy link
Contributor

@adamwoodnz adamwoodnz left a comment

Choose a reason for hiding this comment

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

Clipping issues seem fixed, nice!

LGTM

@annacmc annacmc merged commit 506284f into trunk Jul 25, 2025
84 checks passed
@annacmc annacmc deleted the add/charts-50-standalone-legend-component branch July 25, 2025 04:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR [JS Package] Charts RNA [Tests] Includes Tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants