diff --git a/.pnpm-patches/@wordpress__dataviews@4.10.0.patch b/.pnpm-patches/@wordpress__dataviews@4.10.0.patch new file mode 100644 index 0000000000000..49656b5f977cc --- /dev/null +++ b/.pnpm-patches/@wordpress__dataviews@4.10.0.patch @@ -0,0 +1,15 @@ +Hack for https://github.com/WordPress/gutenberg/issues/67897 + +diff --git a/package.json b/package.json +index d7af17fea3f59f807a9d7234cf9ce79131538383..c862b012af312c9fc5cf1d2d884ec332ee079d0b 100644 +--- a/package.json ++++ b/package.json +@@ -27,7 +27,7 @@ + "exports": { + ".": { + "types": "./build-types/index.d.ts", +- "import": "./build-module/index.js" ++ "default": "./build/index.js" + }, + "./wp": { + "types": "./build-types/index.d.ts", diff --git a/package.json b/package.json index 605f3c28d9302..c48245d935c8a 100644 --- a/package.json +++ b/package.json @@ -37,5 +37,10 @@ "node": "^22.9.0", "pnpm": "^9.3.0 <9.12.0" }, - "packageManager": "pnpm@9.3.0" + "packageManager": "pnpm@9.3.0", + "pnpm": { + "patchedDependencies": { + "@wordpress/dataviews@4.10.0": ".pnpm-patches/@wordpress__dataviews@4.10.0.patch" + } + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f1a0aef04261..d2a2a658b2b2a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,6 +6,11 @@ settings: pnpmfileChecksum: kmseazxfbymwdp5ie53bnph5mq +patchedDependencies: + '@wordpress/dataviews@4.10.0': + hash: of6mtpeubmoicukrgy5ohupf6a + path: .pnpm-patches/@wordpress__dataviews@4.10.0.patch + importers: .: @@ -382,8 +387,8 @@ importers: specifier: 10.14.0 version: 10.14.0(react@18.3.1) '@wordpress/dataviews': - specifier: 4.9.0 - version: 4.9.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 4.10.0 + version: 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': specifier: 5.14.0 version: 5.14.0 @@ -1070,8 +1075,8 @@ importers: specifier: 10.14.0 version: 10.14.0(react@18.3.1) '@wordpress/dataviews': - specifier: 4.9.0 - version: 4.9.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 4.10.0 + version: 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': specifier: 5.14.0 version: 5.14.0 @@ -8129,8 +8134,8 @@ packages: peerDependencies: react: ^18.0.0 - '@wordpress/dataviews@4.9.0': - resolution: {integrity: sha512-ucAQx1dwlHU8WyhNSfl/OEc8hFNwIy2/XkNAjduelrMqbNiOOue5mfKjO43zqKT/ZFVvju/gUU7gnTX1A98tCA==} + '@wordpress/dataviews@4.10.0': + resolution: {integrity: sha512-Rsp5wUTTGAJlbWdkdFHGXq06LU6F/Kvki6IT9byexu+984h3F+VNIyVCP1BQPqNAWhsUHD4o0gIZKzH17zrCbw==} engines: {node: '>=18.12.0', npm: '>=8.19.2'} peerDependencies: react: ^18.0.0 @@ -19621,7 +19626,7 @@ snapshots: rememo: 4.0.2 use-memo-one: 1.1.3(react@18.3.1) - '@wordpress/dataviews@4.9.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@wordpress/dataviews@4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@ariakit/react': 0.4.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@babel/runtime': 7.25.7 @@ -19643,7 +19648,7 @@ snapshots: - react-dom - supports-color - '@wordpress/dataviews@4.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@wordpress/dataviews@4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@ariakit/react': 0.4.15(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@babel/runtime': 7.25.7 @@ -19792,7 +19797,7 @@ snapshots: '@wordpress/compose': 7.14.0(react@18.3.1) '@wordpress/core-data': 7.14.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': 10.14.0(react@18.3.1) - '@wordpress/dataviews': 4.9.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@wordpress/dataviews': 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': 5.14.0 '@wordpress/deprecated': 4.13.0 '@wordpress/dom': 4.13.0 @@ -19851,7 +19856,7 @@ snapshots: '@wordpress/compose': 7.14.0(react@18.3.1) '@wordpress/core-data': 7.14.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': 10.14.0(react@18.3.1) - '@wordpress/dataviews': 4.9.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@wordpress/dataviews': 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': 5.14.0 '@wordpress/deprecated': 4.13.0 '@wordpress/dom': 4.13.0 @@ -19910,7 +19915,7 @@ snapshots: '@wordpress/compose': 7.14.0(react@18.3.1) '@wordpress/core-data': 7.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': 10.14.0(react@18.3.1) - '@wordpress/dataviews': 4.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@wordpress/dataviews': 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': 5.14.0 '@wordpress/deprecated': 4.13.0 '@wordpress/dom': 4.13.0 @@ -20006,7 +20011,7 @@ snapshots: '@wordpress/compose': 7.14.0(react@18.3.1) '@wordpress/core-data': 7.14.0(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': 10.14.0(react@18.3.1) - '@wordpress/dataviews': 4.9.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@wordpress/dataviews': 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': 5.14.0 '@wordpress/element': 6.14.0 '@wordpress/hooks': 4.14.0 @@ -20045,7 +20050,7 @@ snapshots: '@wordpress/compose': 7.14.0(react@18.3.1) '@wordpress/core-data': 7.14.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': 10.14.0(react@18.3.1) - '@wordpress/dataviews': 4.9.0(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@wordpress/dataviews': 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': 5.14.0 '@wordpress/element': 6.14.0 '@wordpress/hooks': 4.14.0 @@ -20084,7 +20089,7 @@ snapshots: '@wordpress/compose': 7.14.0(react@18.3.1) '@wordpress/core-data': 7.14.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': 10.14.0(react@18.3.1) - '@wordpress/dataviews': 4.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@wordpress/dataviews': 4.10.0(patch_hash=of6mtpeubmoicukrgy5ohupf6a)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/date': 5.14.0 '@wordpress/element': 6.14.0 '@wordpress/hooks': 4.14.0 diff --git a/projects/js-packages/charts/changelog/update-charts-library-tooltip-iteration b/projects/js-packages/charts/changelog/update-charts-library-tooltip-iteration new file mode 100644 index 0000000000000..b95e70a4acf87 --- /dev/null +++ b/projects/js-packages/charts/changelog/update-charts-library-tooltip-iteration @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +Chart Library: Update tooltip component diff --git a/projects/js-packages/charts/src/components/bar-chart/bar-chart.module.scss b/projects/js-packages/charts/src/components/bar-chart/bar-chart.module.scss new file mode 100644 index 0000000000000..ec94022ab4d88 --- /dev/null +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.module.scss @@ -0,0 +1,3 @@ +.bar-chart { + position: relative; +} 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 new file mode 100644 index 0000000000000..7c6f4976eaa06 --- /dev/null +++ b/projects/js-packages/charts/src/components/bar-chart/bar-chart.tsx @@ -0,0 +1,107 @@ +import { AxisLeft, AxisBottom } from '@visx/axis'; +import { localPoint } from '@visx/event'; +import { Group } from '@visx/group'; +import { scaleBand, scaleLinear } from '@visx/scale'; +import { Bar } from '@visx/shape'; +import { useTooltip } from '@visx/tooltip'; +import clsx from 'clsx'; +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 { BaseChartProps, DataPoint } from '../shared/types'; + +interface BarChartProps extends BaseChartProps { + /** + * Array of data points to display in the chart + */ + data: DataPoint[]; +} + +const BarChart: FC< BarChartProps > = ( { + data, + width, + height, + margin = { top: 20, right: 20, bottom: 40, left: 40 }, + withTooltips = false, + className, +} ) => { + const theme = useChartTheme(); + const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = + useTooltip< DataPoint >(); + + const margins = margin; + const xMax = width - margins.left - margins.right; + const yMax = height - margins.top - margins.bottom; + + const xScale = scaleBand< string >( { + range: [ 0, xMax ], + domain: data.map( d => d.label ), + padding: 0.2, + } ); + + const yScale = scaleLinear< number >( { + range: [ yMax, 0 ], + domain: [ 0, Math.max( ...data.map( d => d.value ) ) ], + } ); + + const handleMouseMove = useCallback( + ( event: MouseEvent< SVGRectElement >, datum: DataPoint ) => { + const coords = localPoint( event ); + if ( ! coords ) return; + + showTooltip( { + tooltipData: datum, + tooltipLeft: coords.x, + tooltipTop: coords.y - 10, + } ); + }, + [ showTooltip ] + ); + + const handleMouseLeave = useCallback( () => { + hideTooltip(); + }, [ hideTooltip ] ); + + return ( +
+ + + { data.map( d => { + const handleBarMouseMove = event => handleMouseMove( event, d ); + + return ( + + ); + } ) } + + + + + + { withTooltips && tooltipOpen && tooltipData && ( + + ) } +
+ ); +}; + +BarChart.displayName = 'BarChart'; + +export default BarChart; diff --git a/projects/js-packages/charts/src/components/bar-chart/index.tsx b/projects/js-packages/charts/src/components/bar-chart/index.tsx index f3a1e21790eba..df4a1f97ba3ad 100644 --- a/projects/js-packages/charts/src/components/bar-chart/index.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/index.tsx @@ -1,113 +1 @@ -import { AxisLeft, AxisBottom } from '@visx/axis'; -import { localPoint } from '@visx/event'; -import { Group } from '@visx/group'; -import { scaleBand, scaleLinear } from '@visx/scale'; -import { Bar } from '@visx/shape'; -import { useTooltip } from '@visx/tooltip'; -import clsx from 'clsx'; -import React from 'react'; -import { useChartTheme } from '../../providers/theme'; -import { Tooltip } from '../tooltip'; -import type { BaseChartProps, DataPoint } from '../shared/types'; - -interface BarChartProps extends BaseChartProps { - /** - * Array of data points to display in the chart - */ - data: DataPoint[]; -} - -/** - * Renders a bar chart using the provided data. - * - * @param {BarChartProps} props - Component props - * @return {JSX.Element} The rendered bar chart component - */ -function BarChart( { - data, - width, - height, - margin, - withTooltips = false, - className, -}: BarChartProps ) { - const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = - useTooltip< DataPoint >(); - - const theme = useChartTheme(); - const margins = { top: 20, right: 20, bottom: 40, left: 40, ...margin }; - const xMax = width - margins.left - margins.right; - const yMax = height - margins.top - margins.bottom; - - const xScale = scaleBand< string >( { - range: [ 0, xMax ], - domain: data.map( d => d.label ), - padding: 0.2, - } ); - - const yScale = scaleLinear< number >( { - range: [ yMax, 0 ], - domain: [ 0, Math.max( ...data.map( d => d.value ) ) ], - } ); - - const handleMouseMove = React.useCallback( - ( event: React.MouseEvent< SVGRectElement >, datum: DataPoint ) => { - const coords = localPoint( event ); - if ( ! coords ) return; - - showTooltip( { - tooltipData: datum, - tooltipLeft: coords.x, - tooltipTop: coords.y - 10, - } ); - }, - [ showTooltip ] - ); - - const handleMouseLeave = React.useCallback( () => { - hideTooltip(); - }, [ hideTooltip ] ); - - const getMouseMoveHandler = React.useCallback( - ( d: DataPoint ) => { - if ( ! withTooltips ) return undefined; - return ( event: React.MouseEvent< SVGRectElement > ) => handleMouseMove( event, d ); - }, - [ withTooltips, handleMouseMove ] - ); - - return ( -
- - - { data.map( d => ( - - ) ) } - - - - - { tooltipOpen && tooltipData && ( - - ) } -
- ); -} - -export default BarChart; +export { default } from './bar-chart'; diff --git a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx index 45ae2a989c737..5e7f98699165d 100644 --- a/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/bar-chart/stories/index.stories.tsx @@ -23,21 +23,17 @@ export const Default = Template.bind( {} ); Default.args = { width: 500, height: 300, - showTooltips: false, + margin: { top: 20, right: 20, bottom: 40, left: 40 }, + withTooltips: false, data: data[ 0 ].data, }; export const WithTooltips = Template.bind( {} ); WithTooltips.args = { ...Default.args, - showTooltips: true, - data: [ - { label: 'Q1', value: 420 }, - { label: 'Q2', value: 650 }, - { label: 'Q3', value: 850 }, - { label: 'Q4', value: 950 }, - ], + withTooltips: true, }; + WithTooltips.parameters = { docs: { description: { diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss index 6ff61d27acf34..54c0bfb01e098 100644 --- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/pie-semi-circle-chart.module.scss @@ -1,3 +1,15 @@ .pie-semi-circle-chart { position: relative; + text-align: center; + + .label { + margin-bottom: 0px; // Add space between label and pie chart + font-weight: 600; // Make label more prominent than note + font-size: 16px; // Set explicit font size + } + + .note { + margin-top: 0px; // Add space between pie chart and note + font-size: 14px; // Slightly smaller text for hierarchy + } } 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 8b7a9993fb6a6..a6f0d30e6d68b 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 @@ -1,9 +1,12 @@ +import { localPoint } from '@visx/event'; import { Group } from '@visx/group'; -import { Pie } from '@visx/shape'; +import Pie, { PieArcDatum } from '@visx/shape/lib/shapes/Pie'; import { Text } from '@visx/text'; +import { useTooltip } from '@visx/tooltip'; import clsx from 'clsx'; -import { FC } from 'react'; +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 { BaseChartProps, DataPointPercentage } from '../shared/types'; @@ -18,6 +21,8 @@ interface PieSemiCircleChartProps extends BaseChartProps< DataPointPercentage[] note: string; } +type ArcData = PieArcDatum< DataPointPercentage >; + const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { data, width, @@ -25,59 +30,121 @@ const PieSemiCircleChart: FC< PieSemiCircleChartProps > = ( { label, note, className, + withTooltips = false, } ) => { const providerTheme = useChartTheme(); + const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = + useTooltip< DataPointPercentage >(); + const centerX = width / 2; const centerY = height; + // Map the data to include index for color assignment + const dataWithIndex = data.map( ( d, index ) => ( { + ...d, + index, + } ) ); + const accessors = { - value: d => d.value, - sort: ( a, b ) => a.value - b.value, + value: ( d: DataPointPercentage & { index: number } ) => d.value, + sort: ( + a: DataPointPercentage & { index: number }, + b: DataPointPercentage & { index: number } + ) => b.value - a.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 ], + fill: ( d: DataPointPercentage & { index: number } ) => + d.color || providerTheme.colors[ d.index % providerTheme.colors.length ], }; + const handleMouseMove = useCallback( + ( event: React.MouseEvent, arc: ArcData ) => { + const coords = localPoint( event ); + if ( ! coords ) return; + + showTooltip( { + tooltipData: arc.data, + tooltipLeft: coords.x, + tooltipTop: coords.y - 10, + } ); + }, + [ showTooltip ] + ); + + const handleMouseLeave = useCallback( () => { + hideTooltip(); + }, [ hideTooltip ] ); + + const handleArcMouseMove = useCallback( + ( arc: ArcData ) => ( event: React.MouseEvent ) => { + handleMouseMove( event, arc ); + }, + [ handleMouseMove ] + ); + return (
+ { /* Main chart group that contains both the pie and text elements */ } - - data={ data } + { /* Pie chart */ } + + data={ dataWithIndex } pieValue={ accessors.value } - outerRadius={ 100 } - innerRadius={ 70 } + outerRadius={ width / 2 } // half of the diameter (width) + innerRadius={ ( width / 2 ) * 0.6 } // 60% of the radius cornerRadius={ 3 } padAngle={ 0.03 } startAngle={ -Math.PI / 2 } endAngle={ Math.PI / 2 } pieSort={ accessors.sort } - fill={ accessors.fill } - /> + > + { pie => { + return pie.arcs.map( arc => ( + + + + ) ); + } } + + { label } { note } + + { withTooltips && tooltipOpen && tooltipData && ( + + ) }
); }; diff --git a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx index cfc4f50d7453c..219b15dbf9064 100644 --- a/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/pie-semi-circle-chart/stories/index.stories.tsx @@ -5,19 +5,19 @@ const data = [ { label: 'Windows', value: 80000, - valueDisplay: '$80K', + valueDisplay: '80K', percentage: 2, }, { label: 'MacOS', value: 30000, - valueDisplay: '$30K', + valueDisplay: '30K', percentage: 5, }, { label: 'Linux', value: 22000, - valueDisplay: '$22K', + valueDisplay: '22K', percentage: 1, }, ]; @@ -47,3 +47,13 @@ Default.args = { label: 'OS', note: 'Windows +10%', }; + +export const WithTooltips = Template.bind( {} ); +WithTooltips.args = { + width: 500, + height: 300, + data, + label: 'OS', + note: 'Windows +10%', + withTooltips: true, +}; diff --git a/projects/js-packages/charts/src/components/tooltip/base-tooltip.module.scss b/projects/js-packages/charts/src/components/tooltip/base-tooltip.module.scss new file mode 100644 index 0000000000000..e848fdc91adee --- /dev/null +++ b/projects/js-packages/charts/src/components/tooltip/base-tooltip.module.scss @@ -0,0 +1,11 @@ +.tooltip { + padding: 0.5rem; + background-color: rgba(0, 0, 0, 0.85); + color: white; + border-radius: 4px; + font-size: 14px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + position: absolute; + pointer-events: none; + transform: translate(-50%, -100%); +} diff --git a/projects/js-packages/charts/src/components/tooltip/base-tooltip.tsx b/projects/js-packages/charts/src/components/tooltip/base-tooltip.tsx new file mode 100644 index 0000000000000..8c7964ea7e048 --- /dev/null +++ b/projects/js-packages/charts/src/components/tooltip/base-tooltip.tsx @@ -0,0 +1,44 @@ +import styles from './base-tooltip.module.scss'; +import type { CSSProperties, ComponentType } from 'react'; + +type TooltipData = { + label: string; + value: number; + valueDisplay?: string; +}; + +type TooltipComponentProps = { + data: TooltipData; + className?: string; +}; + +type BaseTooltipProps = { + data: TooltipData; + top: number; + left: number; + style?: CSSProperties; + component?: ComponentType< TooltipComponentProps >; + className?: string; +}; + +const DefaultTooltipContent = ( { data }: TooltipComponentProps ) => ( + <> + { data.label }: { data.valueDisplay || data.value } + +); + +export const BaseTooltip = ( { + data, + top, + left, + component: Component = DefaultTooltipContent, + className, +}: BaseTooltipProps ) => { + return ( +
+ +
+ ); +}; + +export type { BaseTooltipProps, TooltipData }; diff --git a/projects/js-packages/charts/src/components/tooltip/index.ts b/projects/js-packages/charts/src/components/tooltip/index.ts new file mode 100644 index 0000000000000..e7d00cf3a0fa6 --- /dev/null +++ b/projects/js-packages/charts/src/components/tooltip/index.ts @@ -0,0 +1,2 @@ +export { BaseTooltip } from './base-tooltip'; +export type { BaseTooltipProps, TooltipData } from './base-tooltip'; diff --git a/projects/js-packages/charts/src/components/tooltip/index.tsx b/projects/js-packages/charts/src/components/tooltip/index.tsx deleted file mode 100644 index 3aa503cd4919f..0000000000000 --- a/projects/js-packages/charts/src/components/tooltip/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import type { TooltipProps } from './types'; -import type { ReactNode, CSSProperties, ComponentType } from 'react'; - -const defaultTooltipStyles = { - padding: '0.5rem', - backgroundColor: 'rgba(0,0,0,0.85)', - color: 'white', - borderRadius: '4px', - fontSize: '14px', - boxShadow: '0 1px 2px rgba(0,0,0,0.1)', -}; - -interface TooltipComponentProps { - data: TooltipProps[ 'data' ]; - className?: string; -} - -const DefaultTooltipContent = ( { data }: TooltipComponentProps ) => ( - <> - { data.label }: { data.value } - -); - -interface ExtendedTooltipProps { - top: number; - left: number; - style?: CSSProperties; - data: TooltipProps[ 'data' ]; - component?: ComponentType< TooltipComponentProps >; - children?: ReactNode; - className?: string; -} - -/** - * Tooltip component that can be customized with different content components - * @param {object} props - Component properties - * @param {TooltipProps['data']} props.data - Data to be displayed in the tooltip - * @param {number} props.top - Distance from top of container in pixels - * @param {number} props.left - Distance from left of container in pixels - * @param {CSSProperties} props.style - Additional CSS styles to apply to tooltip - * @param {ComponentType} props.component - Custom component to render tooltip content - * @param {string} props.className - Additional CSS class names - * @return {JSX.Element} Rendered tooltip component - */ -export const Tooltip = ( { - data, - top, - left, - style = {}, - component: Component = DefaultTooltipContent, - className, -}: ExtendedTooltipProps ) => { - return ( -
- -
- ); -}; diff --git a/projects/js-packages/charts/src/components/tooltip/stories/index.stories.tsx b/projects/js-packages/charts/src/components/tooltip/stories/index.stories.tsx index 832873db77817..0af79a7d0de00 100644 --- a/projects/js-packages/charts/src/components/tooltip/stories/index.stories.tsx +++ b/projects/js-packages/charts/src/components/tooltip/stories/index.stories.tsx @@ -1,13 +1,6 @@ -import { Tooltip } from '../index'; -import type { TooltipProps } from '../types'; +import { BaseTooltip } from '../index'; import type { Meta } from '@storybook/react'; -/** - * Custom tooltip component example that shows a different layout - * @param {object} props - Component properties - * @param {TooltipProps['data']} props.data - The data to display in the tooltip - * @return {JSX.Element} Custom tooltip content component - */ const CustomTooltipContent = ( { data } ) => (
{ data.label } @@ -17,7 +10,7 @@ const CustomTooltipContent = ( { data } ) => ( export default { title: 'JS Packages/Charts/Tooltip', - component: Tooltip, + component: BaseTooltip, parameters: { layout: 'centered', docs: { @@ -45,13 +38,8 @@ export default { control: 'object', }, }, -} satisfies Meta< typeof Tooltip >; +} satisfies Meta< typeof BaseTooltip >; -/** - * Template with a visible container to better demonstrate positioning - * @param {object} args - Story arguments - * @return {JSX.Element} Story template component - */ const Template = args => (
( background: '#f5f5f5', } } > -
- Tooltip Container -
- +
); @@ -84,14 +61,7 @@ Default.args = { left: 100, data: { label: 'Monthly Sales', - value: '$4,200', - }, -}; -Default.parameters = { - docs: { - description: { - story: 'Default tooltip implementation with basic styling.', - }, + value: 4200, }, }; @@ -101,7 +71,7 @@ CustomComponent.args = { component: CustomTooltipContent, data: { label: 'Q4 Performance', - value: '+27%', + value: 27, }, style: { backgroundColor: '#fff', @@ -109,34 +79,3 @@ CustomComponent.args = { boxShadow: '0 2px 8px rgba(0,0,0,0.15)', }, }; -CustomComponent.parameters = { - docs: { - description: { - story: 'Example of a custom tooltip component with different styling and layout.', - }, - }, -}; - -export const StyledTooltip = Template.bind( {} ); -StyledTooltip.args = { - ...Default.args, - data: { - label: 'Active Users', - value: '1,234', - }, - style: { - backgroundColor: '#2c5282', - color: '#fff', - padding: '1rem', - borderRadius: '8px', - fontSize: '16px', - fontWeight: 'bold', - }, -}; -StyledTooltip.parameters = { - docs: { - description: { - story: 'Tooltip with custom styling applied through the style prop.', - }, - }, -}; diff --git a/projects/js-packages/charts/src/components/tooltip/types.ts b/projects/js-packages/charts/src/components/tooltip/types.ts index 5747a0aa73d00..fc7570794557c 100644 --- a/projects/js-packages/charts/src/components/tooltip/types.ts +++ b/projects/js-packages/charts/src/components/tooltip/types.ts @@ -1,6 +1,8 @@ -export interface TooltipProps { +type TooltipProps = { data: { label: string; value: number; }; -} +}; + +export type { TooltipProps }; diff --git a/projects/js-packages/charts/src/index.ts b/projects/js-packages/charts/src/index.ts index 5847237506be1..b52a51461252c 100644 --- a/projects/js-packages/charts/src/index.ts +++ b/projects/js-packages/charts/src/index.ts @@ -5,7 +5,7 @@ export { PieChart } from './components/pie-chart'; export { PieSemiCircleChart } from './components/pie-semi-circle-chart'; // Chart components -export { Tooltip } from './components/tooltip'; +export { BaseTooltip } from './components/tooltip'; // Providers export { ThemeProvider } from './providers/theme'; @@ -14,4 +14,4 @@ export { ThemeProvider } from './providers/theme'; // Types export type * from './components/shared/types'; -export type { TooltipProps } from './components/tooltip/types'; +export type { BaseTooltipProps } from './components/tooltip'; diff --git a/projects/js-packages/components/changelog/fix-components-threats-data-views-default-layouts b/projects/js-packages/components/changelog/fix-components-threats-data-views-default-layouts new file mode 100644 index 0000000000000..64fa3036e7810 --- /dev/null +++ b/projects/js-packages/components/changelog/fix-components-threats-data-views-default-layouts @@ -0,0 +1,4 @@ +Significance: minor +Type: changed + +Fixes ThreatsDataViews defaultLayouts diff --git a/projects/js-packages/components/changelog/renovate-wordpress-monorepo#2 b/projects/js-packages/components/changelog/renovate-wordpress-monorepo#2 new file mode 100644 index 0000000000000..c47cb18e82997 --- /dev/null +++ b/projects/js-packages/components/changelog/renovate-wordpress-monorepo#2 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Updated package dependencies. diff --git a/projects/js-packages/components/components/threats-data-views/constants.ts b/projects/js-packages/components/components/threats-data-views/constants.ts index 59b79a7618453..cc37c28c7b39b 100644 --- a/projects/js-packages/components/components/threats-data-views/constants.ts +++ b/projects/js-packages/components/components/threats-data-views/constants.ts @@ -22,8 +22,8 @@ export const THREAT_TYPES = [ ]; export const THREAT_ICONS = { - plugin: pluginIcon, - theme: themeIcon, + plugins: pluginIcon, + themes: themeIcon, core: coreIcon, file: fileIcon, default: shieldIcon, diff --git a/projects/js-packages/components/components/threats-data-views/index.tsx b/projects/js-packages/components/components/threats-data-views/index.tsx index 6af7c028f4c3a..44efc998dc3ae 100644 --- a/projects/js-packages/components/components/threats-data-views/index.tsx +++ b/projects/js-packages/components/components/threats-data-views/index.tsx @@ -33,7 +33,6 @@ import { THREAT_FIELD_SIGNATURE, THREAT_FIELD_STATUS, THREAT_FIELD_THEME, - THREAT_FIELD_THREAT, THREAT_FIELD_TITLE, THREAT_FIELD_TYPE, THREAT_ICONS, @@ -101,23 +100,10 @@ export default function ThreatsDataViews( { const defaultLayouts: SupportedLayouts = { table: { ...baseView, - fields: [ - THREAT_FIELD_SEVERITY, - THREAT_FIELD_THREAT, - THREAT_FIELD_TYPE, - THREAT_FIELD_AUTO_FIX, - ], - layout: { - primaryField: THREAT_FIELD_SEVERITY, - combinedFields: [ - { - id: THREAT_FIELD_THREAT, - label: __( 'Threat', 'jetpack-components' ), - children: [ THREAT_FIELD_TITLE, THREAT_FIELD_DESCRIPTION ], - direction: 'vertical', - }, - ], - }, + fields: [ THREAT_FIELD_SEVERITY, THREAT_FIELD_TYPE, THREAT_FIELD_AUTO_FIX ], + titleField: THREAT_FIELD_TITLE, + descriptionField: THREAT_FIELD_DESCRIPTION, + showMedia: false, }, list: { ...baseView, @@ -127,10 +113,9 @@ export default function ThreatsDataViews( { THREAT_FIELD_EXTENSION, THREAT_FIELD_SIGNATURE, ], - layout: { - primaryField: THREAT_FIELD_TITLE, - mediaField: THREAT_FIELD_ICON, - }, + titleField: THREAT_FIELD_TITLE, + mediaField: THREAT_FIELD_ICON, + showMedia: true, }, }; @@ -222,7 +207,7 @@ export default function ThreatsDataViews( { const result: Field< Threat >[] = [ { id: THREAT_FIELD_TITLE, - label: __( 'Title', 'jetpack-components' ), + label: __( 'Threat', 'jetpack-components' ), enableGlobalSearch: true, enableHiding: false, render: ( { item }: { item: Threat } ) => ( diff --git a/projects/js-packages/components/package.json b/projects/js-packages/components/package.json index 25ea7c73ba5d0..df315974e18ed 100644 --- a/projects/js-packages/components/package.json +++ b/projects/js-packages/components/package.json @@ -22,7 +22,7 @@ "@wordpress/components": "29.0.0", "@wordpress/compose": "7.14.0", "@wordpress/data": "10.14.0", - "@wordpress/dataviews": "4.9.0", + "@wordpress/dataviews": "4.10.0", "@wordpress/date": "5.14.0", "@wordpress/element": "6.14.0", "@wordpress/i18n": "5.14.0", diff --git a/projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo#2 b/projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo#2 new file mode 100644 index 0000000000000..c47cb18e82997 --- /dev/null +++ b/projects/js-packages/publicize-components/changelog/renovate-wordpress-monorepo#2 @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Updated package dependencies. diff --git a/projects/js-packages/publicize-components/package.json b/projects/js-packages/publicize-components/package.json index 6ec1c474d893c..9a9c568e62665 100644 --- a/projects/js-packages/publicize-components/package.json +++ b/projects/js-packages/publicize-components/package.json @@ -34,7 +34,7 @@ "@wordpress/compose": "7.14.0", "@wordpress/core-data": "7.14.0", "@wordpress/data": "10.14.0", - "@wordpress/dataviews": "4.9.0", + "@wordpress/dataviews": "4.10.0", "@wordpress/date": "5.14.0", "@wordpress/edit-post": "8.14.0", "@wordpress/editor": "14.14.0", diff --git a/projects/packages/jetpack-mu-wpcom/changelog/fix-migration-diy-throws-403-on-page-reload b/projects/packages/jetpack-mu-wpcom/changelog/fix-migration-diy-throws-403-on-page-reload new file mode 100644 index 0000000000000..f6c66cc0de6aa --- /dev/null +++ b/projects/packages/jetpack-mu-wpcom/changelog/fix-migration-diy-throws-403-on-page-reload @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Fix migration key fetch failing when DIY migration page is reloaded diff --git a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-site-migration-wpcom-migration-key.php b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-site-migration-wpcom-migration-key.php index 955e839d2da66..5cd20cc4dd25c 100644 --- a/projects/packages/jetpack-mu-wpcom/src/features/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-site-migration-wpcom-migration-key.php +++ b/projects/packages/jetpack-mu-wpcom/src/features/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-site-migration-wpcom-migration-key.php @@ -12,13 +12,6 @@ * @hide-in-jetpack */ class WPCOM_REST_API_V2_Endpoint_Site_Migration_WPCOM_Migration_Key extends WP_REST_Controller { - /** - * Option name that tracks wether the key has been read or not. - * The only possible value for the option is 'read'. - * - * @var string - */ - protected $key_is_read_option_name = 'wpcom_site_migration_wpcom_migration_key_read'; /** * Class constructor @@ -73,10 +66,6 @@ public function can_access() { return false; } - if ( 'read' === get_option( $this->key_is_read_option_name, false ) ) { - return false; - } - return true; } @@ -89,8 +78,6 @@ private function get_migration_key() { $wpcom_migration_settings = new WPCOMWPSettings(); $wpcom_migration_info = new WPCOMInfo( $wpcom_migration_settings ); - update_option( $this->key_is_read_option_name, 'read' ); - return $wpcom_migration_info->getConnectionKey(); } diff --git a/projects/plugins/jetpack/changelog/fix-manual-plugin-updates b/projects/plugins/jetpack/changelog/fix-manual-plugin-updates new file mode 100644 index 0000000000000..b9e7c7872762f --- /dev/null +++ b/projects/plugins/jetpack/changelog/fix-manual-plugin-updates @@ -0,0 +1,4 @@ +Significance: patch +Type: other + +API Endpoints: make sure manual plugin updates applied when auto update is disabled diff --git a/projects/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php b/projects/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php index 60be46e04d5fc..66baa5a5d250b 100644 --- a/projects/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php +++ b/projects/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php @@ -383,9 +383,12 @@ protected function deactivate() { */ protected function update() { $query_args = $this->query_args(); + + $is_automatic_update = false; if ( isset( $query_args['autoupdate'] ) && $query_args['autoupdate'] || $this->scheduled_update ) { - Constants::set_constant( 'JETPACK_PLUGIN_AUTOUPDATE', true ); + $is_automatic_update = true; } + if ( $this->scheduled_update ) { Constants::set_constant( 'SCHEDULED_AUTOUPDATE', true ); } @@ -416,7 +419,7 @@ protected function update() { // Early return if unable to obtain auto_updater lock. // @see https://github.com/WordPress/wordpress-develop/blob/66469efa99e7978c8824e287834135aa9842e84f/src/wp-admin/includes/class-wp-automatic-updater.php#L453. - if ( Constants::get_constant( 'JETPACK_PLUGIN_AUTOUPDATE' ) && ! WP_Upgrader::create_lock( 'auto_updater', $lock_release_timeout ) ) { + if ( $is_automatic_update && ! WP_Upgrader::create_lock( 'auto_updater', $lock_release_timeout ) ) { return new WP_Error( 'update_fail', __( 'Updates are already in progress.', 'jetpack' ), 400 ); } @@ -430,7 +433,7 @@ protected function update() { } // Rely on WP_Automatic_Updater class to check if a plugin item should be updated if it is a Jetpack autoupdate request. - if ( Constants::get_constant( 'JETPACK_PLUGIN_AUTOUPDATE' ) && ! ( new WP_Automatic_Updater() )->should_update( 'plugin', $update_plugins->response[ $plugin ], WP_PLUGIN_DIR ) ) { + if ( $is_automatic_update && ! ( new WP_Automatic_Updater() )->should_update( 'plugin', $update_plugins->response[ $plugin ], WP_PLUGIN_DIR ) ) { continue; } @@ -473,7 +476,7 @@ protected function update() { } // release auto_udpate lock. - if ( Constants::get_constant( 'JETPACK_PLUGIN_AUTOUPDATE' ) ) { + if ( $is_automatic_update ) { WP_Upgrader::release_lock( 'auto_updater' ); }