diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 4af216da4b55c..d2a2a658b2b2a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -304,6 +304,9 @@ importers:
'@visx/group':
specifier: ^3.12.0
version: 3.12.0(react@18.3.1)
+ '@visx/responsive':
+ specifier: 3.12.0
+ version: 3.12.0(react@18.3.1)
'@visx/scale':
specifier: ^3.12.0
version: 3.12.0
diff --git a/projects/js-packages/charts/changelog/add-charts-pie-chart b/projects/js-packages/charts/changelog/add-charts-pie-chart
new file mode 100644
index 0000000000000..81e8c5063e8ae
--- /dev/null
+++ b/projects/js-packages/charts/changelog/add-charts-pie-chart
@@ -0,0 +1,4 @@
+Significance: patch
+Type: added
+
+Adding new chart type - pie chart.
diff --git a/projects/js-packages/charts/package.json b/projects/js-packages/charts/package.json
index 41e7c7118aaa1..e51243ee01bc2 100644
--- a/projects/js-packages/charts/package.json
+++ b/projects/js-packages/charts/package.json
@@ -21,6 +21,7 @@
},
"dependencies": {
"@react-spring/web": "9.7.3",
+ "@visx/responsive": "3.12.0",
"@visx/axis": "^3.12.0",
"@visx/group": "^3.12.0",
"@visx/scale": "^3.12.0",
diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx
index ee4fe451fe464..984fddd5ac8f4 100644
--- a/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx
+++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx
@@ -5,46 +5,25 @@ import { scaleBand, scaleLinear } from '@visx/scale';
import { Bar } from '@visx/shape';
import { useTooltip } from '@visx/tooltip';
import clsx from 'clsx';
-import { FC, useCallback } from 'react';
+import { FC, useCallback, type MouseEvent } from 'react';
import { useChartTheme } from '../../providers/theme';
import { BaseTooltip } from '../tooltip';
import styles from './bar-chart.module.scss';
-import type { DataPoint } from '../shared/types';
+import type { BaseChartProps, DataPoint } from '../shared/types';
-type BarChartProps = {
+interface BarChartProps extends BaseChartProps {
/**
* Array of data points to display in the chart
*/
data: DataPoint[];
- /**
- * Width of the chart in pixels
- */
- width: number;
- /**
- * Height of the chart in pixels
- */
- height: number;
- /**
- * Chart margins
- */
- margin?: {
- top?: number;
- right?: number;
- bottom?: number;
- left?: number;
- };
- /**
- * Whether to show tooltips on hover
- */
- showTooltips?: boolean;
-};
+}
const BarChart: FC< BarChartProps > = ( {
data,
width,
height,
margin = { top: 20, right: 20, bottom: 40, left: 40 },
- showTooltips = false,
+ withTooltips = false,
} ) => {
const theme = useChartTheme();
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } =
@@ -66,7 +45,7 @@ const BarChart: FC< BarChartProps > = ( {
} );
const handleMouseMove = useCallback(
- ( event: React.MouseEvent, datum: DataPoint ) => {
+ ( event: MouseEvent< SVGRectElement >, datum: DataPoint ) => {
const coords = localPoint( event );
if ( ! coords ) return;
@@ -83,35 +62,32 @@ const BarChart: FC< BarChartProps > = ( {
hideTooltip();
}, [ hideTooltip ] );
- const handleBarMouseMove = useCallback(
- ( d: DataPoint ) => ( event: React.MouseEvent< SVGRectElement > ) => {
- handleMouseMove( event, d );
- },
- [ handleMouseMove ]
- );
-
return (
- { showTooltips && tooltipOpen && tooltipData && (
+ { withTooltips && tooltipOpen && tooltipData && (
{}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const renderTooltip: any = ( { tooltipData } ) => {
diff --git a/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx
index 40a11b9c67364..d5c1a7fb6e2fb 100644
--- a/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx
+++ b/projects/js-packages/charts/src/components/line-chart/stories/index.stories.tsx
@@ -1,13 +1,7 @@
import { LineChart } from '../index';
+import sampleData from './sample-data';
import type { Meta } from '@storybook/react';
-const data = [
- { date: new Date( '2023-01-01' ), value: 10 },
- { date: new Date( '2023-02-01' ), value: 20 },
- { date: new Date( '2023-03-01' ), value: 15 },
- { date: new Date( '2023-04-01' ), value: 25 },
-];
-
export default {
title: 'JS Packages/Charts/Types/Line Chart',
component: LineChart,
@@ -30,5 +24,5 @@ Default.args = {
width: 500,
height: 300,
margin: { top: 20, right: 20, bottom: 30, left: 40 },
- data,
+ data: sampleData.mars,
};
diff --git a/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts b/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts
new file mode 100644
index 0000000000000..53d7f8d97d72e
--- /dev/null
+++ b/projects/js-packages/charts/src/components/line-chart/stories/sample-data.ts
@@ -0,0 +1,173 @@
+// Data from UK Met Office (London/Heathrow), Australian Bureau of Meteorology (Canberra),
+// and NASA Mars Curiosity Rover (Gale Crater)
+const temperatureData = {
+ london: [
+ { date: new Date( '2023-01-01' ), value: 8.2 },
+ { date: new Date( '2023-01-08' ), value: 7.9 },
+ { date: new Date( '2023-01-15' ), value: 5.1 },
+ { date: new Date( '2023-01-22' ), value: 4.8 },
+ { date: new Date( '2023-01-29' ), value: 6.3 },
+ { date: new Date( '2023-02-05' ), value: 7.2 },
+ { date: new Date( '2023-02-12' ), value: 9.4 },
+ { date: new Date( '2023-02-19' ), value: 8.7 },
+ { date: new Date( '2023-02-26' ), value: 7.1 },
+ { date: new Date( '2023-03-05' ), value: 8.3 },
+ { date: new Date( '2023-03-12' ), value: 9.5 },
+ { date: new Date( '2023-03-19' ), value: 11.2 },
+ { date: new Date( '2023-03-26' ), value: 12.8 },
+ { date: new Date( '2023-04-02' ), value: 13.4 },
+ { date: new Date( '2023-04-09' ), value: 14.1 },
+ { date: new Date( '2023-04-16' ), value: 15.3 },
+ { date: new Date( '2023-04-23' ), value: 14.8 },
+ { date: new Date( '2023-04-30' ), value: 15.7 },
+ { date: new Date( '2023-05-07' ), value: 16.9 },
+ { date: new Date( '2023-05-14' ), value: 17.2 },
+ { date: new Date( '2023-05-21' ), value: 18.4 },
+ { date: new Date( '2023-05-28' ), value: 19.1 },
+ { date: new Date( '2023-06-04' ), value: 20.3 },
+ { date: new Date( '2023-06-11' ), value: 21.5 },
+ { date: new Date( '2023-06-18' ), value: 22.8 },
+ { date: new Date( '2023-06-25' ), value: 21.9 },
+ { date: new Date( '2023-07-02' ), value: 23.1 },
+ { date: new Date( '2023-07-09' ), value: 22.7 },
+ { date: new Date( '2023-07-16' ), value: 24.2 },
+ { date: new Date( '2023-07-23' ), value: 23.8 },
+ { date: new Date( '2023-07-30' ), value: 22.9 },
+ { date: new Date( '2023-08-06' ), value: 23.4 },
+ { date: new Date( '2023-08-13' ), value: 22.8 },
+ { date: new Date( '2023-08-20' ), value: 21.9 },
+ { date: new Date( '2023-08-27' ), value: 20.7 },
+ { date: new Date( '2023-09-03' ), value: 19.8 },
+ { date: new Date( '2023-09-10' ), value: 18.9 },
+ { date: new Date( '2023-09-17' ), value: 17.6 },
+ { date: new Date( '2023-09-24' ), value: 16.8 },
+ { date: new Date( '2023-10-01' ), value: 15.9 },
+ { date: new Date( '2023-10-08' ), value: 14.7 },
+ { date: new Date( '2023-10-15' ), value: 13.8 },
+ { date: new Date( '2023-10-22' ), value: 12.9 },
+ { date: new Date( '2023-10-29' ), value: 11.7 },
+ { date: new Date( '2023-11-05' ), value: 10.8 },
+ { date: new Date( '2023-11-12' ), value: 9.9 },
+ { date: new Date( '2023-11-19' ), value: 8.7 },
+ { date: new Date( '2023-11-26' ), value: 7.8 },
+ { date: new Date( '2023-12-03' ), value: 6.9 },
+ { date: new Date( '2023-12-10' ), value: 5.8 },
+ { date: new Date( '2023-12-17' ), value: 4.9 },
+ { date: new Date( '2023-12-24' ), value: 5.7 },
+ { date: new Date( '2023-12-31' ), value: 6.2 },
+ ],
+
+ canberra: [
+ { date: new Date( '2023-01-01' ), value: 28.5 },
+ { date: new Date( '2023-01-08' ), value: 29.2 },
+ { date: new Date( '2023-01-15' ), value: 30.1 },
+ { date: new Date( '2023-01-22' ), value: 29.8 },
+ { date: new Date( '2023-01-29' ), value: 28.9 },
+ { date: new Date( '2023-02-05' ), value: 27.8 },
+ { date: new Date( '2023-02-12' ), value: 26.9 },
+ { date: new Date( '2023-02-19' ), value: 25.7 },
+ { date: new Date( '2023-02-26' ), value: 24.8 },
+ { date: new Date( '2023-03-05' ), value: 23.9 },
+ { date: new Date( '2023-03-12' ), value: 22.8 },
+ { date: new Date( '2023-03-19' ), value: 21.7 },
+ { date: new Date( '2023-03-26' ), value: 20.8 },
+ { date: new Date( '2023-04-02' ), value: 19.6 },
+ { date: new Date( '2023-04-09' ), value: 18.4 },
+ { date: new Date( '2023-04-16' ), value: 17.2 },
+ { date: new Date( '2023-04-23' ), value: 16.1 },
+ { date: new Date( '2023-04-30' ), value: 15.3 },
+ { date: new Date( '2023-05-07' ), value: 14.2 },
+ { date: new Date( '2023-05-14' ), value: 13.1 },
+ { date: new Date( '2023-05-21' ), value: 12.3 },
+ { date: new Date( '2023-05-28' ), value: 11.4 },
+ { date: new Date( '2023-06-04' ), value: 10.2 },
+ { date: new Date( '2023-06-11' ), value: 9.1 },
+ { date: new Date( '2023-06-18' ), value: 8.3 },
+ { date: new Date( '2023-06-25' ), value: 7.8 },
+ { date: new Date( '2023-07-02' ), value: 7.1 },
+ { date: new Date( '2023-07-09' ), value: 6.9 },
+ { date: new Date( '2023-07-16' ), value: 7.2 },
+ { date: new Date( '2023-07-23' ), value: 8.1 },
+ { date: new Date( '2023-07-30' ), value: 9.3 },
+ { date: new Date( '2023-08-06' ), value: 10.4 },
+ { date: new Date( '2023-08-13' ), value: 11.6 },
+ { date: new Date( '2023-08-20' ), value: 12.8 },
+ { date: new Date( '2023-08-27' ), value: 13.9 },
+ { date: new Date( '2023-09-03' ), value: 15.2 },
+ { date: new Date( '2023-09-10' ), value: 16.4 },
+ { date: new Date( '2023-09-17' ), value: 17.6 },
+ { date: new Date( '2023-09-24' ), value: 18.9 },
+ { date: new Date( '2023-10-01' ), value: 20.1 },
+ { date: new Date( '2023-10-08' ), value: 21.3 },
+ { date: new Date( '2023-10-15' ), value: 22.5 },
+ { date: new Date( '2023-10-22' ), value: 23.7 },
+ { date: new Date( '2023-10-29' ), value: 24.8 },
+ { date: new Date( '2023-11-05' ), value: 25.9 },
+ { date: new Date( '2023-11-12' ), value: 26.7 },
+ { date: new Date( '2023-11-19' ), value: 27.8 },
+ { date: new Date( '2023-11-26' ), value: 28.6 },
+ { date: new Date( '2023-12-03' ), value: 29.4 },
+ { date: new Date( '2023-12-10' ), value: 30.2 },
+ { date: new Date( '2023-12-17' ), value: 29.8 },
+ { date: new Date( '2023-12-24' ), value: 28.9 },
+ { date: new Date( '2023-12-31' ), value: 29.3 },
+ ],
+
+ mars: [
+ { date: new Date( '2023-01-01' ), value: -63 },
+ { date: new Date( '2023-01-08' ), value: -64 },
+ { date: new Date( '2023-01-15' ), value: -65 },
+ { date: new Date( '2023-01-22' ), value: -63 },
+ { date: new Date( '2023-01-29' ), value: -62 },
+ { date: new Date( '2023-02-05' ), value: -60 },
+ { date: new Date( '2023-02-12' ), value: -58 },
+ { date: new Date( '2023-02-19' ), value: -55 },
+ { date: new Date( '2023-02-26' ), value: -52 },
+ { date: new Date( '2023-03-05' ), value: -48 },
+ { date: new Date( '2023-03-12' ), value: -45 },
+ { date: new Date( '2023-03-19' ), value: -42 },
+ { date: new Date( '2023-03-26' ), value: -38 },
+ { date: new Date( '2023-04-02' ), value: -35 },
+ { date: new Date( '2023-04-09' ), value: -32 },
+ { date: new Date( '2023-04-16' ), value: -28 },
+ { date: new Date( '2023-04-23' ), value: -25 },
+ { date: new Date( '2023-04-30' ), value: -22 },
+ { date: new Date( '2023-05-07' ), value: -18 },
+ { date: new Date( '2023-05-14' ), value: -15 },
+ { date: new Date( '2023-05-21' ), value: -12 },
+ { date: new Date( '2023-05-28' ), value: -8 },
+ { date: new Date( '2023-06-04' ), value: -5 },
+ { date: new Date( '2023-06-11' ), value: -2 },
+ { date: new Date( '2023-06-18' ), value: 0 },
+ { date: new Date( '2023-06-25' ), value: 2 },
+ { date: new Date( '2023-07-02' ), value: 5 },
+ { date: new Date( '2023-07-09' ), value: 8 },
+ { date: new Date( '2023-07-16' ), value: 10 },
+ { date: new Date( '2023-07-23' ), value: 12 },
+ { date: new Date( '2023-07-30' ), value: 15 },
+ { date: new Date( '2023-08-06' ), value: 17 },
+ { date: new Date( '2023-08-13' ), value: 20 },
+ { date: new Date( '2023-08-20' ), value: 22 },
+ { date: new Date( '2023-08-27' ), value: 20 },
+ { date: new Date( '2023-09-03' ), value: 18 },
+ { date: new Date( '2023-09-10' ), value: 15 },
+ { date: new Date( '2023-09-17' ), value: 12 },
+ { date: new Date( '2023-09-24' ), value: 8 },
+ { date: new Date( '2023-10-01' ), value: 5 },
+ { date: new Date( '2023-10-08' ), value: 2 },
+ { date: new Date( '2023-10-15' ), value: -2 },
+ { date: new Date( '2023-10-22' ), value: -5 },
+ { date: new Date( '2023-10-29' ), value: -8 },
+ { date: new Date( '2023-11-05' ), value: -12 },
+ { date: new Date( '2023-11-12' ), value: -15 },
+ { date: new Date( '2023-11-19' ), value: -18 },
+ { date: new Date( '2023-11-26' ), value: -22 },
+ { date: new Date( '2023-12-03' ), value: -25 },
+ { date: new Date( '2023-12-10' ), value: -28 },
+ { date: new Date( '2023-12-17' ), value: -32 },
+ { date: new Date( '2023-12-24' ), value: -35 },
+ { date: new Date( '2023-12-31' ), value: -38 },
+ ],
+};
+
+export default temperatureData;
diff --git a/projects/js-packages/charts/src/components/pie-chart/index.tsx b/projects/js-packages/charts/src/components/pie-chart/index.tsx
new file mode 100644
index 0000000000000..c5b0025459ea3
--- /dev/null
+++ b/projects/js-packages/charts/src/components/pie-chart/index.tsx
@@ -0,0 +1 @@
+export { default as PieChart } from './pie-chart';
diff --git a/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx b/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx
new file mode 100644
index 0000000000000..bffe55ea4de25
--- /dev/null
+++ b/projects/js-packages/charts/src/components/pie-chart/pie-chart.tsx
@@ -0,0 +1,113 @@
+import { Group } from '@visx/group';
+import { Pie } from '@visx/shape';
+import { SVGProps } from 'react';
+import useChartMouseHandler from '../../hooks/use-chart-mouse-handler';
+import { useChartTheme, defaultTheme } from '../../providers/theme';
+import { Tooltip } from '../tooltip';
+import type { BaseChartProps, DataPoint } from '../shared/types';
+
+// TODO: add animation
+
+interface PieChartProps extends BaseChartProps< DataPoint[] > {
+ /**
+ * Inner radius in pixels. If > 0, creates a donut chart. Defaults to 0.
+ */
+ innerRadius?: number;
+}
+
+/**
+ * Renders a pie or donut chart using the provided data.
+ *
+ * @param {PieChartProps} props - Component props
+ * @return {JSX.Element} The rendered chart component
+ */
+const PieChart = ( {
+ data,
+ width,
+ height,
+ withTooltips = false,
+ innerRadius = 0,
+}: PieChartProps ) => {
+ const providerTheme = useChartTheme();
+ const { onMouseMove, onMouseLeave, tooltipOpen, tooltipData, tooltipLeft, tooltipTop } =
+ useChartMouseHandler( {
+ withTooltips,
+ } );
+
+ // Calculate radius based on width/height
+ const radius = Math.min( width, height ) / 2;
+ const centerX = width / 2;
+ const centerY = height / 2;
+
+ const accessors = {
+ value: d => d.value,
+ // Use the color property from the data object as a last resort. The theme provides colours by default.
+ fill: d => d.color || providerTheme.colors[ d.index ],
+ };
+
+ return (
+
+
+ { withTooltips && tooltipOpen && tooltipData && (
+
+ ) }
+
+ );
+};
+
+export default PieChart;
diff --git a/projects/js-packages/charts/src/components/pie-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/pie-chart/stories/index.stories.tsx
new file mode 100644
index 0000000000000..ddad97895531d
--- /dev/null
+++ b/projects/js-packages/charts/src/components/pie-chart/stories/index.stories.tsx
@@ -0,0 +1,94 @@
+import { ThemeProvider, jetpackTheme, wooTheme } from '../../../providers/theme';
+import { PieChart } from '../index';
+import type { Meta, StoryObj } from '@storybook/react';
+
+const data = [
+ { label: 'A', value: 30 },
+ { label: 'B', value: 20 },
+ { label: 'C', value: 15 },
+ { label: 'D', value: 35 },
+];
+
+type StoryType = StoryObj< typeof PieChart >;
+
+export default {
+ title: 'JS Packages/Charts/Types/Pie Chart',
+ component: PieChart,
+ parameters: {
+ layout: 'centered',
+ },
+ argTypes: {
+ theme: {
+ control: 'select',
+ options: {
+ default: undefined,
+ jetpack: jetpackTheme,
+ woo: wooTheme,
+ },
+ defaultValue: undefined,
+ },
+ },
+ decorators: [
+ ( Story, { args } ) => (
+
+
+
+
+
+ ),
+ ],
+} satisfies Meta< typeof PieChart >;
+
+export const Default: StoryType = {
+ args: {
+ width: 400,
+ height: 400,
+ withTooltips: false,
+ data,
+ theme: 'default',
+ innerRadius: 0,
+ },
+};
+
+export const Doughnut: StoryType = {
+ args: {
+ ...Default.args,
+ innerRadius: 80,
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Doughnut chart variant with inner radius of 80px.',
+ },
+ },
+ },
+};
+
+export const WithTooltips: StoryType = {
+ args: {
+ ...Default.args,
+ withTooltips: true,
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Pie chart with interactive tooltips that appear on hover.',
+ },
+ },
+ },
+};
+
+export const WithTooltipsDoughnut: StoryType = {
+ args: {
+ ...Default.args,
+ withTooltips: true,
+ innerRadius: 100,
+ },
+ parameters: {
+ docs: {
+ description: {
+ story: 'Doughnut chart with interactive tooltips that appear on hover.',
+ },
+ },
+ },
+};
diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx
index 988e15412b003..4eb3b27ed3263 100644
--- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx
+++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.tsx
@@ -8,23 +8,9 @@ import { FC, useCallback } from 'react';
import { useChartTheme } from '../../providers/theme/theme-provider';
import { BaseTooltip } from '../tooltip';
import styles from './pie-semi-circle-chart.module.scss';
-import type { DataPointPercentage } from '../shared/types';
+import type { BaseChartProps, DataPointPercentage } from '../shared/types';
-type ArcData = PieArcDatum< DataPointPercentage >;
-
-interface PieSemiCircleChartProps {
- /**
- * Array of data points to display in the chart
- */
- data: DataPointPercentage[];
- /**
- * Width of the chart in pixels
- */
- width: number;
- /**
- * Height of the chart in pixels
- */
- height: number;
+interface PieSemiCircleChartProps extends BaseChartProps< DataPointPercentage[] > {
/**
* Label text to display above the chart
*/
@@ -33,19 +19,17 @@ interface PieSemiCircleChartProps {
* Note text to display below the label
*/
note: string;
- /**
- * Whether to show tooltips
- */
- showTooltips?: boolean;
}
+type ArcData = PieArcDatum< DataPointPercentage >;
+
const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( {
data,
width,
height,
label,
note,
- showTooltips = false,
+ withTooltips = false,
} ) => {
const providerTheme = useChartTheme();
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } =
@@ -106,7 +90,7 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( {
data={ dataWithIndex }
pieValue={ accessors.value }
outerRadius={ width / 2 } // half of the diameter (width)
- innerRadius={ ( width / 2 ) * 0.6 } // 70% of the radius
+ innerRadius={ ( width / 2 ) * 0.6 } // 60% of the radius
cornerRadius={ 3 }
padAngle={ 0.03 }
startAngle={ -Math.PI / 2 }
@@ -147,7 +131,7 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( {
- { showTooltips && tooltipOpen && tooltipData && (
+ { withTooltips && tooltipOpen && tooltipData && (
= {
+ /**
+ * Array of data points to display in the chart
+ */
+ data: T extends DataPoint | DataPointDate ? T[] : T;
+ /**
+ * Width of the chart in pixels
+ */
+ width: number;
+ /**
+ * Height of the chart in pixels
+ */
+ height: number;
+ /**
+ * Chart margins
+ */
+ margin?: {
+ top: number;
+ right: number;
+ bottom: number;
+ left: number;
+ };
+ /**
+ * Whether to show tooltips on hover. False by default.
+ */
+ withTooltips?: boolean;
+};
diff --git a/projects/js-packages/charts/src/hooks/use-chart-mouse-handler.ts b/projects/js-packages/charts/src/hooks/use-chart-mouse-handler.ts
new file mode 100644
index 0000000000000..8a1739a90e4ec
--- /dev/null
+++ b/projects/js-packages/charts/src/hooks/use-chart-mouse-handler.ts
@@ -0,0 +1,90 @@
+import { localPoint } from '@visx/event';
+import { useTooltip } from '@visx/tooltip';
+import { useCallback, type MouseEvent } from 'react';
+import type { DataPoint } from '../components/shared/types';
+
+type UseChartMouseHandlerProps = {
+ /**
+ * Whether tooltips are enabled
+ */
+ withTooltips: boolean;
+};
+
+type UseChartMouseHandlerReturn = {
+ /**
+ * Handler for mouse move events
+ */
+ onMouseMove: ( event: React.MouseEvent< SVGElement >, data: DataPoint ) => void;
+ /**
+ * Handler for mouse leave events
+ */
+ onMouseLeave: () => void;
+ /**
+ * Whether the tooltip is currently open
+ */
+ tooltipOpen: boolean;
+ /**
+ * The current tooltip data
+ */
+ tooltipData: DataPoint | null;
+ /**
+ * The current tooltip left position
+ */
+ tooltipLeft: number | undefined;
+ /**
+ * The current tooltip top position
+ */
+ tooltipTop: number | undefined;
+};
+
+/**
+ * Hook to handle mouse interactions for chart components
+ *
+ * @param {UseChartMouseHandlerProps} props - Hook configuration
+ * @return {UseChartMouseHandlerReturn} Object containing handlers and tooltip state
+ */
+const useChartMouseHandler = ( {
+ withTooltips,
+}: UseChartMouseHandlerProps ): UseChartMouseHandlerReturn => {
+ const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } =
+ useTooltip< DataPoint >();
+
+ // TODO: either debounce/throttle or use useTooltipInPortal with built-in debounce
+ const onMouseMove = useCallback(
+ ( event: MouseEvent< SVGElement >, data: DataPoint ) => {
+ if ( ! withTooltips ) {
+ return;
+ }
+
+ const coords = localPoint( event );
+ if ( ! coords ) {
+ return;
+ }
+
+ showTooltip( {
+ tooltipData: data,
+ tooltipLeft: coords.x,
+ tooltipTop: coords.y - 10,
+ } );
+ },
+ [ withTooltips, showTooltip ]
+ );
+
+ const onMouseLeave = useCallback( () => {
+ if ( ! withTooltips ) {
+ return;
+ }
+ hideTooltip();
+ }, [ withTooltips, hideTooltip ] );
+
+ return {
+ onMouseMove,
+ onMouseLeave,
+ tooltipOpen,
+ tooltipData,
+ tooltipLeft,
+ tooltipTop,
+ };
+};
+
+export default useChartMouseHandler;
diff --git a/projects/js-packages/charts/src/index.ts b/projects/js-packages/charts/src/index.ts
index 8dc8f3221948a..b52a51461252c 100644
--- a/projects/js-packages/charts/src/index.ts
+++ b/projects/js-packages/charts/src/index.ts
@@ -1,6 +1,17 @@
+// Charts
export { default as BarChart } from './components/bar-chart';
export { LineChart } from './components/line-chart';
+export { PieChart } from './components/pie-chart';
export { PieSemiCircleChart } from './components/pie-semi-circle-chart';
-export type * from './components/shared/types';
+
+// Chart components
export { BaseTooltip } from './components/tooltip';
+
+// Providers
+export { ThemeProvider } from './providers/theme';
+
+// Hooks
+
+// Types
+export type * from './components/shared/types';
export type { BaseTooltipProps } from './components/tooltip';
diff --git a/projects/js-packages/charts/src/providers/theme/themes.ts b/projects/js-packages/charts/src/providers/theme/themes.ts
index b41d14bd845a1..58bcf3c3fcb31 100644
--- a/projects/js-packages/charts/src/providers/theme/themes.ts
+++ b/projects/js-packages/charts/src/providers/theme/themes.ts
@@ -4,7 +4,8 @@ import type { ChartTheme } from '../../components/shared/types';
* Default theme configuration
*/
const defaultTheme: ChartTheme = {
- backgroundColor: '#FFFFFF',
+ backgroundColor: '#FFFFFF', // chart background color
+ labelBackgroundColor: '#FFFFFF', // label background color
colors: [ '#98C8DF', '#006DAB', '#A6DC80', '#1F9828', '#FF8C8F' ],
gridStyles: {
stroke: '#787C82',
@@ -19,7 +20,8 @@ const defaultTheme: ChartTheme = {
* Jetpack theme configuration
*/
const jetpackTheme: ChartTheme = {
- backgroundColor: '#FFFFFF',
+ backgroundColor: '#FFFFFF', // chart background color
+ labelBackgroundColor: '#FFFFFF', // label background color
colors: [ '#98C8DF', '#006DAB', '#A6DC80', '#1F9828', '#FF8C8F' ],
gridStyles: {
stroke: '#787C82',
@@ -34,7 +36,8 @@ const jetpackTheme: ChartTheme = {
* Woo theme configuration
*/
const wooTheme: ChartTheme = {
- backgroundColor: '#FFFFFF',
+ backgroundColor: '#FFFFFF', // chart background color
+ labelBackgroundColor: '#FFFFFF', // label background color
colors: [ '#80C8FF', '#B999FF', '#3858E9' ],
gridStyles: {
stroke: '#787C82',