@automattic/charts 4.1.1 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -0
- package/TOKENS.md +1 -1
- package/dist/index.cjs +1335 -348
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +30 -1
- package/dist/index.d.cts +129 -8
- package/dist/index.d.ts +129 -8
- package/dist/index.js +1336 -351
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/charts/area-chart/area-chart.tsx +42 -10
- package/src/charts/area-chart/private/overlays.tsx +1 -2
- package/src/charts/area-chart/private/validate-data.ts +2 -3
- package/src/charts/area-chart/test/area-chart.test.tsx +72 -1
- package/src/charts/bar-chart/bar-chart.tsx +137 -70
- package/src/charts/bar-chart/index.ts +1 -1
- package/src/charts/bar-chart/private/band-highlight.tsx +87 -0
- package/src/charts/bar-chart/private/band-scale.ts +13 -0
- package/src/charts/bar-chart/private/band-tooltip.tsx +138 -0
- package/src/charts/bar-chart/private/comparison-bars.tsx +5 -10
- package/src/charts/bar-chart/private/index.ts +3 -0
- package/src/charts/bar-chart/private/test/band-highlight.test.tsx +135 -0
- package/src/charts/bar-chart/private/test/band-tooltip.test.ts +26 -0
- package/src/charts/bar-chart/private/test/value-domain.test.ts +100 -0
- package/src/charts/bar-chart/private/truncated-tick-component.tsx +1 -1
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +13 -40
- package/src/charts/bar-chart/private/value-domain.ts +90 -0
- package/src/charts/bar-chart/test/bar-chart-pointer-events.test.tsx +11 -23
- package/src/charts/bar-chart/test/bar-chart.test.tsx +1058 -19
- package/src/charts/bar-chart/types.ts +39 -0
- package/src/charts/bar-list-chart/bar-list-chart.tsx +5 -3
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +1 -1
- package/src/charts/conversion-funnel-chart/types.ts +4 -2
- package/src/charts/geo-chart/types.ts +4 -2
- package/src/charts/heatmap-chart/build-calendar-data.ts +5 -11
- package/src/charts/heatmap-chart/build-month-calendar-data.ts +124 -0
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +32 -0
- package/src/charts/heatmap-chart/heatmap-chart.tsx +191 -114
- package/src/charts/heatmap-chart/index.ts +6 -0
- package/src/charts/heatmap-chart/private/civil-day.ts +26 -0
- package/src/charts/heatmap-chart/private/column-groups.ts +71 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +19 -3
- package/src/charts/heatmap-chart/private/index.ts +2 -0
- package/src/charts/heatmap-chart/private/keyboard-navigation.ts +201 -0
- package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +36 -0
- package/src/charts/heatmap-chart/test/build-month-calendar-data.test.ts +194 -0
- package/src/charts/heatmap-chart/test/column-groups.test.ts +83 -0
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +428 -2
- package/src/charts/heatmap-chart/test/keyboard-navigation.test.ts +25 -0
- package/src/charts/heatmap-chart/test/use-month-calendar-heatmap-data.test.tsx +90 -0
- package/src/charts/heatmap-chart/test/zoned-month-calendar-data.test.ts +23 -0
- package/src/charts/heatmap-chart/types.ts +59 -3
- package/src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts +34 -0
- package/src/charts/leaderboard-chart/types.ts +13 -14
- package/src/charts/line-chart/line-chart.tsx +149 -36
- package/src/charts/line-chart/private/index.ts +1 -0
- package/src/charts/line-chart/private/line-chart-annotation.tsx +1 -1
- package/src/charts/line-chart/private/line-chart-glyph.tsx +17 -3
- package/src/charts/line-chart/private/nearest-pointer-events.tsx +155 -0
- package/src/charts/line-chart/test/line-chart.test.tsx +604 -9
- package/src/charts/line-chart/types.ts +4 -3
- package/src/charts/private/readings.ts +34 -0
- package/src/charts/private/test/readings.test.ts +29 -0
- package/src/charts/private/test/whole-number-ticks.test.tsx +57 -0
- package/src/charts/private/time-axis-options.ts +1 -1
- package/src/charts/private/whole-number-ticks.tsx +79 -0
- package/src/charts/private/with-responsive/with-responsive.tsx +2 -2
- package/src/charts/private/x-zoom/test/x-zoom.test.tsx +1 -3
- package/src/charts/private/x-zoom/x-zoom.tsx +1 -2
- package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +124 -0
- package/src/components/legend/hooks/use-chart-legend-items.ts +60 -2
- package/src/components/legend/private/base-legend.tsx +37 -22
- package/src/components/legend/test/legend.test.tsx +84 -0
- package/src/components/legend/types.ts +2 -0
- package/src/components/legend/utils/index.ts +0 -1
- package/src/components/tooltip/accessible-tooltip.tsx +128 -41
- package/src/components/tooltip/base-tooltip.module.scss +6 -1
- package/src/components/tooltip/private/bounded-tooltip.tsx +12 -6
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +128 -0
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +17 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +7 -0
- package/src/components/tooltip/xy-chart-tooltip.tsx +9 -10
- package/src/hooks/test/use-chart-margin.test.tsx +35 -0
- package/src/hooks/test/use-element-size.test.tsx +13 -13
- package/src/hooks/use-chart-margin.tsx +7 -2
- package/src/hooks/use-xychart-theme.ts +1 -1
- package/src/index.ts +7 -1
- package/src/providers/chart-context/global-charts-provider.tsx +1 -1
- package/src/providers/chart-context/test/chart-context.test.tsx +4 -4
- package/src/providers/chart-context/themes.ts +1 -0
- package/src/styles/test/chart-scope.test.ts +1 -1
- package/src/types.ts +14 -13
- package/src/utils/format-metric-value.ts +4 -4
- package/src/utils/get-edge-tick-widths.ts +1 -1
- package/src/utils/get-styles.ts +1 -1
- package/src/visx/types.ts +7 -10
- package/src/components/legend/utils/label-transform-factory.ts +0 -24
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { EnhancedDataPoint } from '../../../hooks/use-zero-value-display';
|
|
2
|
+
import type { DataPoint, DataPointDate, SeriesData } from '../../../types';
|
|
3
|
+
|
|
4
|
+
/** Domain for a value axis that has nothing to scale, so its ticks still read 0 to 1. */
|
|
5
|
+
const EMPTY_DOMAIN: [ number, number ] = [ 0, 1 ];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The value a bar is drawn at, preferring `visualValue` so a zero still shows a sliver.
|
|
9
|
+
*
|
|
10
|
+
* A missing reading is NaN, not null: `ComparisonBars` coerces the value with `Number()`,
|
|
11
|
+
* which turns null into 0 and would draw a comparison shadow at the baseline.
|
|
12
|
+
*
|
|
13
|
+
* @param point - A data point handed to visx.
|
|
14
|
+
* @return The bar value, or NaN when the bucket has no reading.
|
|
15
|
+
*/
|
|
16
|
+
export const getBarValue = ( point: DataPoint | DataPointDate | EnhancedDataPoint ): number => {
|
|
17
|
+
const enhanced = point as EnhancedDataPoint;
|
|
18
|
+
const value = enhanced?.visualValue !== undefined ? enhanced.visualValue : point?.value;
|
|
19
|
+
return value ?? NaN;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Whether visx renders a bar for a point.
|
|
24
|
+
*
|
|
25
|
+
* @param point - A data point handed to visx.
|
|
26
|
+
* @return True when the point has a finite bar value.
|
|
27
|
+
*/
|
|
28
|
+
export const isBarRendered = ( point: DataPoint | DataPointDate | EnhancedDataPoint ): boolean =>
|
|
29
|
+
Number.isFinite( getBarValue( point ) );
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* How many bars visx renders for a list of points.
|
|
33
|
+
*
|
|
34
|
+
* @param points - Data points handed to visx.
|
|
35
|
+
* @return The number of points that get a bar.
|
|
36
|
+
*/
|
|
37
|
+
export const countRenderedBars = (
|
|
38
|
+
points: ReadonlyArray< DataPoint | DataPointDate | EnhancedDataPoint >
|
|
39
|
+
): number => points.filter( isBarRendered ).length;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* An explicit domain for the value scale, or null to let visx fit one to the data.
|
|
43
|
+
*
|
|
44
|
+
* Zero goes into the domain here rather than through the scale's `zero` flag: visx applies
|
|
45
|
+
* `nice` before `zero`, which would leave the axis topping out at a raw maximum.
|
|
46
|
+
*
|
|
47
|
+
* @param data - Every series handed to the chart.
|
|
48
|
+
* @param includeZero - Whether the domain must span zero.
|
|
49
|
+
* @param isSeriesRendered - Whether visx mounts a series, i.e. the legend shows it.
|
|
50
|
+
* @return Value domain, or null when visx should fit its own.
|
|
51
|
+
*/
|
|
52
|
+
export const getValueScaleDomain = (
|
|
53
|
+
data: SeriesData[],
|
|
54
|
+
includeZero: boolean,
|
|
55
|
+
isSeriesRendered: ( series: SeriesData ) => boolean
|
|
56
|
+
): [ number, number ] | null => {
|
|
57
|
+
let min = Infinity;
|
|
58
|
+
let max = -Infinity;
|
|
59
|
+
|
|
60
|
+
// Only hidden series are skipped. Comparison series count too: visx sees just the
|
|
61
|
+
// primary BarSeries and would fit a domain too narrow for the comparison shadows.
|
|
62
|
+
for ( const series of data ) {
|
|
63
|
+
if ( ! isSeriesRendered( series ) ) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
for ( const point of series.data ) {
|
|
67
|
+
const value = getBarValue( point );
|
|
68
|
+
if ( ! Number.isFinite( value ) ) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
min = Math.min( min, value );
|
|
72
|
+
max = Math.max( max, value );
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if ( min === Infinity ) {
|
|
77
|
+
return [ ...EMPTY_DOMAIN ];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// A flat series fitted by visx collapses to zero height, so it is anchored at zero regardless.
|
|
81
|
+
if ( min === max ) {
|
|
82
|
+
return min === 0 ? [ ...EMPTY_DOMAIN ] : [ Math.min( 0, min ), Math.max( 0, max ) ];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if ( includeZero ) {
|
|
86
|
+
return [ Math.min( 0, min ), Math.max( 0, max ) ];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return null;
|
|
90
|
+
};
|
|
@@ -1,25 +1,13 @@
|
|
|
1
1
|
import { render } from '@testing-library/react';
|
|
2
2
|
import { GlobalChartsProvider } from '../../../providers';
|
|
3
3
|
import BarChart from '../bar-chart';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
jest.mock( '@visx/xychart', () => {
|
|
12
|
-
const actual = jest.requireActual( '@visx/xychart' );
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
__esModule: true,
|
|
16
|
-
...actual,
|
|
17
|
-
XYChart: ( props: { children?: ReactNode } ) => {
|
|
18
|
-
mockXYChart( props );
|
|
19
|
-
return <svg />;
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
} );
|
|
4
|
+
const mockBandTooltip = jest.fn();
|
|
5
|
+
jest.mock( '../private/band-tooltip', () => ( {
|
|
6
|
+
BandTooltip: props => {
|
|
7
|
+
mockBandTooltip( props );
|
|
8
|
+
return null;
|
|
9
|
+
},
|
|
10
|
+
} ) );
|
|
23
11
|
|
|
24
12
|
const mockRefCallback = jest.fn();
|
|
25
13
|
jest.mock( '../../../hooks/use-element-size', () => ( {
|
|
@@ -38,7 +26,7 @@ const DATA = [
|
|
|
38
26
|
];
|
|
39
27
|
|
|
40
28
|
/**
|
|
41
|
-
* Render the chart with the recorder standing in for
|
|
29
|
+
* Render the chart with the recorder standing in for band pointer handling.
|
|
42
30
|
*
|
|
43
31
|
* @param props - Props layered onto the defaults.
|
|
44
32
|
* @return The render result.
|
|
@@ -52,15 +40,15 @@ function renderBarChart( props = {} ) {
|
|
|
52
40
|
}
|
|
53
41
|
|
|
54
42
|
describe( 'BarChart pointer events', () => {
|
|
55
|
-
beforeEach( () =>
|
|
43
|
+
beforeEach( () => mockBandTooltip.mockClear() );
|
|
56
44
|
|
|
57
|
-
test( '
|
|
45
|
+
test( 'routes pointer handlers through band correction without requiring tooltips', () => {
|
|
58
46
|
const onPointerDown = jest.fn();
|
|
59
47
|
const onPointerUp = jest.fn();
|
|
60
48
|
|
|
61
49
|
renderBarChart( { onPointerDown, onPointerUp } );
|
|
62
50
|
|
|
63
|
-
const props =
|
|
51
|
+
const props = mockBandTooltip.mock.calls.at( -1 )[ 0 ];
|
|
64
52
|
expect( props.onPointerDown ).toBe( onPointerDown );
|
|
65
53
|
expect( props.onPointerUp ).toBe( onPointerUp );
|
|
66
54
|
} );
|