Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ed90924
Move all hooks and utils out of shared
adamwoodnz Aug 27, 2025
b230846
Move remaining shared utils to utils
adamwoodnz Aug 27, 2025
5b8e38c
Add an index for utils
adamwoodnz Aug 27, 2025
d4367a7
Move components out of shared and into their own dirs
adamwoodnz Aug 27, 2025
31648b3
Move global chart context hooks into separate files
adamwoodnz Aug 27, 2025
f9ac067
Refactor single chart context exports
adamwoodnz Aug 27, 2025
cc370de
Add changelog
adamwoodnz Aug 28, 2025
0c97ade
Rename utils test dir
adamwoodnz Aug 28, 2025
7fd6892
Rename globals charts things for consistency
adamwoodnz Aug 28, 2025
33a75f7
Move chart composition test into dir
adamwoodnz Aug 28, 2025
f1b980e
Fix import
adamwoodnz Aug 28, 2025
635a065
Fix type import
adamwoodnz Aug 28, 2025
d4ba035
Refactor legend hook and update imports to use useChartLegendItems
adamwoodnz Aug 28, 2025
ff70a08
Restructure Legend
adamwoodnz Aug 29, 2025
e5cc713
Restructure BarChart
adamwoodnz Aug 29, 2025
415d506
Move internal components to private dir
adamwoodnz Aug 29, 2025
b02a4da
Remove internal utils and hooks from top level exports
adamwoodnz Aug 29, 2025
946b677
Restructure Tooltip
adamwoodnz Aug 29, 2025
3d29ae3
Restructure ConversionFunnelChart
adamwoodnz Aug 29, 2025
7d414d7
Remove unused and outdated root index file
adamwoodnz Aug 29, 2025
6815cd9
Fix build warnings for type imports
adamwoodnz Aug 29, 2025
d792b9f
Fix circular dependency for BaseLegenditem
adamwoodnz Aug 29, 2025
588fc6e
Restructure LeaderboardChart
adamwoodnz Aug 29, 2025
678850f
Add a legend private index
adamwoodnz Aug 29, 2025
3fce724
Restructure LineChart
adamwoodnz Aug 29, 2025
7a96fd6
Restructure PieChart
adamwoodnz Aug 29, 2025
0024898
Restructure PieSemiCircleChart
adamwoodnz Aug 29, 2025
e833694
Add missing type exports to component index files
adamwoodnz Aug 29, 2025
e574c76
Fix some imports from private files
adamwoodnz Aug 29, 2025
2f422a8
Remove internal types from root exports
adamwoodnz Aug 29, 2025
caa255a
Move annotation styles back to component folder
adamwoodnz Aug 29, 2025
87130ad
Move BaseLegendItem type back to component
adamwoodnz Aug 29, 2025
7ad91d6
Fix more type import build warnings
adamwoodnz Aug 29, 2025
f6cf4f1
Revert moving CSS modules to private
adamwoodnz Sep 1, 2025
8a2d7c0
Organize LineChart types and exports
adamwoodnz Sep 1, 2025
8a67369
Organize LineChart types and exports
adamwoodnz Sep 1, 2025
8a89ac1
it is actually css for base-legend
kangzj Sep 1, 2025
2189481
Merge remote-tracking branch 'refs/remotes/origin/charts-86-charts-re…
kangzj Sep 1, 2025
c0a9851
it is actually css for base-legend
kangzj Sep 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Charts: Refactor shared components, hooks and utils
16 changes: 0 additions & 16 deletions projects/js-packages/charts/index.ts

This file was deleted.

29 changes: 15 additions & 14 deletions projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,29 @@ import { Axis, BarSeries, BarGroup, Grid, XYChart } from '@visx/xychart';
import { __ } from '@wordpress/i18n';
import clsx from 'clsx';
import { useCallback, useContext, useState, useRef, useMemo } from 'react';
import { useXYChartTheme } from '../../hooks';
import {
useXYChartTheme,
useChartDataTransform,
useZeroValueDisplay,
useChartMargin,
useElementHeight,
} from '../../hooks';
import {
GlobalChartsProvider,
useChartId,
useChartRegistration,
useGlobalChartsContext,
} from '../../providers/chart-context';
import { GlobalChartsContext } from '../../providers/chart-context/global-charts-provider';
import { attachSubComponents } from '../../utils/create-composition';
import { Legend } from '../legend';
import { useChartLegendData } from '../legend/use-chart-legend-data';
import { SingleChartContext } from '../shared/single-chart-context';
import { useChartDataTransform } from '../shared/use-chart-data-transform';
import { useChartMargin } from '../shared/use-chart-margin';
import { useElementHeight } from '../shared/use-element-height';
import { useZeroValueDisplay } from '../shared/use-zero-value-display';
import { withResponsive } from '../shared/with-responsive';
import { AccessibleTooltip, useKeyboardNavigation } from '../tooltip/accessible-tooltip';
import { attachSubComponents } from '../../utils';
import { Legend, useChartLegendItems } from '../legend';
import { SingleChartContext } from '../private/single-chart-context';
import { withResponsive } from '../private/with-responsive';
import { AccessibleTooltip, useKeyboardNavigation } from '../tooltip';
import styles from './bar-chart.module.scss';
import { useBarChartOptions } from './use-bar-chart-options';
import { useBarChartOptions } from './private';
import type { BaseChartProps, DataPointDate, SeriesData, Optional } from '../../types';
import type { ResponsiveConfig } from '../shared/with-responsive';
import type { ResponsiveConfig } from '../private/with-responsive';
import type { RenderTooltipParams } from '@visx/xychart/lib/components/Tooltip';
import type { FC, ReactNode, ComponentType } from 'react';

Expand Down Expand Up @@ -102,7 +103,7 @@ const BarChartInternal: FC< BarChartProps > = ( {
} );

// Create legend items using the reusable hook
const legendItems = useChartLegendData( dataSorted );
const legendItems = useChartLegendItems( dataSorted );
const chartOptions = useBarChartOptions( dataWithVisibleZeros, horizontal, options );
const defaultMargin = useChartMargin( height, chartOptions, dataSorted, theme, horizontal );
const [ legendRef, legendHeight ] = useElementHeight< HTMLDivElement >();
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as BarChart } from './bar-chart';
export type { BarChartProps } from './bar-chart';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useBarChartOptions } from './use-bar-chart-options';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { formatNumberCompact } from '@automattic/number-formatters';
import { useMemo } from 'react';
import type { DataPointDate, BaseChartProps, SeriesData } from '../../types';
import type { EnhancedDataPoint } from '../shared/use-zero-value-display';
import type { EnhancedDataPoint } from '../../../hooks/use-zero-value-display';
import type { DataPointDate, BaseChartProps, SeriesData } from '../../../types';
import type { TickFormatter } from '@visx/axis';

const formatDateTick = ( timestamp: number ) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { Text, type TextProps } from '@visx/text';
import { useContext, useMemo } from 'react';
import { GlobalChartsContext, GlobalChartsProvider } from '../../providers/chart-context';
import { BarChart } from '../bar-chart';
import { withResponsive } from '../shared/with-responsive';
import { withResponsive } from '../private/with-responsive';
import type { SeriesData } from '../..';
import type { ScaleOptions } from '../../types';
import type { BarChartProps } from '../bar-chart/bar-chart';
import type { AxisRendererProps, AxisScale } from '@visx/axis';
import type { AnyD3Scale } from '@visx/scale';
import type { ComponentType, FC } from 'react';

interface BarListChartProps
export interface BarListChartProps
extends Exclude< BarChartProps, 'orientation' | 'size' | 'gridVisibility' > {
options?: {
/**
Expand Down Expand Up @@ -55,15 +55,15 @@ interface BarListChartProps
};
}

interface RenderLabelProps {
export interface RenderLabelProps {
textProps: TextProps;
x: number;
y: number;
label: string;
formatter: ( value: string ) => string;
}

interface RenderValueProps {
export interface RenderValueProps {
textProps: TextProps;
x: number;
y: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as BarListChart } from './bar-list-chart';
export type { BarListChartProps, RenderLabelProps, RenderValueProps } from './bar-list-chart';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { formatNumberCompact } from '@automattic/number-formatters';
import { Circle } from '@visx/shape';
import { Text } from '@visx/text';
import { useGlobalChartTheme } from '../../../hooks';
import { useGlobalChartsTheme } from '../../../providers/chart-context';
import { sharedDecorator } from '../../../stories/decorator-config';
import {
marketingChannelsComparison as salesByChannel,
Expand Down Expand Up @@ -61,7 +61,7 @@ export const CustomLabelComponent: Story = {
yScale: {},
labelComponent: ( { textProps, x, y, label, formatter } ) => {
// eslint-disable-next-line react-hooks/rules-of-hooks
const theme = useGlobalChartTheme();
const theme = useGlobalChartsTheme();
const circleColor = theme.colors[ 1 ]; // Use second theme color for contrast

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { __experimentalText as Text } from '@wordpress/components'; // eslint-disable-line @wordpress/no-unsafe-wp-apis
import clsx from 'clsx';
import { type FC, useRef, useMemo, useEffect, useCallback } from 'react';
import { useGlobalChartTheme } from '../../hooks';
import { useGlobalChartsTheme } from '../../providers/chart-context';
import { hexToRgba } from '../../utils';
import styles from './conversion-funnel-chart.module.scss';
import { useFunnelSelection } from './hooks/use-funnel-selection';
import { hexToRgba } from './utils/color-utils';
import { useFunnelSelection } from './private';

/**
* Represents a single step in the conversion funnel
Expand Down Expand Up @@ -68,7 +68,7 @@ export const ConversionFunnelChart: FC< ConversionFunnelChartProps > = ( {
className,
style,
} ) => {
const theme = useGlobalChartTheme();
const theme = useGlobalChartsTheme();
const chartRef = useRef< HTMLDivElement >( null );
const selectedBarRef = useRef< HTMLDivElement | null >( null );

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useFunnelSelection } from './use-funnel-selection';
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { act, renderHook } from '@testing-library/react';
import { useFunnelSelection } from '../hooks/use-funnel-selection';
import { useFunnelSelection } from '../private/use-funnel-selection';

describe( 'useFunnelSelection', () => {
describe( 'Initial State', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { default as LeaderboardChart } from './leaderboard-chart';
export type { LeaderboardChartProps, LeaderboardEntry } from './leaderboard-chart';
export { formatMetricValue } from '../shared/format-metric-value';
export type { MetricValueType } from '../shared/format-metric-value';
export { formatMetricValue } from '../../utils';
export type { MetricValueType } from '../../utils';
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import {
import { Fragment } from '@wordpress/element';
import clsx from 'clsx';
import { type FC } from 'react';
import { useGlobalChartTheme } from '../../hooks';
import { formatMetricValue } from '../shared/format-metric-value';
import { useGlobalChartsTheme } from '../../providers/chart-context';
import { formatMetricValue } from '../../utils';
import styles from './leaderboard-chart.module.scss';

/**
Expand Down Expand Up @@ -209,7 +209,7 @@ export const LeaderboardChart: FC< LeaderboardChartProps > = ( {
className,
style,
} ) => {
const theme = useGlobalChartTheme();
const theme = useGlobalChartsTheme();

// Get component settings from theme with fallbacks
const leaderboardSettings = theme.leaderboardChart;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
decliningMetricsData as negativeGrowth,
categorizedMetricsData as dataWithImageColor,
} from '../../../stories/sample-data';
import { formatMetricValue } from '../../shared/format-metric-value';
import { formatMetricValue } from '../../../utils';
import { LeaderboardChart } from '../leaderboard-chart';
import type { Meta, StoryObj } from '@storybook/react';

Expand All @@ -23,7 +23,7 @@ A flexible and accessible leaderboard chart component for displaying ranked data
## Features

- 📊 Clean, responsive leaderboard visualization
- 🎨 Customizable colors and styling
- 🎨 Customizable colors and styling
- 🔄 Optional comparison data support
- 📱 Mobile-friendly design
- 🎯 TypeScript support with full type definitions
Expand Down Expand Up @@ -89,7 +89,7 @@ import { LeaderboardChart } from '@automattic/charts';
// Transform your raw data into LeaderboardEntry format
function transformRawData(rawData) {
const maxValue = Math.max(...rawData.map(item => item.current_period.value));

return rawData.map(item => ({
id: item.id,
label: item.name,
Expand All @@ -103,7 +103,7 @@ function transformRawData(rawData) {

function ProcessedDataChart() {
const processedData = transformRawData(rawData);

return (
<LeaderboardChart
data={processedData}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useMemo } from 'react';
import { useGlobalChartTheme } from '../../hooks';
import { getItemShapeStyles, getSeriesStroke } from '../../utils/get-styles';
import type { BaseLegendItem } from './types';
import type { ChartTheme, SeriesData, DataPointDate, DataPointPercentage } from '../../types';
import { useGlobalChartsTheme } from '../../../providers/chart-context';
import { getItemShapeStyles, getSeriesStroke } from '../../../utils';
import type { ChartTheme, SeriesData, DataPointDate, DataPointPercentage } from '../../../types';
import type { BaseLegendItem } from '../types';
import type { LegendShape } from '@visx/legend/lib/types';
import type { GlyphProps } from '@visx/xychart';
import type { ReactNode } from 'react';
Expand Down Expand Up @@ -134,15 +134,15 @@ function processPointData(
* @param legendShape - The shape type for legend items (string literal or React component)
* @return Array of legend items ready for display
*/
export function useChartLegendData<
export function useChartLegendItems<
T extends SeriesData[] | DataPointDate[] | DataPointPercentage[],
>(
data: T,
options: ChartLegendOptions = {},
legendShape?: LegendShape< SeriesData[], number >
): BaseLegendItem[] {
const { showValues = false, withGlyph = false, glyphSize = 8, renderGlyph } = options;
const theme = useGlobalChartTheme();
const theme = useGlobalChartsTheme();

return useMemo( () => {
if ( ! data || ! Array.isArray( data ) || data.length === 0 ) {
Expand Down
7 changes: 3 additions & 4 deletions projects/js-packages/charts/src/components/legend/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
export { Legend } from './legend';
export { BaseLegend } from './base-legend';
export { useChartLegendData } from './use-chart-legend-data';
export type { LegendProps, BaseLegendProps } from './types';
export type { ChartLegendOptions } from './use-chart-legend-data';
export { useChartLegendItems } from './hooks/use-chart-legend-items';
export type { LegendProps, BaseLegendProps, BaseLegendItem } from './types';
export type { ChartLegendOptions } from './hooks/use-chart-legend-items';
4 changes: 2 additions & 2 deletions projects/js-packages/charts/src/components/legend/legend.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useContext, useMemo, forwardRef } from 'react';
import { GlobalChartsContext } from '../../providers/chart-context/global-charts-provider';
import { SingleChartContext } from '../shared/single-chart-context';
import { BaseLegend } from './base-legend';
import { SingleChartContext } from '../private/single-chart-context';
import { BaseLegend } from './private';
import type { LegendProps } from './types';

export const Legend = forwardRef< HTMLDivElement, LegendProps >(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@ import { LegendItem, LegendLabel, LegendOrdinal, LegendShape } from '@visx/legen
import { scaleOrdinal } from '@visx/scale';
import clsx from 'clsx';
import { forwardRef, useCallback, useMemo, useContext } from 'react';
import { useGlobalChartTheme } from '../../hooks';
import { GlobalChartsContext } from '../../providers/chart-context';
import styles from './legend.module.scss';
import { valueOrIdentity, valueOrIdentityString, labelTransformFactory } from './utils';
import type { BaseLegendProps } from './types';
import { useGlobalChartsTheme, GlobalChartsContext } from '../../../providers/chart-context';
import { valueOrIdentity, valueOrIdentityString, labelTransformFactory } from '../utils';
import styles from './base-legend.module.scss';
import type { BaseLegendProps } from '../types';

const orientationToFlexDirection = {
horizontal: 'row' as const,
Expand Down Expand Up @@ -44,7 +43,7 @@ export const BaseLegend = forwardRef< HTMLDivElement, BaseLegendProps >(
},
ref
) => {
const theme = useGlobalChartTheme();
const theme = useGlobalChartsTheme();
const context = useContext( GlobalChartsContext );
const resolveGroupColor = context?.resolveGroupColor;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { BaseLegend } from './base-legend';
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { GlobalChartsProvider } from '../../../providers/chart-context';
import { BarChart } from '../../bar-chart';
import { LineChart } from '../../line-chart';
import { PieChart } from '../../pie-chart';
import { useChartLegendItems } from '../hooks/use-chart-legend-items';
import { Legend } from '../legend';
import { useChartLegendData } from '../use-chart-legend-data';
import type { SeriesData, DataPointPercentage } from '../../../types';

const meta: Meta< typeof Legend > = {
Expand Down Expand Up @@ -147,7 +147,7 @@ export const Vertical: Story = {

// Story showing use with LineChart data
const WithLineChartData = () => {
const legendItems = useChartLegendData( lineChartData, {
const legendItems = useChartLegendItems( lineChartData, {
showValues: false,
} );

Expand Down Expand Up @@ -183,7 +183,7 @@ export const WithLineChart: Story = {

// Story showing use with BarChart data
const WithBarChartData = () => {
const legendItems = useChartLegendData( barChartData );
const legendItems = useChartLegendItems( barChartData );

return (
<div style={ { display: 'flex', gap: '20px', alignItems: 'flex-start' } }>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import { BaseLegend } from './base-legend';
import type { LegendProps } from './types';
import { BaseLegend } from '../private/base-legend';
import type { LegendProps } from '../types';

const TestShape: LegendProps[ 'shape' ] = props => {
return (
Expand Down
26 changes: 13 additions & 13 deletions projects/js-packages/charts/src/components/legend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,6 @@ import type { ComponentProps, CSSProperties, ReactNode } from 'react';
// See https://airbnb.io/visx/docs/legend#Ordinal for more details.
type LegendOrdinalProps = Omit< ComponentProps< typeof LegendOrdinal >, 'scale' | 'direction' >;

export type BaseLegendItem = {
label: string;
value: number | string;
color: string;
glyphSize?: number;
renderGlyph?: < Datum extends object >( props: GlyphProps< Datum > ) => ReactNode;
shapeStyle?: CSSProperties & LineStyles;
// Optional group info for dynamic color resolution
group?: string;
index?: number;
overrideColor?: string;
};

export type BaseLegendProps = Omit< LegendOrdinalProps, 'shapeStyle' > & {
items: BaseLegendItem[];
orientation?: 'horizontal' | 'vertical';
Expand All @@ -32,3 +19,16 @@ export type LegendProps = Omit< BaseLegendProps, 'items' > & {
items?: BaseLegendItem[];
chartId?: string;
};

export type BaseLegendItem = {
label: string;
value: number | string;
color: string;
glyphSize?: number;
renderGlyph?: < Datum extends object >( props: GlyphProps< Datum > ) => ReactNode;
shapeStyle?: CSSProperties & LineStyles;
// Optional group info for dynamic color resolution
group?: string;
index?: number;
overrideColor?: string;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { valueOrIdentity, valueOrIdentityString } from './value-or-identity';
export { labelTransformFactory } from './label-transform-factory';
export type { ValueOrIdentity } from './value-or-identity';
Loading
Loading