@automattic/charts 4.6.0 → 4.8.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 +32 -0
- package/TOKENS.md +15 -10
- package/dist/index.cjs +427 -211
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +40 -26
- package/dist/index.d.cts +69 -29
- package/dist/index.d.ts +69 -29
- package/dist/index.js +427 -213
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/charts/area-chart/area-chart.tsx +2 -2
- package/src/charts/area-chart/test/area-chart.test.tsx +1 -1
- package/src/charts/area-chart/test/tooltip-resolution-branches.test.tsx +1 -1
- package/src/charts/bar-chart/bar-chart.module.scss +7 -0
- package/src/charts/bar-chart/bar-chart.tsx +20 -14
- package/src/charts/bar-chart/private/comparison-bars.tsx +1 -0
- package/src/charts/bar-chart/test/bar-chart.test.tsx +25 -0
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +0 -10
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +5 -3
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +20 -1
- package/src/charts/conversion-funnel-chart/types.ts +3 -0
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +16 -7
- package/src/charts/heatmap-chart/heatmap-chart.tsx +80 -53
- package/src/charts/heatmap-chart/private/heatmap-context.ts +2 -2
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +2 -2
- package/src/charts/heatmap-chart/private/heatmap-scale.ts +74 -0
- package/src/charts/heatmap-chart/private/index.ts +2 -1
- package/src/charts/heatmap-chart/private/use-heatmap-colors.ts +24 -6
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +221 -25
- package/src/charts/heatmap-chart/test/heatmap-scale.test.ts +78 -0
- package/src/charts/heatmap-chart/test/use-heatmap-colors.test.ts +18 -6
- package/src/charts/heatmap-chart/types.ts +6 -9
- package/src/charts/line-chart/crosshair-style-types.fixture.ts +23 -0
- package/src/charts/line-chart/line-chart.module.scss +0 -5
- package/src/charts/line-chart/line-chart.tsx +10 -42
- package/src/charts/line-chart/test/line-chart.test.tsx +19 -47
- package/src/charts/pie-chart/pie-chart.module.scss +9 -0
- package/src/charts/pie-chart/pie-chart.tsx +26 -80
- package/src/charts/pie-chart/test/pie-chart.test.tsx +21 -8
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +4 -4
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +1 -1
- package/src/charts/private/chart-composition/chart-html.tsx +1 -1
- package/src/charts/private/chart-composition/chart-svg.tsx +1 -1
- package/src/charts/private/label-text-color.ts +116 -0
- package/src/charts/private/radial-wipe-animation/radial-wipe-animation.tsx +2 -0
- package/src/charts/private/svg-empty-state/svg-empty-state.tsx +1 -1
- package/src/charts/private/test/label-text-color.test.ts +189 -0
- package/src/charts/private/with-responsive/test/with-responsive.test.tsx +1 -0
- package/src/charts/private/with-responsive/with-responsive.tsx +2 -5
- package/src/components/tooltip/base-tooltip.tsx +31 -30
- package/src/components/tooltip/index.ts +3 -1
- package/src/components/tooltip/private/bounded-tooltip.tsx +32 -13
- package/src/components/tooltip/private/label-value-content.tsx +8 -0
- package/src/components/tooltip/private/tooltip-theme.tsx +37 -0
- package/src/components/tooltip/private/xy-chart-tooltip-overlay.tsx +336 -0
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +82 -1
- package/src/components/tooltip/test/tool-tip.test.tsx +10 -3
- package/src/components/tooltip/test/tooltip-box.test.tsx +53 -0
- package/src/components/tooltip/test/tooltip-theme.test.tsx +61 -0
- package/src/components/tooltip/test/xy-chart-tooltip-overlay.test.tsx +445 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +286 -356
- package/src/components/tooltip/tooltip-box.module.scss +21 -0
- package/src/components/tooltip/tooltip-box.tsx +43 -0
- package/src/components/tooltip/types.ts +7 -1
- package/src/components/tooltip/xy-chart-tooltip.tsx +411 -301
- package/src/components/trend-indicator/trend-indicator.tsx +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/test/use-chart-margin.test.tsx +8 -4
- package/src/hooks/test/use-xychart-theme.test.tsx +3 -3
- package/src/hooks/use-chart-margin.tsx +21 -18
- package/src/hooks/use-isomorphic-layout-effect.ts +5 -0
- package/src/hooks/use-xychart-theme.ts +4 -12
- package/src/index.ts +8 -3
- package/src/providers/chart-context/global-charts-provider.tsx +5 -14
- package/src/providers/chart-context/hooks/use-default-hidden-series.ts +3 -5
- package/src/providers/chart-context/private/catalog-pointers.ts +1 -0
- package/src/providers/chart-context/private/perceptual-color.ts +45 -4
- package/src/providers/chart-context/private/resolve-opaque-hex.ts +16 -0
- package/src/providers/chart-context/test/perceptual-color.test.ts +31 -0
- package/src/providers/chart-context/test/use-default-hidden-series.test.tsx +1 -1
- package/src/styles/chart-scope-class.ts +5 -0
- package/src/styles/chart-scope.scss +10 -6
- package/src/styles/test/chart-scope.test.ts +3 -3
- package/src/test-utils/zoned-parsing-suite.ts +0 -10
- package/src/utils/color-utils.ts +2 -1
- package/src/utils/test/date-formatting.test.ts +0 -10
- package/src/visx/types.ts +1 -1
- package/src/charts/line-chart/test/crosshair-style-types.test.ts +0 -31
- package/src/components/tooltip/accessible-tooltip.tsx +0 -433
- package/src/components/tooltip/base-tooltip.module.scss +0 -20
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +0 -331
package/dist/index.cjs
CHANGED
|
@@ -29,18 +29,19 @@ let clsx = require("clsx");
|
|
|
29
29
|
clsx = __toESM(clsx, 1);
|
|
30
30
|
let react = require("react");
|
|
31
31
|
react = __toESM(react);
|
|
32
|
-
let _visx_vendor_d3_color = require("@visx/vendor/d3-color");
|
|
33
32
|
let date_fns = require("date-fns");
|
|
34
33
|
let _date_fns_tz = require("@date-fns/tz");
|
|
35
34
|
let _visx_text = require("@visx/text");
|
|
36
35
|
let deepmerge = require("deepmerge");
|
|
37
36
|
deepmerge = __toESM(deepmerge, 1);
|
|
37
|
+
let _visx_vendor_d3_color = require("@visx/vendor/d3-color");
|
|
38
38
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
39
39
|
let _visx_tooltip = require("@visx/tooltip");
|
|
40
40
|
let _visx_scale = require("@visx/scale");
|
|
41
41
|
let _visx_group = require("@visx/group");
|
|
42
42
|
let _visx_legend = require("@visx/legend");
|
|
43
43
|
let _wordpress_ui = require("@wordpress/ui");
|
|
44
|
+
let _wordpress_theme = require("@wordpress/theme");
|
|
44
45
|
let react_dom = require("react-dom");
|
|
45
46
|
let _visx_gradient = require("@visx/gradient");
|
|
46
47
|
let _visx_curve = require("@visx/curve");
|
|
@@ -562,7 +563,8 @@ const relativeLuminance = (hex) => {
|
|
|
562
563
|
* Whether light text reads better than dark text on the given background, using the W3C
|
|
563
564
|
* luminance threshold (0.179) that maximizes contrast against black vs white.
|
|
564
565
|
*
|
|
565
|
-
* @
|
|
566
|
+
* @deprecated Assumes black and white text, so it ignores label role overrides and cannot guarantee AA; charts no longer use it, and it will be removed in a future major version.
|
|
567
|
+
* @param backgroundHex - Hex background color
|
|
566
568
|
* @return true if light text should be used; false (dark text) for malformed colors
|
|
567
569
|
*/
|
|
568
570
|
const prefersLightText = (backgroundHex) => {
|
|
@@ -834,6 +836,7 @@ const CATALOG_POINTERS = {
|
|
|
834
836
|
annotation: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
835
837
|
surface: "var(--a8c-charts-color-surface, #fff)",
|
|
836
838
|
surfaceSecondary: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
839
|
+
track: "var(--a8c-charts-color-track, #f0f0f0)",
|
|
837
840
|
trendUp: "var(--a8c-charts-color-trend-up, #008030)",
|
|
838
841
|
trendDown: "var(--a8c-charts-color-trend-down, #cc1818)",
|
|
839
842
|
series: SERIES_PALETTE_POINTERS
|
|
@@ -881,14 +884,27 @@ const PROTANOPIA = [
|
|
|
881
884
|
const DEGREES = Math.PI / 180;
|
|
882
885
|
const toLinear = (channel) => channel <= .04045 ? channel / 12.92 : Math.pow((channel + .055) / 1.055, 2.4);
|
|
883
886
|
const fromLinear = (channel) => channel <= .0031308 ? 12.92 * channel : 1.055 * Math.pow(channel, 1 / 2.4) - .055;
|
|
884
|
-
|
|
887
|
+
/**
|
|
888
|
+
* The sRGB channels of a hex color.
|
|
889
|
+
*
|
|
890
|
+
* @param hex - A six-digit hex color.
|
|
891
|
+
* @return Channels from 0 to 255.
|
|
892
|
+
* @throws {Error} if the hex string is malformed
|
|
893
|
+
*/
|
|
894
|
+
const hexToRgb = (hex) => {
|
|
885
895
|
validateHexColor(hex);
|
|
886
|
-
|
|
896
|
+
const [r, g, b] = [
|
|
887
897
|
1,
|
|
888
898
|
3,
|
|
889
899
|
5
|
|
890
|
-
].map((start) =>
|
|
900
|
+
].map((start) => parseInt(hex.slice(start, start + 2), 16));
|
|
901
|
+
return [
|
|
902
|
+
r,
|
|
903
|
+
g,
|
|
904
|
+
b
|
|
905
|
+
];
|
|
891
906
|
};
|
|
907
|
+
const hexToLinear = (hex) => hexToRgb(hex).map((channel) => toLinear(channel / 255));
|
|
892
908
|
const linearToHex = (linear) => "#" + linear.map((channel) => Math.round(Math.min(1, Math.max(0, fromLinear(channel))) * 255).toString(16).padStart(2, "0")).join("");
|
|
893
909
|
const simulate = (matrix, [r, g, b]) => [
|
|
894
910
|
0,
|
|
@@ -1014,6 +1030,35 @@ const hexToOklch = (hex) => {
|
|
|
1014
1030
|
};
|
|
1015
1031
|
};
|
|
1016
1032
|
/**
|
|
1033
|
+
* `foreground` over `background` at `weight`, left unrounded as CSS `color-mix` and alpha compositing leave it.
|
|
1034
|
+
*
|
|
1035
|
+
* A mix rounded to hex can land on the other side of a contrast threshold from the fill the browser paints.
|
|
1036
|
+
*
|
|
1037
|
+
* @param foreground - The color weighted by `weight`.
|
|
1038
|
+
* @param background - The color it is mixed over.
|
|
1039
|
+
* @param weight - Share of `foreground`, from 0 to 1.
|
|
1040
|
+
* @return The mixed channels.
|
|
1041
|
+
*/
|
|
1042
|
+
const blendRgb = (foreground, background, weight) => {
|
|
1043
|
+
const share = Math.min(1, Math.max(0, weight));
|
|
1044
|
+
const [r, g, b] = foreground.map((channel, i) => background[i] + (channel - background[i]) * share);
|
|
1045
|
+
return [
|
|
1046
|
+
r,
|
|
1047
|
+
g,
|
|
1048
|
+
b
|
|
1049
|
+
];
|
|
1050
|
+
};
|
|
1051
|
+
/**
|
|
1052
|
+
* WCAG relative luminance of unrounded sRGB channels.
|
|
1053
|
+
*
|
|
1054
|
+
* @param rgb - Channels from 0 to 255.
|
|
1055
|
+
* @return Relative luminance from 0 to 1.
|
|
1056
|
+
*/
|
|
1057
|
+
const rgbLuminance = (rgb) => {
|
|
1058
|
+
const [r, g, b] = rgb.map((channel) => toLinear(channel / 255));
|
|
1059
|
+
return .2126 * r + .7152 * g + .0722 * b;
|
|
1060
|
+
};
|
|
1061
|
+
/**
|
|
1017
1062
|
* WCAG contrast ratio between two relative luminances.
|
|
1018
1063
|
*
|
|
1019
1064
|
* @param first - First relative luminance.
|
|
@@ -1220,6 +1265,14 @@ const buildPaletteGenerator = (normalizedSeeds, background, labelColors) => {
|
|
|
1220
1265
|
};
|
|
1221
1266
|
};
|
|
1222
1267
|
//#endregion
|
|
1268
|
+
//#region src/providers/chart-context/private/resolve-opaque-hex.ts
|
|
1269
|
+
const resolveOpaqueHex = (pointer, resolve) => {
|
|
1270
|
+
const raw = resolve(pointer);
|
|
1271
|
+
if (!raw || (0, _visx_vendor_d3_color.color)(raw)?.opacity !== 1) return null;
|
|
1272
|
+
const hex = normalizeColorToHex(raw);
|
|
1273
|
+
return isValidHexColor(hex) ? hex : null;
|
|
1274
|
+
};
|
|
1275
|
+
//#endregion
|
|
1223
1276
|
//#region src/providers/chart-context/themes.ts
|
|
1224
1277
|
/**
|
|
1225
1278
|
* Default theme configuration: the shape and spacing a consumer can override.
|
|
@@ -1268,12 +1321,6 @@ const defaultTheme = {
|
|
|
1268
1321
|
};
|
|
1269
1322
|
//#endregion
|
|
1270
1323
|
//#region src/providers/chart-context/global-charts-provider.tsx
|
|
1271
|
-
const resolveOpaqueHex = (pointer, element) => {
|
|
1272
|
-
const raw = resolveCssVariable(pointer, element);
|
|
1273
|
-
if (!raw || (0, _visx_vendor_d3_color.color)(raw)?.opacity !== 1) return null;
|
|
1274
|
-
const hex = normalizeColorToHex(pointer, element, resolveCssVariable);
|
|
1275
|
-
return isValidHexColor(hex) ? hex : null;
|
|
1276
|
-
};
|
|
1277
1324
|
const PLACEHOLDER_LABEL_COLORS = [LABEL_FALLBACK, LABEL_INVERSE_FALLBACK];
|
|
1278
1325
|
const GlobalChartsContext = (0, react.createContext)(null);
|
|
1279
1326
|
const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
@@ -1301,8 +1348,9 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
|
1301
1348
|
const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
|
|
1302
1349
|
if (isValidHexColor(normalizedColor)) resolvedColors.push(normalizedColor);
|
|
1303
1350
|
}
|
|
1304
|
-
const
|
|
1305
|
-
const
|
|
1351
|
+
const resolveAtWrapper = createCssVariableResolver(wrapperRef.current);
|
|
1352
|
+
const backgroundHex = resolveOpaqueHex(CATALOG_POINTERS.background, resolveAtWrapper) ?? "#ffffff";
|
|
1353
|
+
const labelColors = [CATALOG_POINTERS.label, CATALOG_POINTERS.labelInverse].map((pointer) => resolveOpaqueHex(pointer, resolveAtWrapper)).filter((hex) => hex !== null);
|
|
1306
1354
|
setColorCache({
|
|
1307
1355
|
colors: resolvedColors,
|
|
1308
1356
|
background: backgroundHex,
|
|
@@ -1534,15 +1582,13 @@ const useXYChartTheme = (data) => {
|
|
|
1534
1582
|
const resolve = createCssVariableResolver(scopeElement);
|
|
1535
1583
|
const resolveColor = (value) => value ? resolve(value) ?? value : value;
|
|
1536
1584
|
const paletteColors = [...JSON.parse(seriesColorKey), ...CATALOG_POINTERS.series].map((color) => resolveColor(color)).filter((color) => Boolean(color) && !color.includes("var("));
|
|
1537
|
-
const resolvedLabelColor = resolveColor(CATALOG_POINTERS.labelAxis);
|
|
1538
|
-
const htmlLabelColor = resolvedLabelColor ? normalizeColorToHex(resolvedLabelColor) || resolvedLabelColor : resolvedLabelColor;
|
|
1539
1585
|
return (0, _visx_xychart.buildChartTheme)({
|
|
1540
1586
|
...theme,
|
|
1541
1587
|
gridColor: "",
|
|
1542
1588
|
gridColorDark: "",
|
|
1543
1589
|
colors: paletteColors,
|
|
1544
1590
|
backgroundColor: resolveColor(CATALOG_POINTERS.background),
|
|
1545
|
-
htmlLabel:
|
|
1591
|
+
htmlLabel: { color: CATALOG_POINTERS.labelAxis },
|
|
1546
1592
|
gridStyles: {
|
|
1547
1593
|
...theme.gridStyles,
|
|
1548
1594
|
stroke: CATALOG_POINTERS.grid
|
|
@@ -1640,10 +1686,10 @@ const DEFAULT_MARGIN_BOTTOM = 20;
|
|
|
1640
1686
|
*/
|
|
1641
1687
|
const DEFAULT_MARGIN_LEFT = 20;
|
|
1642
1688
|
/**
|
|
1643
|
-
* Bottom margin
|
|
1689
|
+
* Bottom margin when no X-axis sits below the chart, because it is on top or hidden.
|
|
1644
1690
|
* We only need a small buffer below the chart in that case.
|
|
1645
1691
|
*/
|
|
1646
|
-
const
|
|
1692
|
+
const DEFAULT_BOTTOM_WITHOUT_X_AXIS = 10;
|
|
1647
1693
|
/**
|
|
1648
1694
|
* Fallback font size used when we cannot derive a font size
|
|
1649
1695
|
* from the theme or axis styles for X-axis tick labels.
|
|
@@ -1723,18 +1769,18 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1723
1769
|
if (yAxisOrientation === "right") defaultMargin.right = yMarginValue;
|
|
1724
1770
|
else defaultMargin.left = yMarginValue;
|
|
1725
1771
|
}
|
|
1726
|
-
const xOrientation = options.axis?.x?.orientation === "top" ? "top" : "bottom";
|
|
1727
|
-
const { fontSize, tickLength, tickLabelStyle } = getXAxisLabelMetrics(theme, xOrientation);
|
|
1728
|
-
const computedXMargin = fontSize + tickLength;
|
|
1729
|
-
if (xOrientation === "top") {
|
|
1730
|
-
defaultMargin.top = Math.max(defaultMargin.top, computedXMargin);
|
|
1731
|
-
defaultMargin.bottom = DEFAULT_BOTTOM_FOR_TOP_AXIS;
|
|
1732
|
-
} else defaultMargin.bottom = Math.max(defaultMargin.bottom, computedXMargin);
|
|
1733
1772
|
if (options.axis?.x?.display !== false) {
|
|
1773
|
+
const xOrientation = options.axis?.x?.orientation === "top" ? "top" : "bottom";
|
|
1774
|
+
const { fontSize, tickLength, tickLabelStyle } = getXAxisLabelMetrics(theme, xOrientation);
|
|
1775
|
+
const computedXMargin = fontSize + tickLength;
|
|
1776
|
+
if (xOrientation === "top") {
|
|
1777
|
+
defaultMargin.top = Math.max(defaultMargin.top, computedXMargin);
|
|
1778
|
+
defaultMargin.bottom = DEFAULT_BOTTOM_WITHOUT_X_AXIS;
|
|
1779
|
+
} else defaultMargin.bottom = Math.max(defaultMargin.bottom, computedXMargin);
|
|
1734
1780
|
const { first, last } = getEdgeTickWidths(options.axis?.x?.tickValues ?? [], options.axis?.x?.tickFormat, tickLabelStyle);
|
|
1735
1781
|
defaultMargin.left = Math.max(defaultMargin.left, Math.ceil(first / 2));
|
|
1736
1782
|
defaultMargin.right = Math.max(defaultMargin.right, Math.ceil(last / 2));
|
|
1737
|
-
}
|
|
1783
|
+
} else defaultMargin.bottom = DEFAULT_BOTTOM_WITHOUT_X_AXIS;
|
|
1738
1784
|
return defaultMargin;
|
|
1739
1785
|
}, [
|
|
1740
1786
|
options,
|
|
@@ -1977,6 +2023,9 @@ function usePrefersReducedMotion() {
|
|
|
1977
2023
|
return prefersReducedMotion;
|
|
1978
2024
|
}
|
|
1979
2025
|
//#endregion
|
|
2026
|
+
//#region src/hooks/use-isomorphic-layout-effect.ts
|
|
2027
|
+
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
|
|
2028
|
+
//#endregion
|
|
1980
2029
|
//#region src/providers/chart-context/hooks/use-chart-registration.ts
|
|
1981
2030
|
const useChartRegistration = ({ chartId, legendItems, chartType, isDataValid, metadata }) => {
|
|
1982
2031
|
const { registerChart, unregisterChart } = useGlobalChartsContext();
|
|
@@ -2443,33 +2492,92 @@ function useChartLegendItems(data, options = {}, legendShape) {
|
|
|
2443
2492
|
]);
|
|
2444
2493
|
}
|
|
2445
2494
|
//#endregion
|
|
2446
|
-
//#region src/components/tooltip/
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
"
|
|
2495
|
+
//#region src/components/tooltip/private/label-value-content.tsx
|
|
2496
|
+
const LabelValueContent = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
2497
|
+
data.label,
|
|
2498
|
+
": ",
|
|
2499
|
+
data.valueDisplay || (0, _automattic_number_formatters.formatNumber)(data.value)
|
|
2500
|
+
] });
|
|
2501
|
+
//#endregion
|
|
2502
|
+
//#region src/components/tooltip/private/tooltip-theme.tsx
|
|
2503
|
+
const DEFAULT_SURFACE = "#1e1e1e";
|
|
2504
|
+
const TOOLTIP_SURFACE = `var(--a8c-charts-color-tooltip-surface, ${DEFAULT_SURFACE})`;
|
|
2505
|
+
const toSeed = (value) => {
|
|
2506
|
+
const parsed = value ? (0, _visx_vendor_d3_color.color)(value) : null;
|
|
2507
|
+
return parsed && parsed.opacity === 1 ? parsed.formatHex() : DEFAULT_SURFACE;
|
|
2508
|
+
};
|
|
2509
|
+
/**
|
|
2510
|
+
* Themes the tooltip box for its dark surface, as `@wordpress/ui`'s Tooltip themes its popup. The box re-declares the catalog under this theme, so every role it reads is tuned for the surface, whatever theme the chart is in.
|
|
2511
|
+
*
|
|
2512
|
+
* @param props - Component props.
|
|
2513
|
+
* @param props.children - The tooltip box.
|
|
2514
|
+
* @return The themed box.
|
|
2515
|
+
*/
|
|
2516
|
+
const TooltipTheme = ({ children }) => {
|
|
2517
|
+
const scopeElement = useChartScopeElement();
|
|
2518
|
+
const color = (0, react.useMemo)(() => ({ background: toSeed(resolveCssVariable(TOOLTIP_SURFACE, scopeElement)) }), [scopeElement]);
|
|
2519
|
+
if (!_wordpress_theme.ThemeProvider) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children });
|
|
2520
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_theme.ThemeProvider, {
|
|
2521
|
+
color,
|
|
2522
|
+
children
|
|
2523
|
+
});
|
|
2450
2524
|
};
|
|
2451
2525
|
//#endregion
|
|
2526
|
+
//#region src/components/tooltip/tooltip-box.module.scss
|
|
2527
|
+
var tooltip_box_module_default = { "surface": "a8ccharts-ddpU1W-surface" };
|
|
2528
|
+
//#endregion
|
|
2529
|
+
//#region src/components/tooltip/tooltip-box.tsx
|
|
2530
|
+
/**
|
|
2531
|
+
* The chart tooltip box: the dark surface every chart tooltip draws. It does not position itself; place it with `style` or a wrapper.
|
|
2532
|
+
*
|
|
2533
|
+
* @param props - Div attributes, plus `unstyled`.
|
|
2534
|
+
* @param props.unstyled - Drop the surface, scope class and theme.
|
|
2535
|
+
* @param ref - Forwarded to the box element.
|
|
2536
|
+
* @return The tooltip box.
|
|
2537
|
+
*/
|
|
2538
|
+
const TooltipBox = (0, react.forwardRef)(({ unstyled = false, role = "tooltip", className, children, ...rest }, ref) => {
|
|
2539
|
+
const box = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2540
|
+
ref,
|
|
2541
|
+
role,
|
|
2542
|
+
className: (0, clsx.default)("visx-tooltip", !unstyled && ["a8c-charts-tooltip-scope", tooltip_box_module_default.surface], className),
|
|
2543
|
+
...rest,
|
|
2544
|
+
children
|
|
2545
|
+
});
|
|
2546
|
+
return unstyled ? box : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTheme, { children: box });
|
|
2547
|
+
});
|
|
2548
|
+
TooltipBox.displayName = "TooltipBox";
|
|
2549
|
+
//#endregion
|
|
2452
2550
|
//#region src/components/tooltip/base-tooltip.tsx
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2551
|
+
/**
|
|
2552
|
+
* A tooltip box with children or `label: value` content. Prefer `TooltipBox`.
|
|
2553
|
+
*
|
|
2554
|
+
* @param props - Tooltip props.
|
|
2555
|
+
* @param props.data - Data for the default content.
|
|
2556
|
+
* @param props.top - Deprecated vertical position.
|
|
2557
|
+
* @param props.left - Deprecated horizontal position.
|
|
2558
|
+
* @param props.component - Deprecated content component.
|
|
2559
|
+
* @param props.children - Tooltip content.
|
|
2560
|
+
* @param props.className - Class name passed to the content component.
|
|
2561
|
+
* @param props.style - Styles for the box.
|
|
2562
|
+
* @param props.renderContainer - Deprecated; render the content alone when false.
|
|
2563
|
+
* @return The tooltip.
|
|
2564
|
+
*/
|
|
2565
|
+
const BaseTooltip = ({ data, top, left, component: Component = LabelValueContent, children, className, style, renderContainer = true }) => {
|
|
2459
2566
|
const content = children || data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
|
|
2460
2567
|
data,
|
|
2461
2568
|
className
|
|
2462
2569
|
});
|
|
2463
|
-
const standaloneScopeClass = useStandaloneScopeClass();
|
|
2464
2570
|
if (!renderContainer) return content;
|
|
2465
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2466
|
-
className: (0, clsx.default)(standaloneScopeClass, base_tooltip_module_default.tooltip),
|
|
2571
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipBox, {
|
|
2467
2572
|
style: {
|
|
2468
|
-
top
|
|
2469
|
-
|
|
2573
|
+
...top === void 0 && left === void 0 ? void 0 : {
|
|
2574
|
+
position: "absolute",
|
|
2575
|
+
top,
|
|
2576
|
+
left,
|
|
2577
|
+
transform: "translate(-50%, -100%)"
|
|
2578
|
+
},
|
|
2470
2579
|
...style
|
|
2471
2580
|
},
|
|
2472
|
-
role: "tooltip",
|
|
2473
2581
|
children: content
|
|
2474
2582
|
});
|
|
2475
2583
|
};
|
|
@@ -2486,6 +2594,11 @@ const isClipping = (element) => {
|
|
|
2486
2594
|
overflowY
|
|
2487
2595
|
].some((value) => value && value !== "visible");
|
|
2488
2596
|
};
|
|
2597
|
+
const findLayoutParent = (node) => {
|
|
2598
|
+
let element = node.parentElement;
|
|
2599
|
+
while (element && getComputedStyle(element).display === "contents") element = element.parentElement;
|
|
2600
|
+
return element;
|
|
2601
|
+
};
|
|
2489
2602
|
const findClippingAncestor = (wrapper) => {
|
|
2490
2603
|
let element = wrapper.parentElement;
|
|
2491
2604
|
while (element && element !== document.body) {
|
|
@@ -2546,7 +2659,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2546
2659
|
};
|
|
2547
2660
|
};
|
|
2548
2661
|
/**
|
|
2549
|
-
*
|
|
2662
|
+
* A `TooltipBox`, positioned like visx's `TooltipWithBounds` but kept inside the
|
|
2550
2663
|
* nearest clipping ancestor — or the viewport when there is none — rather than
|
|
2551
2664
|
* inside its own parent. Rendered in-tree, a tooltip's parent is the chart
|
|
2552
2665
|
* wrapper, which is often narrower than the box; measuring against the parent
|
|
@@ -2555,24 +2668,25 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2555
2668
|
* Re-measures on every render, so a box whose content changes width between
|
|
2556
2669
|
* two hovers is placed for its current size.
|
|
2557
2670
|
*
|
|
2558
|
-
* @param props -
|
|
2671
|
+
* @param props - `TooltipBox` props plus placement.
|
|
2559
2672
|
* @param props.left - Anchor x, in wrapper coordinates.
|
|
2560
2673
|
* @param props.top - Anchor y, in wrapper coordinates.
|
|
2561
2674
|
* @param props.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2562
2675
|
* @param props.offsetTop - Gap between the anchor and the box, vertically.
|
|
2563
|
-
* @param props.style -
|
|
2564
|
-
* @param props.unstyled -
|
|
2676
|
+
* @param props.style - Inline overrides on the surface; ignored when `unstyled`.
|
|
2677
|
+
* @param props.unstyled - Drop the surface and `style`, leaving the box bare.
|
|
2678
|
+
* @param props.className - Extra classes beside the surface.
|
|
2565
2679
|
* @param props.children - Box content.
|
|
2566
2680
|
* @param props.placement - Below-axis, beside without vertical flipping, or automatic flipping.
|
|
2567
2681
|
* @return The tooltip box.
|
|
2568
2682
|
*/
|
|
2569
|
-
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style
|
|
2683
|
+
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style, unstyled = false, className, children, placement = "auto", ...rest }) => {
|
|
2570
2684
|
const nodeRef = (0, react.useRef)(null);
|
|
2571
2685
|
const clipRef = (0, react.useRef)(null);
|
|
2572
2686
|
const [position, setPosition] = (0, react.useState)(null);
|
|
2573
2687
|
(0, react.useLayoutEffect)(() => {
|
|
2574
2688
|
const node = nodeRef.current;
|
|
2575
|
-
const wrapper = node
|
|
2689
|
+
const wrapper = node && findLayoutParent(node);
|
|
2576
2690
|
if (!node || !wrapper) return;
|
|
2577
2691
|
if (clipRef.current?.wrapper !== wrapper) clipRef.current = {
|
|
2578
2692
|
wrapper,
|
|
@@ -2620,8 +2734,11 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2620
2734
|
]);
|
|
2621
2735
|
const x = position?.x ?? left + offsetLeft;
|
|
2622
2736
|
const y = position?.y ?? top + (placement === "below-axis" ? POINTER_HEIGHT : offsetTop);
|
|
2623
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
2737
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TooltipBox, {
|
|
2624
2738
|
ref: nodeRef,
|
|
2739
|
+
role: "presentation",
|
|
2740
|
+
unstyled,
|
|
2741
|
+
className,
|
|
2625
2742
|
style: {
|
|
2626
2743
|
position: "absolute",
|
|
2627
2744
|
left: 0,
|
|
@@ -2637,16 +2754,16 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2637
2754
|
left: left - x - POINTER_HEIGHT,
|
|
2638
2755
|
top: -6,
|
|
2639
2756
|
width: 12,
|
|
2640
|
-
height:
|
|
2757
|
+
height: 7,
|
|
2641
2758
|
background: "inherit",
|
|
2642
|
-
clipPath:
|
|
2759
|
+
clipPath: `polygon(50% 0, 100% ${POINTER_HEIGHT}px, 100% 100%, 0 100%, 0 ${POINTER_HEIGHT}px)`,
|
|
2643
2760
|
pointerEvents: "none"
|
|
2644
2761
|
}
|
|
2645
2762
|
}), children]
|
|
2646
2763
|
});
|
|
2647
2764
|
};
|
|
2648
2765
|
//#endregion
|
|
2649
|
-
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2766
|
+
//#region src/components/tooltip/private/xy-chart-tooltip-overlay.tsx
|
|
2650
2767
|
const CROSSHAIR_STROKE_WIDTH = 1.5;
|
|
2651
2768
|
const CROSSHAIR_PAINT_PROPERTIES = /* @__PURE__ */ new Set([
|
|
2652
2769
|
"stroke",
|
|
@@ -2748,15 +2865,36 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2748
2865
|
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2749
2866
|
const marginTop = margin?.top ?? 0;
|
|
2750
2867
|
const marginLeft = margin?.left ?? 0;
|
|
2751
|
-
const TooltipComponent = detectBounds || tooltipPlacement !== "auto" ? BoundedTooltip : _visx_tooltip.Tooltip;
|
|
2752
2868
|
const boxStyle = {
|
|
2753
|
-
..._visx_tooltip.defaultStyles,
|
|
2754
2869
|
zIndex,
|
|
2755
|
-
backgroundColor: theme?.backgroundColor ?? "white",
|
|
2756
|
-
boxShadow: `0 1px 2px ${isValidHexColor(theme?.htmlLabel?.color) ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2757
|
-
...theme?.htmlLabel,
|
|
2758
2870
|
...style
|
|
2759
2871
|
};
|
|
2872
|
+
const { offsetLeft = 10, offsetTop = 10, unstyled, className, ...boxProps } = tooltipProps;
|
|
2873
|
+
const anchorTop = tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipAnchorTop ?? tooltipTop;
|
|
2874
|
+
const box = detectBounds || tooltipPlacement !== "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
2875
|
+
left: tooltipLeft,
|
|
2876
|
+
top: anchorTop,
|
|
2877
|
+
offsetLeft,
|
|
2878
|
+
offsetTop,
|
|
2879
|
+
unstyled,
|
|
2880
|
+
className,
|
|
2881
|
+
style: boxStyle,
|
|
2882
|
+
...boxProps,
|
|
2883
|
+
...tooltipPlacement !== "auto" && { placement: tooltipPlacement },
|
|
2884
|
+
children: tooltipContent
|
|
2885
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipBox, {
|
|
2886
|
+
role: "presentation",
|
|
2887
|
+
unstyled,
|
|
2888
|
+
className,
|
|
2889
|
+
style: {
|
|
2890
|
+
position: "absolute",
|
|
2891
|
+
left: (tooltipLeft ?? 0) + offsetLeft,
|
|
2892
|
+
top: (anchorTop ?? 0) + offsetTop,
|
|
2893
|
+
...!unstyled && boxStyle
|
|
2894
|
+
},
|
|
2895
|
+
...boxProps,
|
|
2896
|
+
children: tooltipContent
|
|
2897
|
+
});
|
|
2760
2898
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
2761
2899
|
className: "visx-tooltip-overlay",
|
|
2762
2900
|
pointerEvents: "none",
|
|
@@ -2783,15 +2921,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2783
2921
|
}),
|
|
2784
2922
|
glyphs
|
|
2785
2923
|
]
|
|
2786
|
-
}), container && (0, react_dom.createPortal)(
|
|
2787
|
-
left: tooltipLeft,
|
|
2788
|
-
top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipAnchorTop ?? tooltipTop,
|
|
2789
|
-
style: boxStyle,
|
|
2790
|
-
applyPositionStyle: true,
|
|
2791
|
-
...tooltipProps,
|
|
2792
|
-
...tooltipPlacement !== "auto" && { placement: tooltipPlacement },
|
|
2793
|
-
children: tooltipContent
|
|
2794
|
-
}), container)] });
|
|
2924
|
+
}), container && (0, react_dom.createPortal)(box, container)] });
|
|
2795
2925
|
};
|
|
2796
2926
|
/**
|
|
2797
2927
|
* In-tree replacement for `@visx/xychart`'s `Tooltip`.
|
|
@@ -2816,7 +2946,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2816
2946
|
* @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
|
|
2817
2947
|
* @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
|
|
2818
2948
|
*/
|
|
2819
|
-
const
|
|
2949
|
+
const XyChartTooltipOverlay = (props) => {
|
|
2820
2950
|
const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
2821
2951
|
const [container, setContainer] = (0, react.useState)(null);
|
|
2822
2952
|
const anchorRef = (0, react.useCallback)((node) => {
|
|
@@ -2829,8 +2959,8 @@ const XyChartTooltip = (props) => {
|
|
|
2829
2959
|
})] });
|
|
2830
2960
|
};
|
|
2831
2961
|
//#endregion
|
|
2832
|
-
//#region src/components/tooltip/
|
|
2833
|
-
const
|
|
2962
|
+
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2963
|
+
const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
|
|
2834
2964
|
const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
2835
2965
|
const scopeElement = useChartScopeElement();
|
|
2836
2966
|
const crosshairStroke = (0, react.useMemo)(() => {
|
|
@@ -2936,7 +3066,7 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2936
3066
|
keyboardFocusedClassName,
|
|
2937
3067
|
standaloneScopeClass
|
|
2938
3068
|
]);
|
|
2939
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3069
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltipOverlay, {
|
|
2940
3070
|
...props,
|
|
2941
3071
|
verticalCrosshairStyle: {
|
|
2942
3072
|
...crosshairStroke,
|
|
@@ -2949,6 +3079,8 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2949
3079
|
renderTooltip: focusableRenderTooltip
|
|
2950
3080
|
});
|
|
2951
3081
|
};
|
|
3082
|
+
/** @deprecated Use `XYChartTooltip`. */
|
|
3083
|
+
const AccessibleTooltip = XYChartTooltip;
|
|
2952
3084
|
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false, visibleSeriesKey }) => {
|
|
2953
3085
|
const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"grid\"]") ?? chartRef.current, [chartRef]);
|
|
2954
3086
|
const focusWithoutScrollIfNeeded = (0, react.useCallback)((element) => {
|
|
@@ -3058,7 +3190,6 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
|
|
|
3058
3190
|
};
|
|
3059
3191
|
//#endregion
|
|
3060
3192
|
//#region src/providers/chart-context/hooks/use-default-hidden-series.ts
|
|
3061
|
-
const useIsomorphicLayoutEffect$1 = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
|
|
3062
3193
|
/**
|
|
3063
3194
|
* Seeds a chart's hidden series once per chart ID, the first time the provider
|
|
3064
3195
|
* sees that ID.
|
|
@@ -3079,7 +3210,7 @@ const useDefaultHiddenSeries = (chartId, seriesLabels) => {
|
|
|
3079
3210
|
labelsRef.current = seriesLabels;
|
|
3080
3211
|
const hasSeriesLabels = seriesLabels !== void 0;
|
|
3081
3212
|
const shouldUseDefaults = hasSeriesLabels && !hasSeededChart(chartId);
|
|
3082
|
-
useIsomorphicLayoutEffect
|
|
3213
|
+
useIsomorphicLayoutEffect(() => {
|
|
3083
3214
|
if (labelsRef.current === void 0) return;
|
|
3084
3215
|
seedChartHiddenSeries(chartId, labelsRef.current);
|
|
3085
3216
|
}, [
|
|
@@ -3704,7 +3835,6 @@ var with_responsive_module_default = {
|
|
|
3704
3835
|
};
|
|
3705
3836
|
//#endregion
|
|
3706
3837
|
//#region src/charts/private/with-responsive/with-responsive.tsx
|
|
3707
|
-
const useIsomorphicLayoutEffect = typeof window !== "undefined" ? react.useLayoutEffect : react.useEffect;
|
|
3708
3838
|
/**
|
|
3709
3839
|
* A higher-order component that provides responsive dimensions
|
|
3710
3840
|
* to the wrapped chart component using useParentSize from `@visx/responsive`.
|
|
@@ -3988,10 +4118,8 @@ var line_chart_module_default = {
|
|
|
3988
4118
|
"line-chart__annotation-label-popover-content": "a8ccharts-inuQka-line-chart__annotation-label-popover-content",
|
|
3989
4119
|
"line-chart__annotation-label-trigger-button": "a8ccharts-inuQka-line-chart__annotation-label-trigger-button",
|
|
3990
4120
|
"line-chart__annotations-overlay": "a8ccharts-inuQka-line-chart__annotations-overlay",
|
|
3991
|
-
"line-chart__tooltip": "a8ccharts-inuQka-line-chart__tooltip",
|
|
3992
4121
|
"line-chart__tooltip-date": "a8ccharts-inuQka-line-chart__tooltip-date",
|
|
3993
4122
|
"line-chart__tooltip-label": "a8ccharts-inuQka-line-chart__tooltip-label",
|
|
3994
|
-
"line-chart__tooltip-row": "a8ccharts-inuQka-line-chart__tooltip-row",
|
|
3995
4123
|
"line-chart--animated": "a8ccharts-inuQka-line-chart--animated",
|
|
3996
4124
|
"rise": "a8ccharts-inuQka-rise"
|
|
3997
4125
|
};
|
|
@@ -4518,11 +4646,10 @@ const TooltipDate = ({ date, displayResolution }) => {
|
|
|
4518
4646
|
* one row per visible series (label + formatted value), sorted descending by
|
|
4519
4647
|
* value. Reused by AreaChart, which has the same multi-series shape.
|
|
4520
4648
|
*
|
|
4521
|
-
* @param params
|
|
4522
|
-
* @param contentStyle - Explicit tooltip content color overrides.
|
|
4649
|
+
* @param params - visx tooltip data and the chart's optional `bucketInfo`.
|
|
4523
4650
|
* @return Tooltip JSX, or `null` when no datum is hovered.
|
|
4524
4651
|
*/
|
|
4525
|
-
const renderDefaultTooltip = (params
|
|
4652
|
+
const renderDefaultTooltip = (params) => {
|
|
4526
4653
|
const { tooltipData, bucketInfo } = params;
|
|
4527
4654
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
4528
4655
|
if (!nearestDatum) return null;
|
|
@@ -4535,29 +4662,24 @@ const renderDefaultTooltip = (params, contentStyle) => {
|
|
|
4535
4662
|
if (b.value === null) return -1;
|
|
4536
4663
|
return b.value - a.value;
|
|
4537
4664
|
});
|
|
4538
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4539
|
-
className: line_chart_module_default["line-chart__tooltip"],
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
className: line_chart_module_default["line-chart__tooltip-value"],
|
|
4557
|
-
children: formatReading(point.value)
|
|
4558
|
-
})]
|
|
4559
|
-
}, point.key))]
|
|
4560
|
-
});
|
|
4665
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4666
|
+
className: line_chart_module_default["line-chart__tooltip-date"],
|
|
4667
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipDate, {
|
|
4668
|
+
date: nearestDatum.date,
|
|
4669
|
+
displayResolution: bucketInfo?.displayResolution ?? "day"
|
|
4670
|
+
})
|
|
4671
|
+
}), tooltipPoints.map((point) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
4672
|
+
direction: "row",
|
|
4673
|
+
align: "center",
|
|
4674
|
+
justify: "space-between",
|
|
4675
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4676
|
+
className: line_chart_module_default["line-chart__tooltip-label"],
|
|
4677
|
+
children: [point.key, ":"]
|
|
4678
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4679
|
+
className: line_chart_module_default["line-chart__tooltip-value"],
|
|
4680
|
+
children: formatReading(point.value)
|
|
4681
|
+
})]
|
|
4682
|
+
}, point.key))] });
|
|
4561
4683
|
};
|
|
4562
4684
|
const validateData$4 = (data) => {
|
|
4563
4685
|
if (!data?.length) return (0, _wordpress_i18n.__)("No data available", "jetpack-charts");
|
|
@@ -4817,29 +4939,10 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4817
4939
|
xAccessor: (d) => d?.date,
|
|
4818
4940
|
yAccessor: (d) => d?.value
|
|
4819
4941
|
};
|
|
4820
|
-
const
|
|
4821
|
-
if (renderTooltip !== renderDefaultTooltip || !tooltipStyle) return tooltipStyle;
|
|
4822
|
-
if (!tooltipStyle.color || tooltipStyle.background || tooltipStyle.backgroundColor) return tooltipStyle;
|
|
4823
|
-
return {
|
|
4824
|
-
backgroundColor: "var(--a8c-charts-color-tooltip-surface, rgb(0 0 0 / 85%))",
|
|
4825
|
-
...tooltipStyle
|
|
4826
|
-
};
|
|
4827
|
-
}, [renderTooltip, tooltipStyle]);
|
|
4828
|
-
const tooltipRenderer = (0, react.useMemo)(() => (params) => renderTooltip === renderDefaultTooltip ? renderDefaultTooltip({
|
|
4829
|
-
...params,
|
|
4830
|
-
bucketInfo
|
|
4831
|
-
}, {
|
|
4832
|
-
color: tooltipStyle?.color,
|
|
4833
|
-
background: tooltipStyle?.background,
|
|
4834
|
-
backgroundColor: tooltipStyle?.backgroundColor
|
|
4835
|
-
}) : renderTooltip({
|
|
4942
|
+
const tooltipRenderer = (0, react.useMemo)(() => (params) => renderTooltip({
|
|
4836
4943
|
...params,
|
|
4837
4944
|
bucketInfo
|
|
4838
|
-
}), [
|
|
4839
|
-
renderTooltip,
|
|
4840
|
-
bucketInfo,
|
|
4841
|
-
tooltipStyle
|
|
4842
|
-
]);
|
|
4945
|
+
}), [renderTooltip, bucketInfo]);
|
|
4843
4946
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4844
4947
|
className: (0, clsx.default)("line-chart", line_chart_module_default["line-chart"]),
|
|
4845
4948
|
children: error
|
|
@@ -4983,11 +5086,11 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4983
5086
|
] }, seriesData?.label || index);
|
|
4984
5087
|
})
|
|
4985
5088
|
}),
|
|
4986
|
-
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5089
|
+
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
|
|
4987
5090
|
detectBounds: true,
|
|
4988
5091
|
snapTooltipToDatumX: true,
|
|
4989
5092
|
tooltipPlacement,
|
|
4990
|
-
style:
|
|
5093
|
+
style: tooltipStyle,
|
|
4991
5094
|
snapTooltipToDatumY: true,
|
|
4992
5095
|
showSeriesGlyphs: true,
|
|
4993
5096
|
renderTooltip: tooltipRenderer,
|
|
@@ -5459,7 +5562,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5459
5562
|
children: seriesWithVisibility.map(renderSeries)
|
|
5460
5563
|
}), !allSeriesHidden && !stacked && seriesWithVisibility.map(renderSeries)]
|
|
5461
5564
|
}),
|
|
5462
|
-
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5565
|
+
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
|
|
5463
5566
|
detectBounds: true,
|
|
5464
5567
|
snapTooltipToDatumX: true,
|
|
5465
5568
|
snapTooltipToDatumY: !stacked,
|
|
@@ -6070,6 +6173,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
6070
6173
|
widthFactor
|
|
6071
6174
|
});
|
|
6072
6175
|
rects.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
6176
|
+
className: "bar-chart__comparison-bar",
|
|
6073
6177
|
x: rect.x,
|
|
6074
6178
|
y: rect.y,
|
|
6075
6179
|
width: rect.width,
|
|
@@ -6485,7 +6589,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6485
6589
|
const patternId = getPatternId(chartId, index);
|
|
6486
6590
|
return `
|
|
6487
6591
|
.visx-bar[fill="url(#${patternId})"],
|
|
6488
|
-
.bar-chart__comparison-
|
|
6592
|
+
.bar-chart__comparison-bar[fill="url(#${patternId})"] {
|
|
6489
6593
|
stroke: ${color};
|
|
6490
6594
|
stroke-width: 1;
|
|
6491
6595
|
}
|
|
@@ -6667,15 +6771,15 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6667
6771
|
}),
|
|
6668
6772
|
!allSeriesHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WholeNumberTicks, {
|
|
6669
6773
|
...wholeNumberTicksProps,
|
|
6670
|
-
children: (valueTicks) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
|
|
6774
|
+
children: (valueTicks) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [chartOptions.axis.x.display !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
|
|
6671
6775
|
...chartOptions.axis.x,
|
|
6672
6776
|
...horizontal && valueTicks ? { tickValues: valueTicks } : {}
|
|
6673
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
|
|
6777
|
+
}), chartOptions.axis.y.display !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
|
|
6674
6778
|
...chartOptions.axis.y,
|
|
6675
6779
|
...!horizontal && valueTicks ? { tickValues: valueTicks } : {}
|
|
6676
6780
|
})] })
|
|
6677
6781
|
}),
|
|
6678
|
-
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
6782
|
+
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
|
|
6679
6783
|
tooltipPlacement,
|
|
6680
6784
|
tooltipAnchorTop,
|
|
6681
6785
|
style: tooltipStyle,
|
|
@@ -6895,8 +6999,7 @@ var conversion_funnel_chart_module_default = {
|
|
|
6895
6999
|
"step-rate": "a8ccharts-mGEVca-step-rate",
|
|
6896
7000
|
"stretch": "a8ccharts-mGEVca-stretch",
|
|
6897
7001
|
"tooltip-content": "a8ccharts-mGEVca-tooltip-content",
|
|
6898
|
-
"tooltip-title": "a8ccharts-mGEVca-tooltip-title"
|
|
6899
|
-
"tooltip-wrapper": "a8ccharts-mGEVca-tooltip-wrapper"
|
|
7002
|
+
"tooltip-title": "a8ccharts-mGEVca-tooltip-title"
|
|
6900
7003
|
};
|
|
6901
7004
|
//#endregion
|
|
6902
7005
|
//#region src/charts/conversion-funnel-chart/private/use-funnel-selection.ts
|
|
@@ -6957,9 +7060,10 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
6957
7060
|
* @param props.renderStepRate - Custom render function for step rates
|
|
6958
7061
|
* @param props.renderMainMetric - Custom render function for the entire main metric section
|
|
6959
7062
|
* @param props.renderTooltip - Custom render function for tooltip content
|
|
7063
|
+
* @param props.tooltipStyle - Inline styles merged over the tooltip box defaults
|
|
6960
7064
|
* @return JSX element representing the conversion funnel chart
|
|
6961
7065
|
*/
|
|
6962
|
-
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip }) => {
|
|
7066
|
+
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
|
|
6963
7067
|
const chartId = useChartId(providedChartId);
|
|
6964
7068
|
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
6965
7069
|
const chartRef = (0, react.useRef)(null);
|
|
@@ -7194,15 +7298,18 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7194
7298
|
step: tooltipData,
|
|
7195
7299
|
index: steps.findIndex((s) => s.id === tooltipData.id),
|
|
7196
7300
|
top: tooltipTop,
|
|
7197
|
-
left: tooltipLeft
|
|
7198
|
-
className: conversion_funnel_chart_module_default["tooltip-wrapper"]
|
|
7301
|
+
left: tooltipLeft
|
|
7199
7302
|
}) : renderDefaultTooltip(tooltipData);
|
|
7200
7303
|
if (!tooltipContent) return null;
|
|
7201
7304
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
7202
7305
|
top: tooltipTop,
|
|
7203
7306
|
left: tooltipLeft,
|
|
7204
|
-
className:
|
|
7205
|
-
|
|
7307
|
+
className: standaloneScopeClass,
|
|
7308
|
+
style: tooltipStyle,
|
|
7309
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7310
|
+
role: "tooltip",
|
|
7311
|
+
children: tooltipContent
|
|
7312
|
+
})
|
|
7206
7313
|
});
|
|
7207
7314
|
})()]
|
|
7208
7315
|
});
|
|
@@ -7487,6 +7594,73 @@ let GoogleDataTableColumnRoleType = /* @__PURE__ */ function(GoogleDataTableColu
|
|
|
7487
7594
|
GoogleDataTableColumnRoleType["domain"] = "domain";
|
|
7488
7595
|
return GoogleDataTableColumnRoleType;
|
|
7489
7596
|
}({});
|
|
7597
|
+
const resolveRole = (pointer, resolve) => {
|
|
7598
|
+
const raw = resolve(pointer);
|
|
7599
|
+
const parsed = raw ? (0, _visx_vendor_d3_color.color)(raw) : null;
|
|
7600
|
+
if (!parsed) return {
|
|
7601
|
+
kind: "unreadable",
|
|
7602
|
+
raw
|
|
7603
|
+
};
|
|
7604
|
+
const { r, g, b } = parsed.opacity > 0 ? parsed.rgb() : {
|
|
7605
|
+
r: 0,
|
|
7606
|
+
g: 0,
|
|
7607
|
+
b: 0
|
|
7608
|
+
};
|
|
7609
|
+
return {
|
|
7610
|
+
kind: "color",
|
|
7611
|
+
rgb: [
|
|
7612
|
+
r,
|
|
7613
|
+
g,
|
|
7614
|
+
b
|
|
7615
|
+
],
|
|
7616
|
+
alpha: parsed.opacity
|
|
7617
|
+
};
|
|
7618
|
+
};
|
|
7619
|
+
/**
|
|
7620
|
+
* Reads both label roles at the element the label text inherits from, so JS and CSS agree on what paints.
|
|
7621
|
+
*
|
|
7622
|
+
* @param resolve - A CSS variable resolver bound to that element.
|
|
7623
|
+
* @return The resolved label roles.
|
|
7624
|
+
*/
|
|
7625
|
+
const resolveLabelRoles = (resolve) => ({
|
|
7626
|
+
label: resolveRole(CATALOG_POINTERS.label, resolve),
|
|
7627
|
+
labelInverse: resolveRole(CATALOG_POINTERS.labelInverse, resolve)
|
|
7628
|
+
});
|
|
7629
|
+
const roleContrast = (role, fill, fillLuminance) => {
|
|
7630
|
+
if (role.kind === "unreadable") return 0;
|
|
7631
|
+
return luminanceContrastRatio(fillLuminance, rgbLuminance(blendRgb(role.rgb, fill, role.alpha)));
|
|
7632
|
+
};
|
|
7633
|
+
/**
|
|
7634
|
+
* Picks the label color for text drawn on a fill: the role that contrasts more, or black/white when neither reaches AA.
|
|
7635
|
+
*
|
|
7636
|
+
* Both roles set to one color is a host's choice to keep that color, so it never falls back.
|
|
7637
|
+
*
|
|
7638
|
+
* @param fill - The fill the text sits on, as unrounded sRGB channels.
|
|
7639
|
+
* @param roles - The label roles resolved at the chart's element, or null before they are read.
|
|
7640
|
+
* @param defaultRole - The role the chart's stylesheet paints when nothing can be decided.
|
|
7641
|
+
* @return The color the label should paint with.
|
|
7642
|
+
*/
|
|
7643
|
+
const pickLabelTextColorForFill = (fill, roles, defaultRole) => {
|
|
7644
|
+
if (!roles || (0, import_fast_deep_equal.default)(roles.label, roles.labelInverse)) return defaultRole;
|
|
7645
|
+
const fillLuminance = rgbLuminance(fill);
|
|
7646
|
+
const labelContrast = roleContrast(roles.label, fill, fillLuminance);
|
|
7647
|
+
const inverseContrast = roleContrast(roles.labelInverse, fill, fillLuminance);
|
|
7648
|
+
if (Math.max(labelContrast, inverseContrast) >= 4.55) return labelContrast > inverseContrast ? "label" : "label-inverse";
|
|
7649
|
+
return luminanceContrastRatio(fillLuminance, 0) > luminanceContrastRatio(fillLuminance, 1) ? "black" : "white";
|
|
7650
|
+
};
|
|
7651
|
+
/**
|
|
7652
|
+
* `pickLabelTextColorForFill` for a fill given as a color.
|
|
7653
|
+
*
|
|
7654
|
+
* @param fill - The fill, in any color syntax `normalizeColorToHex` reads.
|
|
7655
|
+
* @param roles - The label roles resolved at the chart's element, or null before they are read.
|
|
7656
|
+
* @param defaultRole - The role the chart's stylesheet paints when nothing can be decided.
|
|
7657
|
+
* @return The color the label should paint with.
|
|
7658
|
+
*/
|
|
7659
|
+
const pickLabelTextColor = (fill, roles, defaultRole) => {
|
|
7660
|
+
const fillHex = normalizeColorToHex(fill);
|
|
7661
|
+
if (!isValidHexColor(fillHex)) return defaultRole;
|
|
7662
|
+
return pickLabelTextColorForFill(hexToRgb(fillHex), roles, defaultRole);
|
|
7663
|
+
};
|
|
7490
7664
|
//#endregion
|
|
7491
7665
|
//#region src/charts/heatmap-chart/heatmap-chart.module.scss
|
|
7492
7666
|
var heatmap_chart_module_default = {
|
|
@@ -7496,9 +7670,11 @@ var heatmap_chart_module_default = {
|
|
|
7496
7670
|
"heatmap-chart__cell--hidden": "a8ccharts-O3YMOW-heatmap-chart__cell--hidden",
|
|
7497
7671
|
"heatmap-chart__cell--placeholder": "a8ccharts-O3YMOW-heatmap-chart__cell--placeholder",
|
|
7498
7672
|
"heatmap-chart__cell--selected": "a8ccharts-O3YMOW-heatmap-chart__cell--selected",
|
|
7499
|
-
"heatmap-chart__cell--strong": "a8ccharts-O3YMOW-heatmap-chart__cell--strong",
|
|
7500
7673
|
"heatmap-chart__cell--summary": "a8ccharts-O3YMOW-heatmap-chart__cell--summary",
|
|
7501
7674
|
"heatmap-chart__cell-value": "a8ccharts-O3YMOW-heatmap-chart__cell-value",
|
|
7675
|
+
"heatmap-chart__cell-value--black": "a8ccharts-O3YMOW-heatmap-chart__cell-value--black",
|
|
7676
|
+
"heatmap-chart__cell-value--inverse": "a8ccharts-O3YMOW-heatmap-chart__cell-value--inverse",
|
|
7677
|
+
"heatmap-chart__cell-value--white": "a8ccharts-O3YMOW-heatmap-chart__cell-value--white",
|
|
7502
7678
|
"heatmap-chart__col-label": "a8ccharts-O3YMOW-heatmap-chart__col-label",
|
|
7503
7679
|
"heatmap-chart__col-label--summary": "a8ccharts-O3YMOW-heatmap-chart__col-label--summary",
|
|
7504
7680
|
"heatmap-chart__empty": "a8ccharts-O3YMOW-heatmap-chart__empty",
|
|
@@ -7520,30 +7696,44 @@ var heatmap_chart_module_default = {
|
|
|
7520
7696
|
//#region src/charts/heatmap-chart/private/use-heatmap-colors.ts
|
|
7521
7697
|
const isPresent = (value) => value !== null && value !== void 0 && !isNaN(value);
|
|
7522
7698
|
/**
|
|
7523
|
-
* Get the min and max values from heatmap data, ignoring null/NaN
|
|
7524
|
-
* columns stay out: a roll-up on the
|
|
7699
|
+
* Get the min and max values from heatmap data, ignoring null/NaN and the zeros
|
|
7700
|
+
* `isEmptyValue` paints as empty. Summary columns stay out: a roll-up on the
|
|
7701
|
+
* scale would flatten every real cell.
|
|
7525
7702
|
* @param data - The heatmap columns
|
|
7526
7703
|
* @return Tuple of [min, max] values
|
|
7527
7704
|
*/
|
|
7528
7705
|
const getValueExtent = (data) => {
|
|
7529
7706
|
let min = Infinity;
|
|
7530
7707
|
let max = -Infinity;
|
|
7708
|
+
let hasZero = false;
|
|
7531
7709
|
for (const column of data) {
|
|
7532
7710
|
if (column.summary) continue;
|
|
7533
7711
|
for (const cell of column.data) {
|
|
7534
7712
|
if (!isPresent(cell.value)) continue;
|
|
7713
|
+
if (cell.value === 0) {
|
|
7714
|
+
hasZero = true;
|
|
7715
|
+
continue;
|
|
7716
|
+
}
|
|
7535
7717
|
if (cell.value < min) min = cell.value;
|
|
7536
7718
|
if (cell.value > max) max = cell.value;
|
|
7537
7719
|
}
|
|
7538
7720
|
}
|
|
7721
|
+
if (hasZero && min < 0) max = Math.max(max, 0);
|
|
7539
7722
|
if (min === Infinity) return [0, 0];
|
|
7540
7723
|
return [min, max];
|
|
7541
7724
|
};
|
|
7542
7725
|
/**
|
|
7726
|
+
* Whether a value paints as an empty cell: a zero in data with no negatives
|
|
7727
|
+
* counts nothing, so it must not look like the lowest step of activity.
|
|
7728
|
+
*
|
|
7729
|
+
* @param value - The cell value
|
|
7730
|
+
* @param extent - The extent from `getValueExtent`
|
|
7731
|
+
* @return True when the cell takes the empty-cell color
|
|
7732
|
+
*/
|
|
7733
|
+
const isEmptyValue = (value, extent) => value === 0 && extent[0] >= 0;
|
|
7734
|
+
/**
|
|
7543
7735
|
* Normalize a value to 0–1 within the extent. A flat extent (min === max)
|
|
7544
|
-
* maps to 1
|
|
7545
|
-
* extent, which maps to 0 so a no-activity grid renders at the scale's
|
|
7546
|
-
* bottom instead of full intensity.
|
|
7736
|
+
* maps to 1, since every cell is equally the "highest".
|
|
7547
7737
|
*
|
|
7548
7738
|
* @param value - The value to normalize
|
|
7549
7739
|
* @param extent - Tuple of [min, max] values for the normalization range
|
|
@@ -7551,9 +7741,40 @@ const getValueExtent = (data) => {
|
|
|
7551
7741
|
*/
|
|
7552
7742
|
const getNormalizedValue = (value, extent) => {
|
|
7553
7743
|
const [min, max] = extent;
|
|
7554
|
-
if (min === max) return
|
|
7744
|
+
if (min === max) return 1;
|
|
7555
7745
|
return Math.min(1, Math.max(0, (value - min) / (max - min)));
|
|
7556
7746
|
};
|
|
7747
|
+
const STEPS = 200;
|
|
7748
|
+
const firstMeeting = (from, to, meets) => {
|
|
7749
|
+
for (let step = 0; step <= STEPS; step++) {
|
|
7750
|
+
const color = mixHexColors(from, to, step / STEPS);
|
|
7751
|
+
if (meets(color)) return color;
|
|
7752
|
+
}
|
|
7753
|
+
return null;
|
|
7754
|
+
};
|
|
7755
|
+
/**
|
|
7756
|
+
* The two ends of the heatmap fill scale: 3:1 against the background and the empty cell at the
|
|
7757
|
+
* low end, toward 9:1 against the background at the high end.
|
|
7758
|
+
*
|
|
7759
|
+
* @param primary - The resolved primary color, as six-digit hex.
|
|
7760
|
+
* @param background - The resolved chart background, as six-digit hex.
|
|
7761
|
+
* @param emptyCell - The resolved empty-cell color, as six-digit hex, when it is opaque.
|
|
7762
|
+
* @return The scale ends, as six-digit hex.
|
|
7763
|
+
*/
|
|
7764
|
+
const getHeatmapScale = (primary, background, emptyCell) => {
|
|
7765
|
+
const primaryStandsOut = contrastRatio(primary, background) >= 3;
|
|
7766
|
+
const extreme = (primaryStandsOut ? relativeLuminance(primary) > relativeLuminance(background) : contrastRatio("#ffffff", background) > contrastRatio("#000000", background)) ? "#ffffff" : "#000000";
|
|
7767
|
+
const lowAgainst = (references) => {
|
|
7768
|
+
const meets = (color) => references.every((reference) => contrastRatio(color, reference) >= 3);
|
|
7769
|
+
return (primaryStandsOut ? firstMeeting(background, primary, meets) : null) ?? firstMeeting(primary, extreme, meets);
|
|
7770
|
+
};
|
|
7771
|
+
const high = firstMeeting(primary, extreme, (color) => contrastRatio(color, background) >= 9) ?? extreme;
|
|
7772
|
+
const againstEmptyCell = emptyCell ? lowAgainst([background, emptyCell]) : null;
|
|
7773
|
+
return {
|
|
7774
|
+
low: (againstEmptyCell && contrastRatio(againstEmptyCell, background) <= contrastRatio(high, background) ? againstEmptyCell : lowAgainst([background])) ?? extreme,
|
|
7775
|
+
high
|
|
7776
|
+
};
|
|
7777
|
+
};
|
|
7557
7778
|
//#endregion
|
|
7558
7779
|
//#region src/charts/heatmap-chart/private/heatmap-context.ts
|
|
7559
7780
|
/** Shared by the chart and legend without importing back from `heatmap-chart.tsx`. */
|
|
@@ -7564,7 +7785,7 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
|
|
|
7564
7785
|
const context = (0, react.useContext)(HeatmapContext);
|
|
7565
7786
|
const { legend } = useGlobalChartsTheme();
|
|
7566
7787
|
if (!context) return null;
|
|
7567
|
-
const {
|
|
7788
|
+
const { fillVars } = context;
|
|
7568
7789
|
const labelStyle = legend.labelStyles;
|
|
7569
7790
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7570
7791
|
direction: "row",
|
|
@@ -7587,7 +7808,7 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
|
|
|
7587
7808
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7588
7809
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
7589
7810
|
style: {
|
|
7590
|
-
|
|
7811
|
+
...fillVars,
|
|
7591
7812
|
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
7592
7813
|
}
|
|
7593
7814
|
}, index);
|
|
@@ -7791,26 +8012,25 @@ const stepCalendarCell = (grid, blocks, from, key) => {
|
|
|
7791
8012
|
};
|
|
7792
8013
|
//#endregion
|
|
7793
8014
|
//#region src/charts/heatmap-chart/heatmap-chart.tsx
|
|
7794
|
-
const
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
zIndex: 3
|
|
7800
|
-
},
|
|
7801
|
-
dark: { zIndex: 3 }
|
|
8015
|
+
const CELL_VALUE_MODIFIER = {
|
|
8016
|
+
label: void 0,
|
|
8017
|
+
"label-inverse": heatmap_chart_module_default["heatmap-chart__cell-value--inverse"],
|
|
8018
|
+
black: heatmap_chart_module_default["heatmap-chart__cell-value--black"],
|
|
8019
|
+
white: heatmap_chart_module_default["heatmap-chart__cell-value--white"]
|
|
7802
8020
|
};
|
|
8021
|
+
const NO_ROW_LABELS = [];
|
|
8022
|
+
const TOOLTIP_BOX_STYLE = { zIndex: 3 };
|
|
7803
8023
|
const cellName = (info) => info.cellLabel || [
|
|
7804
8024
|
info.groupLabel,
|
|
7805
8025
|
info.columnLabel,
|
|
7806
8026
|
info.rowLabel
|
|
7807
8027
|
].filter(Boolean).join(" ");
|
|
7808
|
-
const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, columnGroups, keyboardNavigation = "grid", ariaLabel, primaryColor, gap = "md", withTooltips = false, renderTooltip,
|
|
8028
|
+
const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, columnGroups, keyboardNavigation = "grid", ariaLabel, primaryColor, gap = "md", withTooltips = false, renderTooltip, tooltipStyle, children }) => {
|
|
7809
8029
|
const chartId = useChartId(providedChartId);
|
|
7810
8030
|
const tooltipBoxStyle = tooltipStyle ? {
|
|
7811
|
-
...
|
|
8031
|
+
...TOOLTIP_BOX_STYLE,
|
|
7812
8032
|
...tooltipStyle
|
|
7813
|
-
} :
|
|
8033
|
+
} : TOOLTIP_BOX_STYLE;
|
|
7814
8034
|
const { getElementStyles, theme } = useGlobalChartsContext();
|
|
7815
8035
|
const scopeElement = useChartScopeElement();
|
|
7816
8036
|
const { heatmapChart: heatmapChartSettings } = theme;
|
|
@@ -7819,19 +8039,44 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7819
8039
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
7820
8040
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
7821
8041
|
const containerRef = (0, react.useRef)(null);
|
|
8042
|
+
const [labelRoles, setLabelRoles] = (0, react.useState)(null);
|
|
7822
8043
|
const getTooltipOrigin = (0, react.useCallback)(() => containerRef.current?.closest(`[data-chart-id="heatmap-chart-${chartId}"]`)?.getBoundingClientRect() ?? null, [chartId]);
|
|
7823
8044
|
const { color: primaryColorHex } = getElementStyles({
|
|
7824
8045
|
index: 0,
|
|
7825
8046
|
overrideColor: primaryColor
|
|
7826
8047
|
});
|
|
7827
|
-
const
|
|
8048
|
+
const resolveAtScope = createCssVariableResolver(scopeElement);
|
|
8049
|
+
const chartBackgroundHex = resolveOpaqueHex(CATALOG_POINTERS.background, resolveAtScope) ?? "#ffffff";
|
|
8050
|
+
const emptyCellHex = resolveOpaqueHex(CATALOG_POINTERS.track, resolveAtScope);
|
|
7828
8051
|
const primaryHex = normalizeColorToHex(primaryColorHex);
|
|
7829
|
-
const
|
|
8052
|
+
const scale = (0, react.useMemo)(() => isValidHexColor(primaryHex) ? getHeatmapScale(primaryHex, chartBackgroundHex, emptyCellHex) : null, [
|
|
8053
|
+
primaryHex,
|
|
8054
|
+
chartBackgroundHex,
|
|
8055
|
+
emptyCellHex
|
|
8056
|
+
]);
|
|
8057
|
+
const fillVars = (0, react.useMemo)(() => ({
|
|
8058
|
+
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
8059
|
+
...scale && {
|
|
8060
|
+
"--a8c-charts-color-heatmap-low": scale.low,
|
|
8061
|
+
"--a8c-charts-color-heatmap-high": scale.high
|
|
8062
|
+
}
|
|
8063
|
+
}), [primaryColorHex, scale]);
|
|
8064
|
+
const cellTextColor = (intensity) => scale ? pickLabelTextColorForFill(blendRgb(hexToRgb(scale.high), hexToRgb(scale.low), intensity), labelRoles, "label") : "label";
|
|
8065
|
+
useIsomorphicLayoutEffect(() => {
|
|
8066
|
+
if (!containerRef.current) return;
|
|
8067
|
+
const next = resolveLabelRoles(createCssVariableResolver(containerRef.current));
|
|
8068
|
+
setLabelRoles((previous) => (0, import_fast_deep_equal.default)(previous, next) ? previous : next);
|
|
8069
|
+
}, [
|
|
8070
|
+
data,
|
|
8071
|
+
className,
|
|
8072
|
+
primaryColorHex,
|
|
8073
|
+
chartBackgroundHex
|
|
8074
|
+
]);
|
|
7830
8075
|
const extent = (0, react.useMemo)(() => getValueExtent(data), [data]);
|
|
7831
8076
|
const heatmapContext = (0, react.useMemo)(() => ({
|
|
7832
8077
|
extent,
|
|
7833
|
-
|
|
7834
|
-
}), [extent,
|
|
8078
|
+
fillVars
|
|
8079
|
+
}), [extent, fillVars]);
|
|
7835
8080
|
const columns = data.length;
|
|
7836
8081
|
const rows = Math.max(0, ...data.map((column) => column.data.length));
|
|
7837
8082
|
const groupLayout = (0, react.useMemo)(() => resolveColumnGroups(columnGroups, columns, 2), [columnGroups, columns]);
|
|
@@ -7982,9 +8227,10 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7982
8227
|
const firstDataRow = hasColumnLabels ? 2 : 1;
|
|
7983
8228
|
const dataTrack = (column) => column.summary ? "minmax(auto, max-content)" : columnTrack;
|
|
7984
8229
|
const gapTrack = compact ? `minmax(${groupGap}px, 1fr)` : `${groupGap}px`;
|
|
8230
|
+
const columnTracks = data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ");
|
|
7985
8231
|
const gridStyle = {
|
|
7986
|
-
|
|
7987
|
-
gridTemplateColumns: `auto ${
|
|
8232
|
+
...fillVars,
|
|
8233
|
+
gridTemplateColumns: `auto ${columnTracks}`,
|
|
7988
8234
|
gridTemplateRows: `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`
|
|
7989
8235
|
};
|
|
7990
8236
|
if (compact) {
|
|
@@ -8084,7 +8330,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8084
8330
|
}, `cell-${columnIndex}-${rowIndex}`);
|
|
8085
8331
|
const value = cell?.value ?? null;
|
|
8086
8332
|
const present = isPresent(value);
|
|
8087
|
-
const filled = present && !column.summary;
|
|
8333
|
+
const filled = present && !column.summary && !isEmptyValue(value, extent);
|
|
8088
8334
|
const normalized = filled ? getNormalizedValue(value, extent) : 0;
|
|
8089
8335
|
const info = buildTooltipData(columnIndex, rowIndex);
|
|
8090
8336
|
const accessibleLabel = `${cellName(info)}: ${info.value === null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(info.value)}`;
|
|
@@ -8098,7 +8344,6 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8098
8344
|
"data-row": rowIndex,
|
|
8099
8345
|
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__cell"], {
|
|
8100
8346
|
[heatmap_chart_module_default["heatmap-chart__cell--filled"]]: filled,
|
|
8101
|
-
[heatmap_chart_module_default["heatmap-chart__cell--strong"]]: filled && cellHasLightText(normalized),
|
|
8102
8347
|
[heatmap_chart_module_default["heatmap-chart__cell--summary"]]: column.summary,
|
|
8103
8348
|
...summaryGaps(columnIndex),
|
|
8104
8349
|
[heatmap_chart_module_default["heatmap-chart__cell--selected"]]: selected?.column === columnIndex && selected?.row === rowIndex
|
|
@@ -8110,7 +8355,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8110
8355
|
onMouseMove: handleCellMouseMove,
|
|
8111
8356
|
onMouseLeave: handleCellMouseLeave,
|
|
8112
8357
|
children: (drawValues || column.summary) && present && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8113
|
-
className: heatmap_chart_module_default["heatmap-chart__cell-value"],
|
|
8358
|
+
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__cell-value"], filled && CELL_VALUE_MODIFIER[cellTextColor(normalized)]),
|
|
8114
8359
|
children: (0, _automattic_number_formatters.formatNumberCompact)(value)
|
|
8115
8360
|
})
|
|
8116
8361
|
}, `cell-${columnIndex}-${rowIndex}`);
|
|
@@ -8134,7 +8379,6 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8134
8379
|
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
8135
8380
|
top: tooltipTop,
|
|
8136
8381
|
left: tooltipLeft,
|
|
8137
|
-
className: tooltipVariant === "dark" ? base_tooltip_module_default.surface : void 0,
|
|
8138
8382
|
style: tooltipBoxStyle,
|
|
8139
8383
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8140
8384
|
className: standaloneScopeClass,
|
|
@@ -11726,7 +11970,9 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
|
|
|
11726
11970
|
var pie_chart_module_default = {
|
|
11727
11971
|
"pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
|
|
11728
11972
|
"pie-chart__label-text": "a8ccharts-gnszbG-pie-chart__label-text",
|
|
11973
|
+
"pie-chart__label-text--black": "a8ccharts-gnszbG-pie-chart__label-text--black",
|
|
11729
11974
|
"pie-chart__label-text--on-light": "a8ccharts-gnszbG-pie-chart__label-text--on-light",
|
|
11975
|
+
"pie-chart__label-text--white": "a8ccharts-gnszbG-pie-chart__label-text--white",
|
|
11730
11976
|
"pie-chart__plot": "a8ccharts-gnszbG-pie-chart__plot",
|
|
11731
11977
|
"pie-chart--responsive": "a8ccharts-gnszbG-pie-chart--responsive"
|
|
11732
11978
|
};
|
|
@@ -11734,18 +11980,13 @@ var pie_chart_module_default = {
|
|
|
11734
11980
|
//#region src/charts/pie-chart/pie-chart.tsx
|
|
11735
11981
|
/**
|
|
11736
11982
|
* Default tooltip renderer for pie charts.
|
|
11737
|
-
* Renders
|
|
11983
|
+
* Renders the default `label: value` tooltip content for the hovered segment.
|
|
11738
11984
|
*
|
|
11739
11985
|
* @param {PieChartRenderTooltipParams} params - The tooltip parameters containing the hovered data point
|
|
11740
11986
|
* @return {ReactNode} The rendered tooltip content
|
|
11741
11987
|
*/
|
|
11742
11988
|
const renderDefaultPieTooltip = ({ tooltipData }) => {
|
|
11743
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
11744
|
-
data: tooltipData,
|
|
11745
|
-
top: 0,
|
|
11746
|
-
left: 0,
|
|
11747
|
-
renderContainer: false
|
|
11748
|
-
});
|
|
11989
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data: tooltipData });
|
|
11749
11990
|
};
|
|
11750
11991
|
/**
|
|
11751
11992
|
* Validates the pie chart data
|
|
@@ -11770,24 +12011,11 @@ const validateData$1 = (data) => {
|
|
|
11770
12011
|
message: ""
|
|
11771
12012
|
};
|
|
11772
12013
|
};
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
|
|
11778
|
-
* yet resolved, or labels off) keep the default inverse role.
|
|
11779
|
-
*
|
|
11780
|
-
* @param fill - The slice's resolved fill color.
|
|
11781
|
-
* @param pointers - The label pointers, resolved at the chart's own root element.
|
|
11782
|
-
* @return Whether the label needs dark text.
|
|
11783
|
-
*/
|
|
11784
|
-
const labelNeedsDarkText = (fill, pointers) => {
|
|
11785
|
-
if (!pointers || pointers.hasPlate) return false;
|
|
11786
|
-
const fillHex = normalizeColorToHex(fill);
|
|
11787
|
-
if (!isValidHexColor(fillHex) || !isValidHexColor(pointers.labelHex)) return false;
|
|
11788
|
-
if (pointers.isInverseSeeThrough) return true;
|
|
11789
|
-
if (!isValidHexColor(pointers.labelInverseHex)) return false;
|
|
11790
|
-
return contrastRatio(fillHex, pointers.labelHex) > contrastRatio(fillHex, pointers.labelInverseHex);
|
|
12014
|
+
const LABEL_TEXT_MODIFIER = {
|
|
12015
|
+
label: pie_chart_module_default["pie-chart__label-text--on-light"],
|
|
12016
|
+
"label-inverse": void 0,
|
|
12017
|
+
black: pie_chart_module_default["pie-chart__label-text--black"],
|
|
12018
|
+
white: pie_chart_module_default["pie-chart__label-text--white"]
|
|
11791
12019
|
};
|
|
11792
12020
|
/**
|
|
11793
12021
|
* Renders a pie or donut chart using the provided data.
|
|
@@ -11804,7 +12032,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
11804
12032
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
11805
12033
|
const containerRef = (0, react.useRef)(null);
|
|
11806
12034
|
const rootRef = (0, react.useRef)(null);
|
|
11807
|
-
const [
|
|
12035
|
+
const [labelRoles, setLabelRoles] = (0, react.useState)(null);
|
|
11808
12036
|
const onMouseLeave = (0, react.useCallback)(() => {
|
|
11809
12037
|
if (!withTooltips) return;
|
|
11810
12038
|
hideTooltip();
|
|
@@ -11815,18 +12043,9 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
11815
12043
|
if (!showLabels || !rootRef.current) return;
|
|
11816
12044
|
const resolve = createCssVariableResolver(rootRef.current);
|
|
11817
12045
|
const rawLabelBackground = resolve(CATALOG_POINTERS.labelBackground);
|
|
11818
|
-
const rawLabel = resolve(CATALOG_POINTERS.label);
|
|
11819
|
-
const isLabelOpaque = rawLabel ? (0, _visx_vendor_d3_color.color)(rawLabel)?.opacity === 1 : false;
|
|
11820
|
-
const rawLabelInverse = resolve(CATALOG_POINTERS.labelInverse);
|
|
11821
|
-
const labelInverseColor = rawLabelInverse ? (0, _visx_vendor_d3_color.color)(rawLabelInverse) : null;
|
|
11822
12046
|
const plateColor = rawLabelBackground ? (0, _visx_vendor_d3_color.color)(rawLabelBackground) : null;
|
|
11823
|
-
const next =
|
|
11824
|
-
|
|
11825
|
-
labelHex: isLabelOpaque ? normalizeColorToHex(CATALOG_POINTERS.label, null, resolve) : "",
|
|
11826
|
-
labelInverseHex: normalizeColorToHex(CATALOG_POINTERS.labelInverse, null, resolve),
|
|
11827
|
-
isInverseSeeThrough: labelInverseColor ? labelInverseColor.opacity < 1 : false
|
|
11828
|
-
};
|
|
11829
|
-
setLabelPointers((previous) => previous && previous.hasPlate === next.hasPlate && previous.labelHex === next.labelHex && previous.labelInverseHex === next.labelInverseHex && previous.isInverseSeeThrough === next.isInverseSeeThrough ? previous : next);
|
|
12047
|
+
const next = (rawLabelBackground ? !plateColor || plateColor.opacity > 0 : false) ? null : resolveLabelRoles(resolve);
|
|
12048
|
+
setLabelRoles((previous) => (0, import_fast_deep_equal.default)(previous, next) ? previous : next);
|
|
11830
12049
|
}, [
|
|
11831
12050
|
showLabels,
|
|
11832
12051
|
className,
|
|
@@ -11997,7 +12216,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
11997
12216
|
ry: 4,
|
|
11998
12217
|
pointerEvents: "none"
|
|
11999
12218
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
12000
|
-
className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"],
|
|
12219
|
+
className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"], LABEL_TEXT_MODIFIER[pickLabelTextColor(fill, labelRoles, "label-inverse")]),
|
|
12001
12220
|
x: centroidX,
|
|
12002
12221
|
y: centroidY,
|
|
12003
12222
|
dy: ".33em",
|
|
@@ -12053,18 +12272,13 @@ var pie_semi_circle_chart_module_default = {
|
|
|
12053
12272
|
//#region src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx
|
|
12054
12273
|
/**
|
|
12055
12274
|
* Default tooltip renderer for semi-circle pie charts.
|
|
12056
|
-
* Renders
|
|
12275
|
+
* Renders the default `label: value` tooltip content for the hovered segment.
|
|
12057
12276
|
*
|
|
12058
12277
|
* @param {PieSemiCircleChartRenderTooltipParams} params - The tooltip parameters containing the hovered data point
|
|
12059
12278
|
* @return {ReactNode} The rendered tooltip content
|
|
12060
12279
|
*/
|
|
12061
12280
|
const renderDefaultPieSemiCircleTooltip = ({ tooltipData }) => {
|
|
12062
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
12063
|
-
data: tooltipData,
|
|
12064
|
-
top: 0,
|
|
12065
|
-
left: 0,
|
|
12066
|
-
renderContainer: false
|
|
12067
|
-
});
|
|
12281
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data: tooltipData });
|
|
12068
12282
|
};
|
|
12069
12283
|
const PAD_ANGLE = .03;
|
|
12070
12284
|
const DEFAULT_WIDTH$1 = 400;
|
|
@@ -12532,7 +12746,9 @@ exports.PieSemiCircleChartUnresponsive = PieSemiCircleChart;
|
|
|
12532
12746
|
exports.Sparkline = Sparkline;
|
|
12533
12747
|
exports.SparklineUnresponsive = SparklineUnresponsive;
|
|
12534
12748
|
exports.ThemeProvider = GlobalChartsProvider;
|
|
12749
|
+
exports.TooltipBox = TooltipBox;
|
|
12535
12750
|
exports.TrendIndicator = TrendIndicator;
|
|
12751
|
+
exports.XYChartTooltip = XYChartTooltip;
|
|
12536
12752
|
exports.buildCalendarHeatmapData = buildCalendarHeatmapData;
|
|
12537
12753
|
exports.buildMonthCalendarHeatmapData = buildMonthCalendarHeatmapData;
|
|
12538
12754
|
exports.defaultTheme = defaultTheme;
|