diff --git a/projects/js-packages/charts/changelog/charts-175-use-stack-for-layout b/projects/js-packages/charts/changelog/charts-175-use-stack-for-layout new file mode 100644 index 000000000000..45519913e244 --- /dev/null +++ b/projects/js-packages/charts/changelog/charts-175-use-stack-for-layout @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Charts: Replace ad-hoc flexbox layouts with @wordpress/ui Stack across legend, conversion funnel, line chart, geo chart, conversion funnel tooltip, and donut story. diff --git a/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss b/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss index 16da365f498b..52b4891936f0 100644 --- a/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +++ b/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss @@ -7,10 +7,6 @@ } .main-metric { - display: flex; - align-items: baseline; - gap: 8px; - margin-bottom: 24px; height: 20px; } @@ -36,9 +32,6 @@ } .funnel-container { - display: flex; - gap: 16px; - align-items: flex-end; flex: 1; min-height: 200px; width: 100%; @@ -47,8 +40,6 @@ .funnel-step { flex: 1 1 0; min-width: 0; - display: flex; - flex-direction: column; height: 100%; &--animated { @@ -60,10 +51,6 @@ } } -.step-header { - margin-bottom: 24px; -} - .step-label { color: #757575; font-size: var(--wpds-font-size-sm, 12px); @@ -88,8 +75,6 @@ .bar-container { flex: 1; - display: flex; - align-items: flex-end; border-radius: 4px; position: relative; cursor: pointer; @@ -116,12 +101,6 @@ } .tooltip-wrapper { - display: inline-flex; - flex-direction: column; - justify-content: center; - align-items: flex-start; - gap: 4px; - border-bottom: 1px solid var(--Gray-Gray-5, #dcdcde); background: var(--black-white-white, #fff); diff --git a/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx b/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx index 610aba37c5d3..05fb970b5523 100644 --- a/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +++ b/projects/js-packages/charts/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx @@ -263,13 +263,13 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( { // Default tooltip rendering function const renderDefaultTooltip = ( step: FunnelStep ) => ( - <> +
{ step.label }
{ formatPercentage( step.rate ) } { ` • ${ step.count ?? 'no' } items` }
- +
); // Validate data @@ -322,6 +322,7 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( { <> { // Set containerRef for @visx coordinate system @@ -344,27 +345,31 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( { changeColor, } ) ) : ( -
{ renderDefaultMainMetric() }
+ + { renderDefaultMainMetric() } + ) } { /* Funnel Steps */ } -
+ { steps.map( ( step, index ) => { const barHeight = ( step.rate / maxRate ) * 100; const { isBlurred } = getStepState( step.id ); return ( -
{ /* Step Label and Rate */ } -
+
{ renderStepLabel ? ( renderStepLabel( { step, @@ -388,7 +393,9 @@ const ConversionFunnelChartInternal: FC< ConversionFunnelChartProps > = ( {
{ /* Funnel Bar */ } -
= ( { backgroundColor: barColor, } } /> -
-
+ + ); } ) } -
+
{ /* Tooltip Portal */ } diff --git a/projects/js-packages/charts/src/charts/geo-chart/geo-chart.module.scss b/projects/js-packages/charts/src/charts/geo-chart/geo-chart.module.scss index a69330bbc55a..b4a51cf6b002 100644 --- a/projects/js-packages/charts/src/charts/geo-chart/geo-chart.module.scss +++ b/projects/js-packages/charts/src/charts/geo-chart/geo-chart.module.scss @@ -1,6 +1,3 @@ .container { position: relative; - display: flex; - justify-content: center; - align-items: center; } diff --git a/projects/js-packages/charts/src/charts/geo-chart/geo-chart.tsx b/projects/js-packages/charts/src/charts/geo-chart/geo-chart.tsx index b2e9dc5d998e..db0e1464ff1f 100644 --- a/projects/js-packages/charts/src/charts/geo-chart/geo-chart.tsx +++ b/projects/js-packages/charts/src/charts/geo-chart/geo-chart.tsx @@ -2,6 +2,7 @@ * External dependencies */ import { __ } from '@wordpress/i18n'; +import { Stack } from '@wordpress/ui'; import clsx from 'clsx'; import { FC, useContext, useMemo } from 'react'; import { Chart, type GoogleChartOptions } from 'react-google-charts'; @@ -57,13 +58,15 @@ const GeoChartInternal: FC< GeoChartProps > = ( { // Render loading placeholder const loadingPlaceholder = ( -
{ renderPlaceholder ? renderPlaceholder() : __( 'Loading map', 'jetpack-charts' ) } -
+ ); // Google charts doesn't accept CSS variables, so we need to convert them to hex colors @@ -144,7 +147,9 @@ const GeoChartInternal: FC< GeoChartProps > = ( { ); return ( -
= ( { options={ options } loader={ loadingPlaceholder } /> -
+ ); }; diff --git a/projects/js-packages/charts/src/charts/line-chart/line-chart.module.scss b/projects/js-packages/charts/src/charts/line-chart/line-chart.module.scss index 027e9d18faac..67d40905763a 100644 --- a/projects/js-packages/charts/src/charts/line-chart/line-chart.module.scss +++ b/projects/js-packages/charts/src/charts/line-chart/line-chart.module.scss @@ -26,10 +26,7 @@ } &__tooltip-row { - display: flex; - align-items: center; padding: 4px 0; - justify-content: space-between; } &__tooltip-label { @@ -81,13 +78,6 @@ } } - &__annotation-label-popover-header { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: start; - } - &__annotation-label-popover-content { padding: 0.5rem; } diff --git a/projects/js-packages/charts/src/charts/line-chart/line-chart.tsx b/projects/js-packages/charts/src/charts/line-chart/line-chart.tsx index 43b846e5db27..8757e34fb190 100644 --- a/projects/js-packages/charts/src/charts/line-chart/line-chart.tsx +++ b/projects/js-packages/charts/src/charts/line-chart/line-chart.tsx @@ -4,6 +4,7 @@ import { LinearGradient } from '@visx/gradient'; import { scaleTime } from '@visx/scale'; import { XYChart, AreaSeries, Grid, Axis, DataContext } from '@visx/xychart'; import { __ } from '@wordpress/i18n'; +import { Stack } from '@wordpress/ui'; import clsx from 'clsx'; import { differenceInHours, differenceInYears } from 'date-fns'; import { @@ -103,12 +104,18 @@ const renderDefaultTooltip = ( params: RenderTooltipParams< DataPointDate > ) => { nearestDatum.date?.toLocaleDateString() }
{ tooltipPoints.map( point => ( -
+ { point.key }: { formatNumber( point.value ) } -
+
) ) } ); diff --git a/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx b/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx index 6b5f15e9a88f..787fa729e54b 100644 --- a/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx +++ b/projects/js-packages/charts/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx @@ -1,5 +1,6 @@ import { __ } from '@wordpress/i18n'; import { Icon, close } from '@wordpress/icons'; +import { Stack } from '@wordpress/ui'; import clsx from 'clsx'; import { useEffect, useId, useRef, useState } from 'react'; import { isSafari } from '../../../utils'; @@ -88,7 +89,7 @@ const LineChartAnnotationLabelWithPopover: FC< LineChartAnnotationLabelWithPopov ) } data-testid="line-chart-annotation-label-popover" > -
+
{ renderLabelPopover( { title, subtitle } ) }
@@ -102,7 +103,7 @@ const LineChartAnnotationLabelWithPopover: FC< LineChartAnnotationLabelWithPopov > -
+ ); diff --git a/projects/js-packages/charts/src/charts/pie-chart/stories/donut.stories.tsx b/projects/js-packages/charts/src/charts/pie-chart/stories/donut.stories.tsx index 7ea4afecb3c5..2732e0a210fa 100644 --- a/projects/js-packages/charts/src/charts/pie-chart/stories/donut.stories.tsx +++ b/projects/js-packages/charts/src/charts/pie-chart/stories/donut.stories.tsx @@ -1,6 +1,4 @@ -/* eslint-disable @wordpress/no-unsafe-wp-apis */ -import { __experimentalHStack as HStack } from '@wordpress/components'; -import { Text } from '@wordpress/ui'; +import { Stack, Text } from '@wordpress/ui'; import { Fragment } from 'react'; import { BaseLegendItem } from '../../../components/legend/types'; import { @@ -267,7 +265,7 @@ const CustomPieLegend = ( { return ( - +
{ item.label } - + { item.formattedValue } diff --git a/projects/js-packages/charts/src/components/legend/private/base-legend.module.scss b/projects/js-packages/charts/src/components/legend/private/base-legend.module.scss index 64ced1a401ec..d29410dcc58c 100644 --- a/projects/js-packages/charts/src/components/legend/private/base-legend.module.scss +++ b/projects/js-packages/charts/src/components/legend/private/base-legend.module.scss @@ -1,49 +1,8 @@ .legend { align-self: stretch; - - &--horizontal { - display: flex; - flex-direction: row; - flex-wrap: wrap; - gap: 16px; - } - - &--vertical { - display: flex; - flex-direction: column; - gap: 8px; - } - - &--alignment-start { - justify-content: flex-start; - } - - &--alignment-center { - justify-content: center; - } - - &--alignment-end { - justify-content: flex-end; - } - - // Vertical legends align on the cross-axis instead - &--vertical.legend--alignment-start { - align-items: flex-start; - } - - &--vertical.legend--alignment-center { - align-items: center; - } - - &--vertical.legend--alignment-end { - align-items: flex-end; - } - } .legend-item { - display: flex; - align-items: center; font-size: var(--wpds-font-size-md, 13px); &--interactive { @@ -75,14 +34,6 @@ } } -.legend-item-label { - display: flex; - align-items: center; - gap: 0.5rem; - - /* Text wrapping is handled at the text level, not the label container */ -} - .legend-item-text { &--wrap { diff --git a/projects/js-packages/charts/src/components/legend/private/base-legend.tsx b/projects/js-packages/charts/src/components/legend/private/base-legend.tsx index df56e784f968..125c9c6cf437 100644 --- a/projects/js-packages/charts/src/components/legend/private/base-legend.tsx +++ b/projects/js-packages/charts/src/components/legend/private/base-legend.tsx @@ -1,6 +1,7 @@ import { Group } from '@visx/group'; import { LegendItem, LegendLabel, LegendOrdinal, LegendShape } from '@visx/legend'; import { scaleOrdinal } from '@visx/scale'; +import { Stack } from '@wordpress/ui'; import clsx from 'clsx'; import { type RefAttributes, @@ -16,10 +17,11 @@ import { valueOrIdentity, valueOrIdentityString, labelTransformFactory } from '. import styles from './base-legend.module.scss'; import type { BaseLegendProps } from '../types'; -const orientationToFlexDirection = { - horizontal: 'row' as const, - vertical: 'column' as const, -}; +const ALIGNMENT_TO_FLEX = { + start: 'flex-start', + center: 'center', + end: 'flex-end', +} as const; // Component for legend text with truncation detection // Moved outside BaseLegend to prevent recreation on every render @@ -159,6 +161,8 @@ export const BaseLegend: ForwardRefExoticComponent< [ interactive, handleLegendClick ] ); + const flexAlignment = ALIGNMENT_TO_FLEX[ alignment ] ?? 'center'; + return render ? ( render( items ) ) : ( @@ -168,20 +172,17 @@ export const BaseLegend: ForwardRefExoticComponent< labelTransform={ labelTransform } > { labels => ( -
{ labels.map( ( label, i ) => { const visible = isSeriesVisible( label.text ); @@ -257,28 +258,29 @@ export const BaseLegend: ForwardRefExoticComponent< labelClassName ) } style={ { - justifyContent: labelJustifyContent, flex: labelFlex, margin: labelMargin, ...theme.legend?.labelStyles, } } > - - { matchedItem?.value != null && matchedItem.value !== '' && ( - - { '\u00A0' } - { matchedItem.value } - - ) } + + + { matchedItem?.value != null && matchedItem.value !== '' && ( + + { '\u00A0' } + { matchedItem.value } + + ) } + ); } ) } -
+ ) } );