@automattic/charts 4.7.0 → 4.9.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 +30 -0
- package/TOKENS.md +6 -3
- package/dist/index.cjs +834 -321
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +68 -17
- package/dist/index.d.cts +102 -28
- package/dist/index.d.ts +102 -28
- package/dist/index.js +838 -327
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/charts/area-chart/area-chart.tsx +7 -4
- package/src/charts/area-chart/test/area-chart.test.tsx +24 -15
- package/src/charts/area-chart/test/tooltip-resolution-branches.test.tsx +1 -1
- package/src/charts/area-chart/test/tooltip-resolution.test.tsx +2 -2
- package/src/charts/area-chart/types.ts +2 -0
- package/src/charts/bar-chart/bar-chart.module.scss +7 -0
- package/src/charts/bar-chart/bar-chart.tsx +25 -16
- package/src/charts/bar-chart/private/comparison-bars.tsx +1 -0
- package/src/charts/bar-chart/test/bar-chart.test.tsx +106 -62
- package/src/charts/bar-chart/types.ts +2 -0
- package/src/charts/bar-list-chart/test/bar-list-chart.test.tsx +3 -1
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +1 -1
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +9 -0
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +16 -8
- package/src/charts/heatmap-chart/heatmap-chart.tsx +183 -66
- package/src/charts/heatmap-chart/private/column-groups.ts +79 -8
- package/src/charts/heatmap-chart/private/fit-compact-cells.ts +72 -0
- package/src/charts/heatmap-chart/private/heatmap-context.ts +2 -2
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +15 -3
- package/src/charts/heatmap-chart/private/heatmap-scale.ts +74 -0
- package/src/charts/heatmap-chart/private/index.ts +6 -3
- package/src/charts/heatmap-chart/private/use-heatmap-colors.ts +24 -6
- package/src/charts/heatmap-chart/test/column-groups.test.ts +41 -4
- package/src/charts/heatmap-chart/test/fit-compact-cells.test.ts +59 -0
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +231 -8
- 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 -3
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +46 -4
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +37 -1
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +53 -0
- package/src/charts/leaderboard-chart/types.ts +6 -1
- package/src/charts/line-chart/line-chart.tsx +7 -4
- package/src/charts/line-chart/private/line-chart-annotation-label-popover.tsx +19 -9
- package/src/charts/line-chart/test/default-tooltip-formatting.test.tsx +1 -1
- package/src/charts/line-chart/test/line-chart.test.tsx +45 -35
- package/src/charts/line-chart/test/tooltip-resolution.test.tsx +2 -2
- package/src/charts/line-chart/types.ts +5 -3
- package/src/charts/pie-chart/pie-chart.tsx +153 -143
- package/src/charts/pie-chart/test/pie-chart.test.tsx +171 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +126 -124
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +55 -1
- package/src/charts/private/chart-composition/use-chart-children.ts +11 -6
- package/src/charts/private/pie-keyboard-navigation/index.ts +4 -0
- package/src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts +10 -0
- package/src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss +16 -0
- package/src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx +14 -0
- package/src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx +82 -0
- package/src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx +44 -0
- package/src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx +47 -0
- package/src/charts/private/pie-keyboard-navigation/test/order-arcs-for-navigation.test.ts +34 -0
- package/src/charts/private/pie-keyboard-navigation/test/selected-segment-ring.test.ts +14 -0
- package/src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts +139 -0
- package/src/charts/private/test/label-text-color.test.ts +6 -8
- package/src/charts/private/x-zoom/test/x-zoom.test.tsx +3 -2
- package/src/components/tooltip/base-tooltip.tsx +31 -32
- package/src/components/tooltip/index.ts +3 -1
- package/src/components/tooltip/private/bounded-tooltip.tsx +15 -15
- package/src/components/tooltip/private/label-value-content.tsx +8 -0
- package/src/components/tooltip/private/xy-chart-tooltip-overlay.tsx +336 -0
- package/src/components/tooltip/test/tool-tip.test.tsx +8 -6
- package/src/components/tooltip/test/tooltip-box.test.tsx +53 -0
- package/src/components/tooltip/test/xy-chart-tooltip-overlay.test.tsx +445 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +283 -365
- package/src/components/tooltip/{base-tooltip.module.scss → tooltip-box.module.scss} +5 -8
- 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 +410 -300
- package/src/hooks/test/use-chart-margin.test.tsx +8 -4
- package/src/hooks/use-chart-margin.tsx +21 -18
- 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 +1 -1
- package/src/providers/chart-context/private/catalog-pointers.ts +1 -0
- package/src/providers/chart-context/private/resolve-opaque-hex.ts +16 -0
- package/src/providers/chart-context/test/use-default-hidden-series.test.tsx +1 -1
- package/src/styles/chart-scope.scss +1 -0
- package/src/test-utils/zoned-parsing-suite.ts +0 -10
- package/src/types.ts +18 -2
- package/src/utils/test/date-formatting.test.ts +0 -10
- package/src/components/tooltip/accessible-tooltip.tsx +0 -433
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +0 -331
package/dist/index.cjs
CHANGED
|
@@ -29,12 +29,12 @@ 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");
|
|
@@ -836,6 +836,7 @@ const CATALOG_POINTERS = {
|
|
|
836
836
|
annotation: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
837
837
|
surface: "var(--a8c-charts-color-surface, #fff)",
|
|
838
838
|
surfaceSecondary: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
839
|
+
track: "var(--a8c-charts-color-track, #f0f0f0)",
|
|
839
840
|
trendUp: "var(--a8c-charts-color-trend-up, #008030)",
|
|
840
841
|
trendDown: "var(--a8c-charts-color-trend-down, #cc1818)",
|
|
841
842
|
series: SERIES_PALETTE_POINTERS
|
|
@@ -1065,6 +1066,15 @@ const rgbLuminance = (rgb) => {
|
|
|
1065
1066
|
* @return Ratio from 1 to 21.
|
|
1066
1067
|
*/
|
|
1067
1068
|
const luminanceContrastRatio = (first, second) => (Math.max(first, second) + .05) / (Math.min(first, second) + .05);
|
|
1069
|
+
/**
|
|
1070
|
+
* WCAG contrast ratio between two hex colors.
|
|
1071
|
+
*
|
|
1072
|
+
* @param first - First hex color.
|
|
1073
|
+
* @param second - Second hex color.
|
|
1074
|
+
* @return Ratio from 1 to 21.
|
|
1075
|
+
* @throws {Error} if either hex string is malformed
|
|
1076
|
+
*/
|
|
1077
|
+
const contrastRatio = (first, second) => luminanceContrastRatio(relativeLuminance(first), relativeLuminance(second));
|
|
1068
1078
|
/** WCAG 1.4.3 text contrast, which a label drawn on a fill needs from at least one label color. */
|
|
1069
1079
|
const MIN_LABEL_CONTRAST = 4.5;
|
|
1070
1080
|
/** Degrees of hue one unit of OKLCH chroma is worth when ranking candidates by hue. */
|
|
@@ -1255,6 +1265,14 @@ const buildPaletteGenerator = (normalizedSeeds, background, labelColors) => {
|
|
|
1255
1265
|
};
|
|
1256
1266
|
};
|
|
1257
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
|
|
1258
1276
|
//#region src/providers/chart-context/themes.ts
|
|
1259
1277
|
/**
|
|
1260
1278
|
* Default theme configuration: the shape and spacing a consumer can override.
|
|
@@ -1303,12 +1321,6 @@ const defaultTheme = {
|
|
|
1303
1321
|
};
|
|
1304
1322
|
//#endregion
|
|
1305
1323
|
//#region src/providers/chart-context/global-charts-provider.tsx
|
|
1306
|
-
const resolveOpaqueHex = (pointer, element) => {
|
|
1307
|
-
const raw = resolveCssVariable(pointer, element);
|
|
1308
|
-
if (!raw || (0, _visx_vendor_d3_color.color)(raw)?.opacity !== 1) return null;
|
|
1309
|
-
const hex = normalizeColorToHex(pointer, element, resolveCssVariable);
|
|
1310
|
-
return isValidHexColor(hex) ? hex : null;
|
|
1311
|
-
};
|
|
1312
1324
|
const PLACEHOLDER_LABEL_COLORS = [LABEL_FALLBACK, LABEL_INVERSE_FALLBACK];
|
|
1313
1325
|
const GlobalChartsContext = (0, react.createContext)(null);
|
|
1314
1326
|
const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
@@ -1336,8 +1348,9 @@ const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
|
1336
1348
|
const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
|
|
1337
1349
|
if (isValidHexColor(normalizedColor)) resolvedColors.push(normalizedColor);
|
|
1338
1350
|
}
|
|
1339
|
-
const
|
|
1340
|
-
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);
|
|
1341
1354
|
setColorCache({
|
|
1342
1355
|
colors: resolvedColors,
|
|
1343
1356
|
background: backgroundHex,
|
|
@@ -1673,10 +1686,10 @@ const DEFAULT_MARGIN_BOTTOM = 20;
|
|
|
1673
1686
|
*/
|
|
1674
1687
|
const DEFAULT_MARGIN_LEFT = 20;
|
|
1675
1688
|
/**
|
|
1676
|
-
* Bottom margin
|
|
1689
|
+
* Bottom margin when no X-axis sits below the chart, because it is on top or hidden.
|
|
1677
1690
|
* We only need a small buffer below the chart in that case.
|
|
1678
1691
|
*/
|
|
1679
|
-
const
|
|
1692
|
+
const DEFAULT_BOTTOM_WITHOUT_X_AXIS = 10;
|
|
1680
1693
|
/**
|
|
1681
1694
|
* Fallback font size used when we cannot derive a font size
|
|
1682
1695
|
* from the theme or axis styles for X-axis tick labels.
|
|
@@ -1756,18 +1769,18 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1756
1769
|
if (yAxisOrientation === "right") defaultMargin.right = yMarginValue;
|
|
1757
1770
|
else defaultMargin.left = yMarginValue;
|
|
1758
1771
|
}
|
|
1759
|
-
const xOrientation = options.axis?.x?.orientation === "top" ? "top" : "bottom";
|
|
1760
|
-
const { fontSize, tickLength, tickLabelStyle } = getXAxisLabelMetrics(theme, xOrientation);
|
|
1761
|
-
const computedXMargin = fontSize + tickLength;
|
|
1762
|
-
if (xOrientation === "top") {
|
|
1763
|
-
defaultMargin.top = Math.max(defaultMargin.top, computedXMargin);
|
|
1764
|
-
defaultMargin.bottom = DEFAULT_BOTTOM_FOR_TOP_AXIS;
|
|
1765
|
-
} else defaultMargin.bottom = Math.max(defaultMargin.bottom, computedXMargin);
|
|
1766
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);
|
|
1767
1780
|
const { first, last } = getEdgeTickWidths(options.axis?.x?.tickValues ?? [], options.axis?.x?.tickFormat, tickLabelStyle);
|
|
1768
1781
|
defaultMargin.left = Math.max(defaultMargin.left, Math.ceil(first / 2));
|
|
1769
1782
|
defaultMargin.right = Math.max(defaultMargin.right, Math.ceil(last / 2));
|
|
1770
|
-
}
|
|
1783
|
+
} else defaultMargin.bottom = DEFAULT_BOTTOM_WITHOUT_X_AXIS;
|
|
1771
1784
|
return defaultMargin;
|
|
1772
1785
|
}, [
|
|
1773
1786
|
options,
|
|
@@ -2479,11 +2492,12 @@ function useChartLegendItems(data, options = {}, legendShape) {
|
|
|
2479
2492
|
]);
|
|
2480
2493
|
}
|
|
2481
2494
|
//#endregion
|
|
2482
|
-
//#region src/components/tooltip/
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
"
|
|
2486
|
-
|
|
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
|
+
] });
|
|
2487
2501
|
//#endregion
|
|
2488
2502
|
//#region src/components/tooltip/private/tooltip-theme.tsx
|
|
2489
2503
|
const DEFAULT_SURFACE = "#1e1e1e";
|
|
@@ -2509,28 +2523,63 @@ const TooltipTheme = ({ children }) => {
|
|
|
2509
2523
|
});
|
|
2510
2524
|
};
|
|
2511
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
|
|
2512
2550
|
//#region src/components/tooltip/base-tooltip.tsx
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
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 }) => {
|
|
2519
2566
|
const content = children || data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
|
|
2520
2567
|
data,
|
|
2521
2568
|
className
|
|
2522
2569
|
});
|
|
2523
2570
|
if (!renderContainer) return content;
|
|
2524
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2525
|
-
className: (0, clsx.default)(CHART_SCOPE_CLASS, base_tooltip_module_default.tooltip),
|
|
2571
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipBox, {
|
|
2526
2572
|
style: {
|
|
2527
|
-
top
|
|
2528
|
-
|
|
2573
|
+
...top === void 0 && left === void 0 ? void 0 : {
|
|
2574
|
+
position: "absolute",
|
|
2575
|
+
top,
|
|
2576
|
+
left,
|
|
2577
|
+
transform: "translate(-50%, -100%)"
|
|
2578
|
+
},
|
|
2529
2579
|
...style
|
|
2530
2580
|
},
|
|
2531
|
-
role: "tooltip",
|
|
2532
2581
|
children: content
|
|
2533
|
-
})
|
|
2582
|
+
});
|
|
2534
2583
|
};
|
|
2535
2584
|
//#endregion
|
|
2536
2585
|
//#region src/components/tooltip/private/bounded-tooltip.tsx
|
|
@@ -2610,7 +2659,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2610
2659
|
};
|
|
2611
2660
|
};
|
|
2612
2661
|
/**
|
|
2613
|
-
*
|
|
2662
|
+
* A `TooltipBox`, positioned like visx's `TooltipWithBounds` but kept inside the
|
|
2614
2663
|
* nearest clipping ancestor — or the viewport when there is none — rather than
|
|
2615
2664
|
* inside its own parent. Rendered in-tree, a tooltip's parent is the chart
|
|
2616
2665
|
* wrapper, which is often narrower than the box; measuring against the parent
|
|
@@ -2619,7 +2668,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2619
2668
|
* Re-measures on every render, so a box whose content changes width between
|
|
2620
2669
|
* two hovers is placed for its current size.
|
|
2621
2670
|
*
|
|
2622
|
-
* @param props -
|
|
2671
|
+
* @param props - `TooltipBox` props plus placement.
|
|
2623
2672
|
* @param props.left - Anchor x, in wrapper coordinates.
|
|
2624
2673
|
* @param props.top - Anchor y, in wrapper coordinates.
|
|
2625
2674
|
* @param props.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
@@ -2685,9 +2734,11 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2685
2734
|
]);
|
|
2686
2735
|
const x = position?.x ?? left + offsetLeft;
|
|
2687
2736
|
const y = position?.y ?? top + (placement === "below-axis" ? POINTER_HEIGHT : offsetTop);
|
|
2688
|
-
|
|
2737
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(TooltipBox, {
|
|
2689
2738
|
ref: nodeRef,
|
|
2690
|
-
|
|
2739
|
+
role: "presentation",
|
|
2740
|
+
unstyled,
|
|
2741
|
+
className,
|
|
2691
2742
|
style: {
|
|
2692
2743
|
position: "absolute",
|
|
2693
2744
|
left: 0,
|
|
@@ -2710,10 +2761,9 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2710
2761
|
}
|
|
2711
2762
|
}), children]
|
|
2712
2763
|
});
|
|
2713
|
-
return unstyled ? box : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipTheme, { children: box });
|
|
2714
2764
|
};
|
|
2715
2765
|
//#endregion
|
|
2716
|
-
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2766
|
+
//#region src/components/tooltip/private/xy-chart-tooltip-overlay.tsx
|
|
2717
2767
|
const CROSSHAIR_STROKE_WIDTH = 1.5;
|
|
2718
2768
|
const CROSSHAIR_PAINT_PROPERTIES = /* @__PURE__ */ new Set([
|
|
2719
2769
|
"stroke",
|
|
@@ -2815,21 +2865,35 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2815
2865
|
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2816
2866
|
const marginTop = margin?.top ?? 0;
|
|
2817
2867
|
const marginLeft = margin?.left ?? 0;
|
|
2818
|
-
const TooltipComponent = detectBounds || tooltipPlacement !== "auto" ? BoundedTooltip : _visx_tooltip.Tooltip;
|
|
2819
2868
|
const boxStyle = {
|
|
2820
2869
|
zIndex,
|
|
2821
2870
|
...style
|
|
2822
2871
|
};
|
|
2823
|
-
const
|
|
2824
|
-
const
|
|
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, {
|
|
2825
2875
|
left: tooltipLeft,
|
|
2826
|
-
top:
|
|
2876
|
+
top: anchorTop,
|
|
2877
|
+
offsetLeft,
|
|
2878
|
+
offsetTop,
|
|
2879
|
+
unstyled,
|
|
2880
|
+
className,
|
|
2827
2881
|
style: boxStyle,
|
|
2828
|
-
|
|
2829
|
-
...tooltipProps,
|
|
2830
|
-
className: (0, clsx.default)(themesOwnBox && ["a8c-charts-scope", base_tooltip_module_default.surface], tooltipProps.className),
|
|
2882
|
+
...boxProps,
|
|
2831
2883
|
...tooltipPlacement !== "auto" && { placement: tooltipPlacement },
|
|
2832
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
|
|
2833
2897
|
});
|
|
2834
2898
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
2835
2899
|
className: "visx-tooltip-overlay",
|
|
@@ -2857,7 +2921,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2857
2921
|
}),
|
|
2858
2922
|
glyphs
|
|
2859
2923
|
]
|
|
2860
|
-
}), container && (0, react_dom.createPortal)(
|
|
2924
|
+
}), container && (0, react_dom.createPortal)(box, container)] });
|
|
2861
2925
|
};
|
|
2862
2926
|
/**
|
|
2863
2927
|
* In-tree replacement for `@visx/xychart`'s `Tooltip`.
|
|
@@ -2882,7 +2946,7 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2882
2946
|
* @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
|
|
2883
2947
|
* @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
|
|
2884
2948
|
*/
|
|
2885
|
-
const
|
|
2949
|
+
const XyChartTooltipOverlay = (props) => {
|
|
2886
2950
|
const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
2887
2951
|
const [container, setContainer] = (0, react.useState)(null);
|
|
2888
2952
|
const anchorRef = (0, react.useCallback)((node) => {
|
|
@@ -2895,8 +2959,8 @@ const XyChartTooltip = (props) => {
|
|
|
2895
2959
|
})] });
|
|
2896
2960
|
};
|
|
2897
2961
|
//#endregion
|
|
2898
|
-
//#region src/components/tooltip/
|
|
2899
|
-
const
|
|
2962
|
+
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2963
|
+
const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
|
|
2900
2964
|
const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
2901
2965
|
const scopeElement = useChartScopeElement();
|
|
2902
2966
|
const crosshairStroke = (0, react.useMemo)(() => {
|
|
@@ -3002,7 +3066,7 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
3002
3066
|
keyboardFocusedClassName,
|
|
3003
3067
|
standaloneScopeClass
|
|
3004
3068
|
]);
|
|
3005
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3069
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltipOverlay, {
|
|
3006
3070
|
...props,
|
|
3007
3071
|
verticalCrosshairStyle: {
|
|
3008
3072
|
...crosshairStroke,
|
|
@@ -3015,8 +3079,10 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
3015
3079
|
renderTooltip: focusableRenderTooltip
|
|
3016
3080
|
});
|
|
3017
3081
|
};
|
|
3082
|
+
/** @deprecated Use `XYChartTooltip`. */
|
|
3083
|
+
const AccessibleTooltip = XYChartTooltip;
|
|
3018
3084
|
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false, visibleSeriesKey }) => {
|
|
3019
|
-
const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"
|
|
3085
|
+
const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"application\"]") ?? chartRef.current, [chartRef]);
|
|
3020
3086
|
const focusWithoutScrollIfNeeded = (0, react.useCallback)((element) => {
|
|
3021
3087
|
if (preventTooltipScroll) element?.focus({ preventScroll: true });
|
|
3022
3088
|
else element?.focus();
|
|
@@ -3231,11 +3297,13 @@ function useChartChildren(children, chartType) {
|
|
|
3231
3297
|
}
|
|
3232
3298
|
const displayName = child.type?.displayName;
|
|
3233
3299
|
if (displayName === `${chartType}.SVG` || displayName === "Chart.SVG") {
|
|
3234
|
-
|
|
3300
|
+
const { children: svgChildren } = child.props ?? {};
|
|
3301
|
+
if (svgChildren) react.Children.forEach(svgChildren, (svgChild) => {
|
|
3235
3302
|
svg.push(svgChild);
|
|
3236
3303
|
});
|
|
3237
3304
|
} else if (displayName === `${chartType}.HTML` || displayName === "Chart.HTML") {
|
|
3238
|
-
|
|
3305
|
+
const { children: htmlChildren } = child.props ?? {};
|
|
3306
|
+
if (htmlChildren) react.Children.forEach(htmlChildren, (htmlChild) => {
|
|
3239
3307
|
html.push(htmlChild);
|
|
3240
3308
|
});
|
|
3241
3309
|
} else if (child.type === _visx_group.Group) svg.push(child);
|
|
@@ -4057,6 +4125,7 @@ var line_chart_module_default = {
|
|
|
4057
4125
|
"line-chart--animated": "a8ccharts-inuQka-line-chart--animated",
|
|
4058
4126
|
"rise": "a8ccharts-inuQka-rise"
|
|
4059
4127
|
};
|
|
4128
|
+
const isReact18 = react.version.startsWith("18.");
|
|
4060
4129
|
const CloseIcon = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
4061
4130
|
width: "16",
|
|
4062
4131
|
height: "16",
|
|
@@ -4099,7 +4168,7 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
|
|
|
4099
4168
|
className: line_chart_module_default["line-chart__annotation-label"],
|
|
4100
4169
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4101
4170
|
ref: buttonRef,
|
|
4102
|
-
popovertarget: popoverId,
|
|
4171
|
+
...isReact18 ? { popovertarget: popoverId } : { popoverTarget: popoverId },
|
|
4103
4172
|
className: line_chart_module_default["line-chart__annotation-label-trigger-button"],
|
|
4104
4173
|
style: {
|
|
4105
4174
|
width: `44px`,
|
|
@@ -4127,8 +4196,13 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
|
|
|
4127
4196
|
subtitle
|
|
4128
4197
|
})
|
|
4129
4198
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4130
|
-
|
|
4131
|
-
|
|
4199
|
+
...isReact18 ? {
|
|
4200
|
+
popovertarget: popoverId,
|
|
4201
|
+
popovertargetaction: "hide"
|
|
4202
|
+
} : {
|
|
4203
|
+
popoverTarget: popoverId,
|
|
4204
|
+
popoverTargetAction: "hide"
|
|
4205
|
+
},
|
|
4132
4206
|
className: line_chart_module_default["line-chart__annotation-label-popover-close-button"],
|
|
4133
4207
|
"aria-label": (0, _wordpress_i18n.__)("Close", "jetpack-charts"),
|
|
4134
4208
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseIcon, {})
|
|
@@ -4650,7 +4724,7 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
4650
4724
|
]);
|
|
4651
4725
|
return null;
|
|
4652
4726
|
};
|
|
4653
|
-
const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, tooltipPlacement, tooltipStyle, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, onDatumActivate = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
4727
|
+
const LineChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, tooltipPlacement, tooltipStyle, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, onDatumActivate = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
4654
4728
|
const legendInteractive = legend.interactive ?? false;
|
|
4655
4729
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
4656
4730
|
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
@@ -4918,8 +4992,8 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4918
4992
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
4919
4993
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4920
4994
|
ref: chartRef,
|
|
4921
|
-
role: "
|
|
4922
|
-
"aria-label": (0, _wordpress_i18n.__)("Line chart", "jetpack-charts"),
|
|
4995
|
+
role: "application",
|
|
4996
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Line chart", "jetpack-charts"),
|
|
4923
4997
|
tabIndex: 0,
|
|
4924
4998
|
onKeyDown: onChartKeyDown,
|
|
4925
4999
|
onFocus: onChartFocus,
|
|
@@ -4927,6 +5001,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4927
5001
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4928
5002
|
className: xy_plot_module_default["xy-plot"],
|
|
4929
5003
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
5004
|
+
accessibilityLabel: "",
|
|
4930
5005
|
theme,
|
|
4931
5006
|
width,
|
|
4932
5007
|
height: chartHeight,
|
|
@@ -5020,7 +5095,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5020
5095
|
] }, seriesData?.label || index);
|
|
5021
5096
|
})
|
|
5022
5097
|
}),
|
|
5023
|
-
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5098
|
+
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
|
|
5024
5099
|
detectBounds: true,
|
|
5025
5100
|
snapTooltipToDatumX: true,
|
|
5026
5101
|
tooltipPlacement,
|
|
@@ -5167,7 +5242,7 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
|
|
|
5167
5242
|
};
|
|
5168
5243
|
//#endregion
|
|
5169
5244
|
//#region src/charts/area-chart/area-chart.tsx
|
|
5170
|
-
const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
5245
|
+
const AreaChartInternal = (0, react.forwardRef)(({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
5171
5246
|
const legendInteractive = legend.interactive ?? false;
|
|
5172
5247
|
const legendShape = legend.shape ?? "rect";
|
|
5173
5248
|
const legendPosition = legend.position ?? "bottom";
|
|
@@ -5438,8 +5513,8 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5438
5513
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
5439
5514
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5440
5515
|
ref: chartRef,
|
|
5441
|
-
role: "
|
|
5442
|
-
"aria-label": (0, _wordpress_i18n.__)("Area chart", "jetpack-charts"),
|
|
5516
|
+
role: "application",
|
|
5517
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Area chart", "jetpack-charts"),
|
|
5443
5518
|
tabIndex: 0,
|
|
5444
5519
|
onKeyDown: onChartKeyDown,
|
|
5445
5520
|
onFocus: onChartFocus,
|
|
@@ -5447,6 +5522,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5447
5522
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5448
5523
|
className: xy_plot_module_default["xy-plot"],
|
|
5449
5524
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
5525
|
+
accessibilityLabel: "",
|
|
5450
5526
|
theme,
|
|
5451
5527
|
width,
|
|
5452
5528
|
height: chartHeight,
|
|
@@ -5496,7 +5572,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5496
5572
|
children: seriesWithVisibility.map(renderSeries)
|
|
5497
5573
|
}), !allSeriesHidden && !stacked && seriesWithVisibility.map(renderSeries)]
|
|
5498
5574
|
}),
|
|
5499
|
-
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
5575
|
+
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
|
|
5500
5576
|
detectBounds: true,
|
|
5501
5577
|
snapTooltipToDatumX: true,
|
|
5502
5578
|
snapTooltipToDatumY: !stacked,
|
|
@@ -6107,6 +6183,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
6107
6183
|
widthFactor
|
|
6108
6184
|
});
|
|
6109
6185
|
rects.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
6186
|
+
className: "bar-chart__comparison-bar",
|
|
6110
6187
|
x: rect.x,
|
|
6111
6188
|
y: rect.y,
|
|
6112
6189
|
width: rect.width,
|
|
@@ -6298,7 +6375,7 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ (0, react_jsx_runtime
|
|
|
6298
6375
|
className: bar_chart_module_default["bar-chart__tooltip-row"],
|
|
6299
6376
|
children: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%1$s: %2$s", "jetpack-charts"), label, value)
|
|
6300
6377
|
});
|
|
6301
|
-
const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
6378
|
+
const BarChartInternal = ({ data, ariaLabel, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, tooltipStyle, barClassName, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
6302
6379
|
if (!withTooltips && (withBandHighlight || onBandHighlightChange)) warnOnce("bar-chart-band-highlight-without-tooltips", "BarChart: withBandHighlight and onBandHighlightChange require withTooltips.");
|
|
6303
6380
|
const legendInteractive = legend.interactive ?? false;
|
|
6304
6381
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
@@ -6522,7 +6599,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6522
6599
|
const patternId = getPatternId(chartId, index);
|
|
6523
6600
|
return `
|
|
6524
6601
|
.visx-bar[fill="url(#${patternId})"],
|
|
6525
|
-
.bar-chart__comparison-
|
|
6602
|
+
.bar-chart__comparison-bar[fill="url(#${patternId})"] {
|
|
6526
6603
|
stroke: ${color};
|
|
6527
6604
|
stroke-width: 1;
|
|
6528
6605
|
}
|
|
@@ -6606,9 +6683,9 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6606
6683
|
children: ({ contentHeight }) => {
|
|
6607
6684
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
6608
6685
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6609
|
-
role: "
|
|
6686
|
+
role: "application",
|
|
6610
6687
|
ref: chartRef,
|
|
6611
|
-
"aria-label": (0, _wordpress_i18n.__)("Bar chart", "jetpack-charts"),
|
|
6688
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Bar chart", "jetpack-charts"),
|
|
6612
6689
|
tabIndex: 0,
|
|
6613
6690
|
onKeyDown: onChartKeyDown,
|
|
6614
6691
|
onFocus: onChartFocus,
|
|
@@ -6616,6 +6693,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6616
6693
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6617
6694
|
className: xy_plot_module_default["xy-plot"],
|
|
6618
6695
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
6696
|
+
accessibilityLabel: "",
|
|
6619
6697
|
theme,
|
|
6620
6698
|
width,
|
|
6621
6699
|
height: chartHeight,
|
|
@@ -6704,15 +6782,15 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6704
6782
|
}),
|
|
6705
6783
|
!allSeriesHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WholeNumberTicks, {
|
|
6706
6784
|
...wholeNumberTicksProps,
|
|
6707
|
-
children: (valueTicks) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
|
|
6785
|
+
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, {
|
|
6708
6786
|
...chartOptions.axis.x,
|
|
6709
6787
|
...horizontal && valueTicks ? { tickValues: valueTicks } : {}
|
|
6710
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
|
|
6788
|
+
}), chartOptions.axis.y.display !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, {
|
|
6711
6789
|
...chartOptions.axis.y,
|
|
6712
6790
|
...!horizontal && valueTicks ? { tickValues: valueTicks } : {}
|
|
6713
6791
|
})] })
|
|
6714
6792
|
}),
|
|
6715
|
-
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
6793
|
+
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XYChartTooltip, {
|
|
6716
6794
|
tooltipPlacement,
|
|
6717
6795
|
tooltipAnchorTop,
|
|
6718
6796
|
style: tooltipStyle,
|
|
@@ -7239,7 +7317,10 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7239
7317
|
left: tooltipLeft,
|
|
7240
7318
|
className: standaloneScopeClass,
|
|
7241
7319
|
style: tooltipStyle,
|
|
7242
|
-
children:
|
|
7320
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7321
|
+
role: "tooltip",
|
|
7322
|
+
children: tooltipContent
|
|
7323
|
+
})
|
|
7243
7324
|
});
|
|
7244
7325
|
})()]
|
|
7245
7326
|
});
|
|
@@ -7618,6 +7699,7 @@ var heatmap_chart_module_default = {
|
|
|
7618
7699
|
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
7619
7700
|
"heatmap-chart__legend-scale--bar": "a8ccharts-O3YMOW-heatmap-chart__legend-scale--bar",
|
|
7620
7701
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
7702
|
+
"heatmap-chart__legend-swatch--empty": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch--empty",
|
|
7621
7703
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
7622
7704
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
7623
7705
|
"heatmap-chart--height-capped": "a8ccharts-O3YMOW-heatmap-chart--height-capped"
|
|
@@ -7626,30 +7708,44 @@ var heatmap_chart_module_default = {
|
|
|
7626
7708
|
//#region src/charts/heatmap-chart/private/use-heatmap-colors.ts
|
|
7627
7709
|
const isPresent = (value) => value !== null && value !== void 0 && !isNaN(value);
|
|
7628
7710
|
/**
|
|
7629
|
-
* Get the min and max values from heatmap data, ignoring null/NaN
|
|
7630
|
-
* columns stay out: a roll-up on the
|
|
7711
|
+
* Get the min and max values from heatmap data, ignoring null/NaN and the zeros
|
|
7712
|
+
* `isEmptyValue` paints as empty. Summary columns stay out: a roll-up on the
|
|
7713
|
+
* scale would flatten every real cell.
|
|
7631
7714
|
* @param data - The heatmap columns
|
|
7632
7715
|
* @return Tuple of [min, max] values
|
|
7633
7716
|
*/
|
|
7634
7717
|
const getValueExtent = (data) => {
|
|
7635
7718
|
let min = Infinity;
|
|
7636
7719
|
let max = -Infinity;
|
|
7720
|
+
let hasZero = false;
|
|
7637
7721
|
for (const column of data) {
|
|
7638
7722
|
if (column.summary) continue;
|
|
7639
7723
|
for (const cell of column.data) {
|
|
7640
7724
|
if (!isPresent(cell.value)) continue;
|
|
7725
|
+
if (cell.value === 0) {
|
|
7726
|
+
hasZero = true;
|
|
7727
|
+
continue;
|
|
7728
|
+
}
|
|
7641
7729
|
if (cell.value < min) min = cell.value;
|
|
7642
7730
|
if (cell.value > max) max = cell.value;
|
|
7643
7731
|
}
|
|
7644
7732
|
}
|
|
7733
|
+
if (hasZero && min < 0) max = Math.max(max, 0);
|
|
7645
7734
|
if (min === Infinity) return [0, 0];
|
|
7646
7735
|
return [min, max];
|
|
7647
7736
|
};
|
|
7648
7737
|
/**
|
|
7738
|
+
* Whether a value paints as an empty cell: a zero in data with no negatives
|
|
7739
|
+
* counts nothing, so it must not look like the lowest step of activity.
|
|
7740
|
+
*
|
|
7741
|
+
* @param value - The cell value
|
|
7742
|
+
* @param extent - The extent from `getValueExtent`
|
|
7743
|
+
* @return True when the cell takes the empty-cell color
|
|
7744
|
+
*/
|
|
7745
|
+
const isEmptyValue = (value, extent) => value === 0 && extent[0] >= 0;
|
|
7746
|
+
/**
|
|
7649
7747
|
* Normalize a value to 0–1 within the extent. A flat extent (min === max)
|
|
7650
|
-
* maps to 1
|
|
7651
|
-
* extent, which maps to 0 so a no-activity grid renders at the scale's
|
|
7652
|
-
* bottom instead of full intensity.
|
|
7748
|
+
* maps to 1, since every cell is equally the "highest".
|
|
7653
7749
|
*
|
|
7654
7750
|
* @param value - The value to normalize
|
|
7655
7751
|
* @param extent - Tuple of [min, max] values for the normalization range
|
|
@@ -7657,9 +7753,40 @@ const getValueExtent = (data) => {
|
|
|
7657
7753
|
*/
|
|
7658
7754
|
const getNormalizedValue = (value, extent) => {
|
|
7659
7755
|
const [min, max] = extent;
|
|
7660
|
-
if (min === max) return
|
|
7756
|
+
if (min === max) return 1;
|
|
7661
7757
|
return Math.min(1, Math.max(0, (value - min) / (max - min)));
|
|
7662
7758
|
};
|
|
7759
|
+
const STEPS = 200;
|
|
7760
|
+
const firstMeeting = (from, to, meets) => {
|
|
7761
|
+
for (let step = 0; step <= STEPS; step++) {
|
|
7762
|
+
const color = mixHexColors(from, to, step / STEPS);
|
|
7763
|
+
if (meets(color)) return color;
|
|
7764
|
+
}
|
|
7765
|
+
return null;
|
|
7766
|
+
};
|
|
7767
|
+
/**
|
|
7768
|
+
* The two ends of the heatmap fill scale: 3:1 against the background and the empty cell at the
|
|
7769
|
+
* low end, toward 9:1 against the background at the high end.
|
|
7770
|
+
*
|
|
7771
|
+
* @param primary - The resolved primary color, as six-digit hex.
|
|
7772
|
+
* @param background - The resolved chart background, as six-digit hex.
|
|
7773
|
+
* @param emptyCell - The resolved empty-cell color, as six-digit hex, when it is opaque.
|
|
7774
|
+
* @return The scale ends, as six-digit hex.
|
|
7775
|
+
*/
|
|
7776
|
+
const getHeatmapScale = (primary, background, emptyCell) => {
|
|
7777
|
+
const primaryStandsOut = contrastRatio(primary, background) >= 3;
|
|
7778
|
+
const extreme = (primaryStandsOut ? relativeLuminance(primary) > relativeLuminance(background) : contrastRatio("#ffffff", background) > contrastRatio("#000000", background)) ? "#ffffff" : "#000000";
|
|
7779
|
+
const lowAgainst = (references) => {
|
|
7780
|
+
const meets = (color) => references.every((reference) => contrastRatio(color, reference) >= 3);
|
|
7781
|
+
return (primaryStandsOut ? firstMeeting(background, primary, meets) : null) ?? firstMeeting(primary, extreme, meets);
|
|
7782
|
+
};
|
|
7783
|
+
const high = firstMeeting(primary, extreme, (color) => contrastRatio(color, background) >= 9) ?? extreme;
|
|
7784
|
+
const againstEmptyCell = emptyCell ? lowAgainst([background, emptyCell]) : null;
|
|
7785
|
+
return {
|
|
7786
|
+
low: (againstEmptyCell && contrastRatio(againstEmptyCell, background) <= contrastRatio(high, background) ? againstEmptyCell : lowAgainst([background])) ?? extreme,
|
|
7787
|
+
high
|
|
7788
|
+
};
|
|
7789
|
+
};
|
|
7663
7790
|
//#endregion
|
|
7664
7791
|
//#region src/charts/heatmap-chart/private/heatmap-context.ts
|
|
7665
7792
|
/** Shared by the chart and legend without importing back from `heatmap-chart.tsx`. */
|
|
@@ -7670,8 +7797,9 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
|
|
|
7670
7797
|
const context = (0, react.useContext)(HeatmapContext);
|
|
7671
7798
|
const { legend } = useGlobalChartsTheme();
|
|
7672
7799
|
if (!context) return null;
|
|
7673
|
-
const {
|
|
7800
|
+
const { extent, fillVars } = context;
|
|
7674
7801
|
const labelStyle = legend.labelStyles;
|
|
7802
|
+
const showsEmptyCell = isEmptyValue(0, extent);
|
|
7675
7803
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7676
7804
|
direction: "row",
|
|
7677
7805
|
gap: "xs",
|
|
@@ -7683,21 +7811,21 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
|
|
|
7683
7811
|
style: labelStyle,
|
|
7684
7812
|
children: lessLabel ?? (0, _wordpress_i18n.__)("Less", "jetpack-charts")
|
|
7685
7813
|
}),
|
|
7686
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7814
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7687
7815
|
direction: "row",
|
|
7688
7816
|
gap: variant === "bar" ? void 0 : "xs",
|
|
7689
7817
|
"aria-hidden": "true",
|
|
7690
7818
|
className: variant === "bar" ? heatmap_chart_module_default["heatmap-chart__legend-scale--bar"] : void 0,
|
|
7691
|
-
children: Array.from({ length: steps }, (_, index) => {
|
|
7819
|
+
children: [showsEmptyCell && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__legend-swatch"], heatmap_chart_module_default["heatmap-chart__legend-swatch--empty"]) }), Array.from({ length: steps }, (_, index) => {
|
|
7692
7820
|
const intensity = steps <= 1 ? 1 : index / (steps - 1);
|
|
7693
7821
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7694
7822
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
7695
7823
|
style: {
|
|
7696
|
-
|
|
7824
|
+
...fillVars,
|
|
7697
7825
|
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
7698
7826
|
}
|
|
7699
7827
|
}, index);
|
|
7700
|
-
})
|
|
7828
|
+
})]
|
|
7701
7829
|
}),
|
|
7702
7830
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
7703
7831
|
variant: "body-sm",
|
|
@@ -7723,9 +7851,11 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
|
7723
7851
|
const ungrouped = () => ({
|
|
7724
7852
|
columns: Array.from({ length: columnCount }, (_, index) => ({
|
|
7725
7853
|
line: firstLine + index,
|
|
7854
|
+
band: 0,
|
|
7726
7855
|
gapBefore: false
|
|
7727
7856
|
})),
|
|
7728
|
-
groups: []
|
|
7857
|
+
groups: [],
|
|
7858
|
+
bands: 1
|
|
7729
7859
|
});
|
|
7730
7860
|
if (!groups || groups.length === 0 || columnCount === 0) return ungrouped();
|
|
7731
7861
|
const spans = groups.map((group) => group.span);
|
|
@@ -7741,11 +7871,13 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
|
7741
7871
|
if (groupIndex > 0) line += 1;
|
|
7742
7872
|
laidOut.push({
|
|
7743
7873
|
...group,
|
|
7744
|
-
line
|
|
7874
|
+
line,
|
|
7875
|
+
band: 0
|
|
7745
7876
|
});
|
|
7746
7877
|
for (let offset = 0; offset < group.span; offset++) {
|
|
7747
7878
|
columns.push({
|
|
7748
7879
|
line,
|
|
7880
|
+
band: 0,
|
|
7749
7881
|
gapBefore: groupIndex > 0 && offset === 0,
|
|
7750
7882
|
group: groupIndex
|
|
7751
7883
|
});
|
|
@@ -7755,13 +7887,99 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
|
7755
7887
|
while (columns.length < columnCount) {
|
|
7756
7888
|
columns.push({
|
|
7757
7889
|
line,
|
|
7890
|
+
band: 0,
|
|
7758
7891
|
gapBefore: false
|
|
7759
7892
|
});
|
|
7760
7893
|
line += 1;
|
|
7761
7894
|
}
|
|
7762
7895
|
return {
|
|
7763
7896
|
columns,
|
|
7764
|
-
groups: laidOut
|
|
7897
|
+
groups: laidOut,
|
|
7898
|
+
bands: 1
|
|
7899
|
+
};
|
|
7900
|
+
};
|
|
7901
|
+
/**
|
|
7902
|
+
* Wraps the groups onto bands of equal group count, each band starting back at
|
|
7903
|
+
* the first data line so the groups line up in slots down the bands.
|
|
7904
|
+
*
|
|
7905
|
+
* @param layout - The unwrapped layout from `resolveColumnGroups`.
|
|
7906
|
+
* @param bands - Bands to aim for; the groups split as evenly as whole bands allow.
|
|
7907
|
+
* @return The wrapped layout, or null when there is nothing to wrap: one band, one group, or a column outside every group.
|
|
7908
|
+
*/
|
|
7909
|
+
const wrapColumnGroups = (layout, bands) => {
|
|
7910
|
+
const { columns, groups } = layout;
|
|
7911
|
+
if (bands < 2 || groups.length < 2 || columns.some((column) => column.group === void 0)) return null;
|
|
7912
|
+
const perBand = Math.ceil(groups.length / bands);
|
|
7913
|
+
const slotSpans = Array(perBand).fill(0);
|
|
7914
|
+
groups.forEach((group, index) => {
|
|
7915
|
+
const slot = index % perBand;
|
|
7916
|
+
slotSpans[slot] = Math.max(slotSpans[slot], group.span);
|
|
7917
|
+
});
|
|
7918
|
+
const slotLines = [];
|
|
7919
|
+
let line = columns[0].line;
|
|
7920
|
+
slotSpans.forEach((span, slot) => {
|
|
7921
|
+
if (slot > 0) line += 1;
|
|
7922
|
+
slotLines.push(line);
|
|
7923
|
+
line += span;
|
|
7924
|
+
});
|
|
7925
|
+
const wrappedGroups = groups.map((group, index) => ({
|
|
7926
|
+
...group,
|
|
7927
|
+
line: slotLines[index % perBand],
|
|
7928
|
+
band: Math.floor(index / perBand)
|
|
7929
|
+
}));
|
|
7930
|
+
return {
|
|
7931
|
+
columns: columns.map((column) => {
|
|
7932
|
+
const group = column.group;
|
|
7933
|
+
const offset = column.line - groups[group].line;
|
|
7934
|
+
return {
|
|
7935
|
+
...column,
|
|
7936
|
+
line: wrappedGroups[group].line + offset,
|
|
7937
|
+
band: wrappedGroups[group].band,
|
|
7938
|
+
gapBefore: offset === 0 && group % perBand > 0
|
|
7939
|
+
};
|
|
7940
|
+
}),
|
|
7941
|
+
groups: wrappedGroups,
|
|
7942
|
+
bands: Math.ceil(groups.length / perBand),
|
|
7943
|
+
slotSpans
|
|
7944
|
+
};
|
|
7945
|
+
};
|
|
7946
|
+
//#endregion
|
|
7947
|
+
//#region src/charts/heatmap-chart/private/fit-compact-cells.ts
|
|
7948
|
+
/**
|
|
7949
|
+
* Largest whole-pixel square cell, and the band count giving it, for a compact grid in a box.
|
|
7950
|
+
*
|
|
7951
|
+
* @param input - The box, the grid's layout, and its fixed gaps and label sizes.
|
|
7952
|
+
* @return The fit; one band at `minCellSize` when no band count reaches it.
|
|
7953
|
+
*/
|
|
7954
|
+
const fitCompactCells = (input) => {
|
|
7955
|
+
const { width, height, layout, rows, cellGap, groupGap, minCellSize } = input;
|
|
7956
|
+
const columns = layout.columns.length;
|
|
7957
|
+
if (columns === 0 || rows === 0) return {
|
|
7958
|
+
bands: 1,
|
|
7959
|
+
cellSize: minCellSize
|
|
7960
|
+
};
|
|
7961
|
+
const maxBands = Math.max(1, layout.groups.length);
|
|
7962
|
+
const labelHeights = (input.columnLabelHeight ?? 0) + (input.groupLabelHeight ?? 0);
|
|
7963
|
+
const bandTracks = (input.columnLabelHeight === null ? 0 : 1) + rows + (input.groupLabelHeight === null ? 0 : 1);
|
|
7964
|
+
let best = null;
|
|
7965
|
+
for (let target = 1; target <= maxBands; target++) {
|
|
7966
|
+
const wrapped = target > 1 ? wrapColumnGroups(layout, target) : null;
|
|
7967
|
+
const { bands } = wrapped ?? layout;
|
|
7968
|
+
const cellColumns = wrapped ? wrapped.slotSpans.reduce((sum, span) => sum + span, 0) : columns;
|
|
7969
|
+
const gapTracks = wrapped ? wrapped.slotSpans.length - 1 : layout.columns.filter((column) => column.gapBefore).length;
|
|
7970
|
+
const columnTracks = 1 + cellColumns + gapTracks;
|
|
7971
|
+
const byWidth = (width - input.rowLabelWidth - gapTracks * groupGap - (columnTracks - 1) * cellGap) / cellColumns;
|
|
7972
|
+
const rowTracks = bands * bandTracks + (bands - 1);
|
|
7973
|
+
const byHeight = (height - (bands * labelHeights + (bands - 1) * groupGap + (rowTracks - 1) * cellGap)) / (bands * rows);
|
|
7974
|
+
const cellSize = Math.floor(Math.min(byWidth, byHeight));
|
|
7975
|
+
if (cellSize >= minCellSize && (!best || cellSize > best.cellSize)) best = {
|
|
7976
|
+
bands,
|
|
7977
|
+
cellSize
|
|
7978
|
+
};
|
|
7979
|
+
}
|
|
7980
|
+
return best ?? {
|
|
7981
|
+
bands: 1,
|
|
7982
|
+
cellSize: minCellSize
|
|
7765
7983
|
};
|
|
7766
7984
|
};
|
|
7767
7985
|
//#endregion
|
|
@@ -7897,7 +8115,6 @@ const stepCalendarCell = (grid, blocks, from, key) => {
|
|
|
7897
8115
|
};
|
|
7898
8116
|
//#endregion
|
|
7899
8117
|
//#region src/charts/heatmap-chart/heatmap-chart.tsx
|
|
7900
|
-
const CELL_MIX_FLOOR = .15;
|
|
7901
8118
|
const CELL_VALUE_MODIFIER = {
|
|
7902
8119
|
label: void 0,
|
|
7903
8120
|
"label-inverse": heatmap_chart_module_default["heatmap-chart__cell-value--inverse"],
|
|
@@ -7906,12 +8123,26 @@ const CELL_VALUE_MODIFIER = {
|
|
|
7906
8123
|
};
|
|
7907
8124
|
const NO_ROW_LABELS = [];
|
|
7908
8125
|
const TOOLTIP_BOX_STYLE = { zIndex: 3 };
|
|
8126
|
+
const largest = (root, selector, size) => Math.max(0, ...Array.from(root.querySelectorAll(selector), (el) => el[size]));
|
|
8127
|
+
const gridBox = (chart, grid) => {
|
|
8128
|
+
let height = chart.clientHeight;
|
|
8129
|
+
const rowGap = parseFloat(getComputedStyle(chart).rowGap) || 0;
|
|
8130
|
+
Array.from(chart.children).forEach((child) => {
|
|
8131
|
+
const { display, position } = getComputedStyle(child);
|
|
8132
|
+
if (child === grid || display === "none" || position === "absolute" || position === "fixed") return;
|
|
8133
|
+
height -= child.offsetHeight + rowGap;
|
|
8134
|
+
});
|
|
8135
|
+
return {
|
|
8136
|
+
width: chart.clientWidth,
|
|
8137
|
+
height
|
|
8138
|
+
};
|
|
8139
|
+
};
|
|
7909
8140
|
const cellName = (info) => info.cellLabel || [
|
|
7910
8141
|
info.groupLabel,
|
|
7911
8142
|
info.columnLabel,
|
|
7912
8143
|
info.rowLabel
|
|
7913
8144
|
].filter(Boolean).join(" ");
|
|
7914
|
-
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 }) => {
|
|
8145
|
+
const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, fitCells = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, columnGroups, keyboardNavigation = "grid", ariaLabel, primaryColor, gap = "md", withTooltips = false, renderTooltip, tooltipStyle, children }) => {
|
|
7915
8146
|
const chartId = useChartId(providedChartId);
|
|
7916
8147
|
const tooltipBoxStyle = tooltipStyle ? {
|
|
7917
8148
|
...TOOLTIP_BOX_STYLE,
|
|
@@ -7925,19 +8156,30 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7925
8156
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
7926
8157
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
7927
8158
|
const containerRef = (0, react.useRef)(null);
|
|
8159
|
+
const chartRef = (0, react.useRef)(null);
|
|
7928
8160
|
const [labelRoles, setLabelRoles] = (0, react.useState)(null);
|
|
7929
|
-
const getTooltipOrigin = (0, react.useCallback)(() =>
|
|
8161
|
+
const getTooltipOrigin = (0, react.useCallback)(() => chartRef.current?.getBoundingClientRect() ?? null, []);
|
|
7930
8162
|
const { color: primaryColorHex } = getElementStyles({
|
|
7931
8163
|
index: 0,
|
|
7932
8164
|
overrideColor: primaryColor
|
|
7933
8165
|
});
|
|
7934
|
-
const
|
|
8166
|
+
const resolveAtScope = createCssVariableResolver(scopeElement);
|
|
8167
|
+
const chartBackgroundHex = resolveOpaqueHex(CATALOG_POINTERS.background, resolveAtScope) ?? "#ffffff";
|
|
8168
|
+
const emptyCellHex = resolveOpaqueHex(CATALOG_POINTERS.track, resolveAtScope);
|
|
7935
8169
|
const primaryHex = normalizeColorToHex(primaryColorHex);
|
|
7936
|
-
const
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
8170
|
+
const scale = (0, react.useMemo)(() => isValidHexColor(primaryHex) ? getHeatmapScale(primaryHex, chartBackgroundHex, emptyCellHex) : null, [
|
|
8171
|
+
primaryHex,
|
|
8172
|
+
chartBackgroundHex,
|
|
8173
|
+
emptyCellHex
|
|
8174
|
+
]);
|
|
8175
|
+
const fillVars = (0, react.useMemo)(() => ({
|
|
8176
|
+
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
8177
|
+
...scale && {
|
|
8178
|
+
"--a8c-charts-color-heatmap-low": scale.low,
|
|
8179
|
+
"--a8c-charts-color-heatmap-high": scale.high
|
|
8180
|
+
}
|
|
8181
|
+
}), [primaryColorHex, scale]);
|
|
8182
|
+
const cellTextColor = (intensity) => scale ? pickLabelTextColorForFill(blendRgb(hexToRgb(scale.high), hexToRgb(scale.low), intensity), labelRoles, "label") : "label";
|
|
7941
8183
|
useIsomorphicLayoutEffect(() => {
|
|
7942
8184
|
if (!containerRef.current) return;
|
|
7943
8185
|
const next = resolveLabelRoles(createCssVariableResolver(containerRef.current));
|
|
@@ -7951,13 +8193,56 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7951
8193
|
const extent = (0, react.useMemo)(() => getValueExtent(data), [data]);
|
|
7952
8194
|
const heatmapContext = (0, react.useMemo)(() => ({
|
|
7953
8195
|
extent,
|
|
7954
|
-
|
|
7955
|
-
}), [extent,
|
|
8196
|
+
fillVars
|
|
8197
|
+
}), [extent, fillVars]);
|
|
7956
8198
|
const columns = data.length;
|
|
7957
8199
|
const rows = Math.max(0, ...data.map((column) => column.data.length));
|
|
7958
8200
|
const groupLayout = (0, react.useMemo)(() => resolveColumnGroups(columnGroups, columns, 2), [columnGroups, columns]);
|
|
7959
8201
|
const { compactCellGap, compactCellSize, groupGap } = heatmapChartSettings;
|
|
7960
8202
|
const drawValues = showValues ?? !compact;
|
|
8203
|
+
const hasColumnLabels = data.some((column) => Boolean(column.label));
|
|
8204
|
+
const hasGroups = groupLayout.groups.length > 0;
|
|
8205
|
+
const [fit, setFit] = (0, react.useState)(null);
|
|
8206
|
+
const hasSummary = data.some((column) => column.summary);
|
|
8207
|
+
const fitting = compact && fitCells && !hasSummary;
|
|
8208
|
+
if (fitCells && !fitting) warnOnce("heatmap:fitCells", "fitCells applies only in compact mode without summary columns, so the cells keep their size.");
|
|
8209
|
+
useIsomorphicLayoutEffect(() => {
|
|
8210
|
+
const chart = chartRef.current;
|
|
8211
|
+
const grid = containerRef.current;
|
|
8212
|
+
if (!fitting || !chart || !grid) {
|
|
8213
|
+
setFit(null);
|
|
8214
|
+
return;
|
|
8215
|
+
}
|
|
8216
|
+
const measure = () => {
|
|
8217
|
+
const next = fitCompactCells({
|
|
8218
|
+
...gridBox(chart, grid),
|
|
8219
|
+
layout: groupLayout,
|
|
8220
|
+
rows,
|
|
8221
|
+
cellGap: compactCellGap,
|
|
8222
|
+
groupGap,
|
|
8223
|
+
rowLabelWidth: largest(grid, `.${heatmap_chart_module_default["heatmap-chart__row-label"]}`, "offsetWidth"),
|
|
8224
|
+
columnLabelHeight: hasColumnLabels ? largest(grid, `.${heatmap_chart_module_default["heatmap-chart__col-label"]}`, "offsetHeight") : null,
|
|
8225
|
+
groupLabelHeight: hasGroups ? largest(grid, `.${heatmap_chart_module_default["heatmap-chart__group-label"]}`, "offsetHeight") : null,
|
|
8226
|
+
minCellSize: compactCellSize
|
|
8227
|
+
});
|
|
8228
|
+
setFit((previous) => (0, import_fast_deep_equal.default)(previous, next) ? previous : next);
|
|
8229
|
+
};
|
|
8230
|
+
measure();
|
|
8231
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
8232
|
+
const observer = new ResizeObserver(() => (0, react_dom.flushSync)(measure));
|
|
8233
|
+
observer.observe(chart);
|
|
8234
|
+
return () => observer.disconnect();
|
|
8235
|
+
}, [
|
|
8236
|
+
fitting,
|
|
8237
|
+
groupLayout,
|
|
8238
|
+
rows,
|
|
8239
|
+
hasColumnLabels,
|
|
8240
|
+
hasGroups,
|
|
8241
|
+
compactCellGap,
|
|
8242
|
+
compactCellSize,
|
|
8243
|
+
groupGap
|
|
8244
|
+
]);
|
|
8245
|
+
const wrapped = (0, react.useMemo)(() => fit ? wrapColumnGroups(groupLayout, fit.bands) : null, [fit, groupLayout]);
|
|
7961
8246
|
const buildTooltipData = (0, react.useCallback)((columnIndex, rowIndex) => {
|
|
7962
8247
|
const cell = data[columnIndex]?.data[rowIndex];
|
|
7963
8248
|
const group = groupLayout.columns[columnIndex]?.group;
|
|
@@ -8097,20 +8382,25 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8097
8382
|
});
|
|
8098
8383
|
const columnTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellWidth ?? 0}px, ${maxCellWidth ? `${maxCellWidth}px` : "1fr"})`;
|
|
8099
8384
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
8100
|
-
const
|
|
8101
|
-
const
|
|
8102
|
-
const
|
|
8103
|
-
const
|
|
8385
|
+
const placed = wrapped ?? groupLayout;
|
|
8386
|
+
const columnLine = (columnIndex) => placed.columns[columnIndex].line;
|
|
8387
|
+
const bandOf = (columnIndex) => placed.columns[columnIndex].band;
|
|
8388
|
+
const { bands } = placed;
|
|
8389
|
+
const bandRowCount = (hasColumnLabels ? 1 : 0) + rows + (hasGroups ? 1 : 0) + 1;
|
|
8390
|
+
const labelRowOf = (band) => 1 + band * bandRowCount;
|
|
8391
|
+
const dataRowOf = (band, rowIndex) => labelRowOf(band) + (hasColumnLabels ? 1 : 0) + rowIndex;
|
|
8104
8392
|
const dataTrack = (column) => column.summary ? "minmax(auto, max-content)" : columnTrack;
|
|
8105
8393
|
const gapTrack = compact ? `minmax(${groupGap}px, 1fr)` : `${groupGap}px`;
|
|
8394
|
+
const columnTracks = wrapped ? wrapped.slotSpans.map((span, slot) => [...slot > 0 ? [gapTrack] : [], ...Array(span).fill(columnTrack)].join(" ")).join(" ") : data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ");
|
|
8395
|
+
const bandTracks = `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`;
|
|
8106
8396
|
const gridStyle = {
|
|
8107
|
-
|
|
8108
|
-
gridTemplateColumns: `auto ${
|
|
8109
|
-
gridTemplateRows:
|
|
8397
|
+
...fillVars,
|
|
8398
|
+
gridTemplateColumns: `auto ${columnTracks}`,
|
|
8399
|
+
gridTemplateRows: Array(bands).fill(bandTracks).join(` ${groupGap}px `)
|
|
8110
8400
|
};
|
|
8111
8401
|
if (compact) {
|
|
8112
8402
|
gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
|
|
8113
|
-
gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${compactCellSize}px`;
|
|
8403
|
+
gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${fit?.cellSize ?? compactCellSize}px`;
|
|
8114
8404
|
}
|
|
8115
8405
|
const summaryGaps = (columnIndex) => {
|
|
8116
8406
|
if (!data[columnIndex]?.summary) return {};
|
|
@@ -8130,6 +8420,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8130
8420
|
legendChildren: [],
|
|
8131
8421
|
trailingContent: nonLegendChildren,
|
|
8132
8422
|
gap,
|
|
8423
|
+
rootRef: chartRef,
|
|
8133
8424
|
className: (0, clsx.default)("heatmap-chart", heatmap_chart_module_default["heatmap-chart"], className, { [heatmap_chart_module_default["heatmap-chart--height-capped"]]: heightCapped }),
|
|
8134
8425
|
style: {
|
|
8135
8426
|
width: width || void 0,
|
|
@@ -8159,11 +8450,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8159
8450
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
8160
8451
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
|
|
8161
8452
|
gridColumn: 1,
|
|
8162
|
-
gridRow:
|
|
8453
|
+
gridRow: labelRowOf(0)
|
|
8163
8454
|
} }), data.map((column, columnIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8164
8455
|
style: {
|
|
8165
8456
|
gridColumn: columnLine(columnIndex),
|
|
8166
|
-
gridRow:
|
|
8457
|
+
gridRow: labelRowOf(bandOf(columnIndex))
|
|
8167
8458
|
},
|
|
8168
8459
|
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
8169
8460
|
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
@@ -8174,24 +8465,23 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8174
8465
|
}),
|
|
8175
8466
|
Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
8176
8467
|
const labelVisible = !compact || rowIndex % 2 === 0;
|
|
8177
|
-
const gridRow = firstDataRow + rowIndex;
|
|
8178
8468
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8179
8469
|
role: "row",
|
|
8180
8470
|
"aria-rowindex": rowIndex + 1,
|
|
8181
8471
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
8182
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8472
|
+
children: [Array.from({ length: bands }).map((_band, band) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8183
8473
|
"aria-hidden": "true",
|
|
8184
8474
|
className: heatmap_chart_module_default["heatmap-chart__row-label"],
|
|
8185
8475
|
style: {
|
|
8186
8476
|
gridColumn: 1,
|
|
8187
|
-
gridRow
|
|
8477
|
+
gridRow: dataRowOf(band, rowIndex)
|
|
8188
8478
|
},
|
|
8189
8479
|
children: labelVisible ? rowLabels[rowIndex] ?? "" : ""
|
|
8190
|
-
}), data.map((column, columnIndex) => {
|
|
8480
|
+
}, `row-label-${band}`)), data.map((column, columnIndex) => {
|
|
8191
8481
|
const cell = column.data[rowIndex];
|
|
8192
8482
|
const placement = {
|
|
8193
8483
|
gridColumn: columnLine(columnIndex),
|
|
8194
|
-
gridRow
|
|
8484
|
+
gridRow: dataRowOf(bandOf(columnIndex), rowIndex)
|
|
8195
8485
|
};
|
|
8196
8486
|
if (cell?.hidden) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8197
8487
|
"aria-hidden": "true",
|
|
@@ -8205,7 +8495,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8205
8495
|
}, `cell-${columnIndex}-${rowIndex}`);
|
|
8206
8496
|
const value = cell?.value ?? null;
|
|
8207
8497
|
const present = isPresent(value);
|
|
8208
|
-
const filled = present && !column.summary;
|
|
8498
|
+
const filled = present && !column.summary && !isEmptyValue(value, extent);
|
|
8209
8499
|
const normalized = filled ? getNormalizedValue(value, extent) : 0;
|
|
8210
8500
|
const info = buildTooltipData(columnIndex, rowIndex);
|
|
8211
8501
|
const accessibleLabel = `${cellName(info)}: ${info.value === null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(info.value)}`;
|
|
@@ -8241,11 +8531,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8241
8531
|
role: "row",
|
|
8242
8532
|
"aria-hidden": "true",
|
|
8243
8533
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
8244
|
-
children:
|
|
8534
|
+
children: placed.groups.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8245
8535
|
className: heatmap_chart_module_default["heatmap-chart__group-label"],
|
|
8246
8536
|
style: {
|
|
8247
8537
|
gridColumn: `${group.line} / span ${group.span}`,
|
|
8248
|
-
gridRow:
|
|
8538
|
+
gridRow: dataRowOf(group.band, rows)
|
|
8249
8539
|
},
|
|
8250
8540
|
children: group.label
|
|
8251
8541
|
}, `group-${groupIndex}`))
|
|
@@ -11480,6 +11770,7 @@ var leaderboard_chart_module_default = {
|
|
|
11480
11770
|
"interactiveRow": "a8ccharts-GovfoW-interactiveRow",
|
|
11481
11771
|
"is-overlay": "a8ccharts-GovfoW-is-overlay",
|
|
11482
11772
|
"label": "a8ccharts-GovfoW-label",
|
|
11773
|
+
"layeredRow": "a8ccharts-GovfoW-layeredRow",
|
|
11483
11774
|
"leaderboardChart": "a8ccharts-GovfoW-leaderboardChart",
|
|
11484
11775
|
"leaderboardChart__content": "a8ccharts-GovfoW-leaderboardChart__content",
|
|
11485
11776
|
"leaderboardChart__content--fit": "a8ccharts-GovfoW-leaderboardChart__content--fit",
|
|
@@ -11488,6 +11779,7 @@ var leaderboard_chart_module_default = {
|
|
|
11488
11779
|
"overlap": "a8ccharts-GovfoW-overlap",
|
|
11489
11780
|
"overlayLabel": "a8ccharts-GovfoW-overlayLabel",
|
|
11490
11781
|
"row": "a8ccharts-GovfoW-row",
|
|
11782
|
+
"rowButton": "a8ccharts-GovfoW-rowButton",
|
|
11491
11783
|
"stretch": "a8ccharts-GovfoW-stretch",
|
|
11492
11784
|
"valueContainer": "a8ccharts-GovfoW-valueContainer"
|
|
11493
11785
|
};
|
|
@@ -11538,6 +11830,16 @@ const defaultDeltaFormatter = (value) => {
|
|
|
11538
11830
|
const getBarWidth = (share) => `calc(${share}% - var(--a8c-charts-dimension-leaderboard-bar-hover-inset, 0px) * ${share} / 100)`;
|
|
11539
11831
|
const hasPreviousValue = (entry) => entry.previousValue != null && entry.previousShare != null;
|
|
11540
11832
|
const hasDeltaValue = (entry) => hasPreviousValue(entry) && entry.delta != null;
|
|
11833
|
+
/**
|
|
11834
|
+
* A layered row's cell that takes pointer events of its own (a value tooltip)
|
|
11835
|
+
* sits above the row button; pass its clicks on so they still drill down.
|
|
11836
|
+
*
|
|
11837
|
+
* @param event - The click on the row.
|
|
11838
|
+
*/
|
|
11839
|
+
function forwardCellClickToRowButton(event) {
|
|
11840
|
+
if (event.target.closest("a, button")) return;
|
|
11841
|
+
event.currentTarget.querySelector(":scope > button")?.click();
|
|
11842
|
+
}
|
|
11541
11843
|
const BarLabel = ({ label }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: typeof label === "string" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
11542
11844
|
className: leaderboard_chart_module_default.label,
|
|
11543
11845
|
children: label
|
|
@@ -11770,6 +12072,26 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
11770
12072
|
})
|
|
11771
12073
|
]
|
|
11772
12074
|
})] });
|
|
12075
|
+
if (entry.onClick && entry.hasInteractiveLabel) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12076
|
+
"data-row-index": rowIndex,
|
|
12077
|
+
style: rowStyle,
|
|
12078
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow, leaderboard_chart_module_default.layeredRow),
|
|
12079
|
+
onClick: forwardCellClickToRowButton,
|
|
12080
|
+
children: [
|
|
12081
|
+
rowCells,
|
|
12082
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
12083
|
+
type: "button",
|
|
12084
|
+
className: leaderboard_chart_module_default.rowButton,
|
|
12085
|
+
onClick: entry.onClick,
|
|
12086
|
+
"aria-label": entry.ariaLabel
|
|
12087
|
+
}),
|
|
12088
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_icons.Icon, {
|
|
12089
|
+
className: leaderboard_chart_module_default.chevron,
|
|
12090
|
+
icon: _wordpress_icons.chevronRight,
|
|
12091
|
+
size: 24
|
|
12092
|
+
})
|
|
12093
|
+
]
|
|
12094
|
+
}, entry.id);
|
|
11773
12095
|
if (entry.onClick) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11774
12096
|
type: "button",
|
|
11775
12097
|
"data-row-index": rowIndex,
|
|
@@ -11803,6 +12125,210 @@ LeaderboardChartWithProvider.displayName = "LeaderboardChart";
|
|
|
11803
12125
|
const LeaderboardChart = attachSubComponents(LeaderboardChartWithProvider, { Legend });
|
|
11804
12126
|
const LeaderboardChartResponsive = attachSubComponents(withResponsive(LeaderboardChartWithProvider), { Legend });
|
|
11805
12127
|
//#endregion
|
|
12128
|
+
//#region src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts
|
|
12129
|
+
/**
|
|
12130
|
+
* Orders arcs the way they appear: clockwise from 12 o'clock, which for a semi-circle is left to right.
|
|
12131
|
+
*
|
|
12132
|
+
* @param arcs - Arcs from visx's `pie` factory, in data order.
|
|
12133
|
+
* @return A copy of `arcs` sorted by angular midpoint.
|
|
12134
|
+
*/
|
|
12135
|
+
const orderArcsForNavigation = (arcs) => [...arcs].sort((a, b) => a.startAngle + a.endAngle - (b.startAngle + b.endAngle));
|
|
12136
|
+
//#endregion
|
|
12137
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx
|
|
12138
|
+
const PieSelectionAnnouncement = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.VisuallyHidden, {
|
|
12139
|
+
role: "status",
|
|
12140
|
+
"aria-atomic": "true",
|
|
12141
|
+
children: data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data })
|
|
12142
|
+
});
|
|
12143
|
+
//#endregion
|
|
12144
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx
|
|
12145
|
+
const PieTooltip = ({ top, left, selectedIndex, tooltipRef, children }) => {
|
|
12146
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
12147
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
12148
|
+
top,
|
|
12149
|
+
left,
|
|
12150
|
+
children: selectedIndex === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12151
|
+
className: standaloneScopeClass,
|
|
12152
|
+
role: "tooltip",
|
|
12153
|
+
children
|
|
12154
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12155
|
+
ref: tooltipRef,
|
|
12156
|
+
tabIndex: -1,
|
|
12157
|
+
role: "tooltip",
|
|
12158
|
+
"aria-atomic": "true",
|
|
12159
|
+
className: standaloneScopeClass,
|
|
12160
|
+
children
|
|
12161
|
+
}, `chart-tooltip-${selectedIndex}`)
|
|
12162
|
+
});
|
|
12163
|
+
};
|
|
12164
|
+
//#endregion
|
|
12165
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx
|
|
12166
|
+
/**
|
|
12167
|
+
* Reports the selected segment: a focused tooltip for a keyboard selection, a pointer tooltip on hover, or a screen reader announcement without tooltips.
|
|
12168
|
+
*
|
|
12169
|
+
* @param {PieSelectionOutputProps} props - Component props
|
|
12170
|
+
* @return {JSX.Element} The announcement region and the tooltip, if any
|
|
12171
|
+
*/
|
|
12172
|
+
const PieSelectionOutput = ({ withTooltips, selectedIndex, selectedData, keyboardTooltipAnchor, pointerTooltip, chartRef, svgRef, tooltipRef, renderTooltip }) => {
|
|
12173
|
+
const [svgOffset, setSvgOffset] = (0, react.useState)({
|
|
12174
|
+
top: 0,
|
|
12175
|
+
left: 0
|
|
12176
|
+
});
|
|
12177
|
+
const showKeyboardTooltip = withTooltips && selectedData && keyboardTooltipAnchor;
|
|
12178
|
+
(0, react.useLayoutEffect)(() => {
|
|
12179
|
+
const chartBounds = chartRef.current?.getBoundingClientRect();
|
|
12180
|
+
const svgBounds = svgRef.current?.getBoundingClientRect();
|
|
12181
|
+
if (!showKeyboardTooltip || !chartBounds || !svgBounds) return;
|
|
12182
|
+
const top = svgBounds.top - chartBounds.top;
|
|
12183
|
+
const left = svgBounds.left - chartBounds.left;
|
|
12184
|
+
setSvgOffset((current) => current.top === top && current.left === left ? current : {
|
|
12185
|
+
top,
|
|
12186
|
+
left
|
|
12187
|
+
});
|
|
12188
|
+
});
|
|
12189
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
12190
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionAnnouncement, { data: withTooltips ? void 0 : selectedData }),
|
|
12191
|
+
showKeyboardTooltip && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieTooltip, {
|
|
12192
|
+
top: svgOffset.top + keyboardTooltipAnchor.top,
|
|
12193
|
+
left: svgOffset.left + keyboardTooltipAnchor.left,
|
|
12194
|
+
selectedIndex,
|
|
12195
|
+
tooltipRef,
|
|
12196
|
+
children: renderTooltip({ tooltipData: selectedData })
|
|
12197
|
+
}),
|
|
12198
|
+
withTooltips && !selectedData && pointerTooltip?.data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieTooltip, {
|
|
12199
|
+
top: pointerTooltip.top,
|
|
12200
|
+
left: pointerTooltip.left,
|
|
12201
|
+
children: renderTooltip({ tooltipData: pointerTooltip.data })
|
|
12202
|
+
})
|
|
12203
|
+
] });
|
|
12204
|
+
};
|
|
12205
|
+
//#endregion
|
|
12206
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss
|
|
12207
|
+
var pie_keyboard_navigation_module_default = {
|
|
12208
|
+
"selected-ring__contrast": "a8ccharts-V2HDKq-selected-ring__contrast",
|
|
12209
|
+
"selected-ring__focus": "a8ccharts-V2HDKq-selected-ring__focus"
|
|
12210
|
+
};
|
|
12211
|
+
//#endregion
|
|
12212
|
+
//#region src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx
|
|
12213
|
+
/**
|
|
12214
|
+
* Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
|
|
12215
|
+
*
|
|
12216
|
+
* @param value - Any string.
|
|
12217
|
+
* @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
|
|
12218
|
+
*/
|
|
12219
|
+
const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
|
|
12220
|
+
/**
|
|
12221
|
+
* Marks the selected segment with a two-tone ring drawn inside its edge, so the SVG edge cannot cut it off.
|
|
12222
|
+
*
|
|
12223
|
+
* @param {SelectedSegmentRingProps} props - Component props
|
|
12224
|
+
* @return {JSX.Element} The ring
|
|
12225
|
+
*/
|
|
12226
|
+
const SelectedSegmentRing = ({ chartId, d }) => {
|
|
12227
|
+
const clipId = `pie-selected-ring-clip-${toSvgId(chartId)}`;
|
|
12228
|
+
const clipPath = `url(#${clipId})`;
|
|
12229
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
12230
|
+
pointerEvents: "none",
|
|
12231
|
+
"aria-hidden": "true",
|
|
12232
|
+
children: [
|
|
12233
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("clipPath", {
|
|
12234
|
+
id: clipId,
|
|
12235
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d })
|
|
12236
|
+
}),
|
|
12237
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12238
|
+
d,
|
|
12239
|
+
clipPath,
|
|
12240
|
+
className: pie_keyboard_navigation_module_default["selected-ring__contrast"]
|
|
12241
|
+
}),
|
|
12242
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12243
|
+
d,
|
|
12244
|
+
clipPath,
|
|
12245
|
+
className: pie_keyboard_navigation_module_default["selected-ring__focus"]
|
|
12246
|
+
})
|
|
12247
|
+
]
|
|
12248
|
+
});
|
|
12249
|
+
};
|
|
12250
|
+
//#endregion
|
|
12251
|
+
//#region src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts
|
|
12252
|
+
const usePieKeyboardNavigation = ({ navigationArcs, withTooltips, tooltipOffsetX, tooltipOffsetY }) => {
|
|
12253
|
+
const chartRef = (0, react.useRef)(null);
|
|
12254
|
+
const svgRef = (0, react.useRef)(null);
|
|
12255
|
+
const [selectedIndex, setSelectedIndex] = (0, react.useState)(void 0);
|
|
12256
|
+
const [isNavigating, setIsNavigating] = (0, react.useState)(false);
|
|
12257
|
+
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
12258
|
+
const { tooltipRef: focusTooltip, onChartFocus, onChartBlur, onChartKeyDown, onChartPointerMove } = useKeyboardNavigation({
|
|
12259
|
+
selectedIndex,
|
|
12260
|
+
setSelectedIndex,
|
|
12261
|
+
isNavigating,
|
|
12262
|
+
setIsNavigating,
|
|
12263
|
+
chartRef,
|
|
12264
|
+
totalPoints: navigationArcs.length,
|
|
12265
|
+
visibleSeriesKey: JSON.stringify(navigationArcs.map((arcDatum) => arcDatum.data.label))
|
|
12266
|
+
});
|
|
12267
|
+
const selectedArc = selectedIndex === void 0 ? void 0 : navigationArcs[selectedIndex];
|
|
12268
|
+
const keyboardTooltip = (0, react.useRef)(null);
|
|
12269
|
+
const tooltipLostFocus = (0, react.useRef)(false);
|
|
12270
|
+
const tooltipRef = (0, react.useCallback)((element) => {
|
|
12271
|
+
if (element) {
|
|
12272
|
+
keyboardTooltip.current = element;
|
|
12273
|
+
focusTooltip(element);
|
|
12274
|
+
} else if (keyboardTooltip.current?.ownerDocument.activeElement === keyboardTooltip.current) tooltipLostFocus.current = true;
|
|
12275
|
+
}, [focusTooltip]);
|
|
12276
|
+
(0, react.useLayoutEffect)(() => {
|
|
12277
|
+
if (!tooltipLostFocus.current) return;
|
|
12278
|
+
tooltipLostFocus.current = false;
|
|
12279
|
+
const { activeElement, body } = chartRef.current?.ownerDocument ?? document;
|
|
12280
|
+
if (activeElement === null || activeElement === body) chartRef.current?.focus();
|
|
12281
|
+
});
|
|
12282
|
+
const getSegmentHandlers = (data, navigationIndex) => ({
|
|
12283
|
+
onMouseMove: (event) => {
|
|
12284
|
+
onChartPointerMove(navigationIndex);
|
|
12285
|
+
if (!withTooltips) return;
|
|
12286
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
12287
|
+
if (!bounds) return;
|
|
12288
|
+
showTooltip({
|
|
12289
|
+
tooltipData: data,
|
|
12290
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
12291
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
12292
|
+
});
|
|
12293
|
+
},
|
|
12294
|
+
onMouseLeave: withTooltips ? hideTooltip : void 0
|
|
12295
|
+
});
|
|
12296
|
+
return {
|
|
12297
|
+
chartRef,
|
|
12298
|
+
svgRef,
|
|
12299
|
+
selectedArc,
|
|
12300
|
+
getSegmentHandlers,
|
|
12301
|
+
getKeyboardTooltipAnchor: (0, react.useCallback)((originX, originY, [x, y]) => withTooltips ? {
|
|
12302
|
+
left: originX + x + tooltipOffsetX,
|
|
12303
|
+
top: originY + y + tooltipOffsetY
|
|
12304
|
+
} : void 0, [
|
|
12305
|
+
withTooltips,
|
|
12306
|
+
tooltipOffsetX,
|
|
12307
|
+
tooltipOffsetY
|
|
12308
|
+
]),
|
|
12309
|
+
selectionOutputProps: {
|
|
12310
|
+
withTooltips,
|
|
12311
|
+
selectedIndex,
|
|
12312
|
+
selectedData: selectedArc?.data,
|
|
12313
|
+
chartRef,
|
|
12314
|
+
svgRef,
|
|
12315
|
+
tooltipRef,
|
|
12316
|
+
pointerTooltip: tooltipOpen ? {
|
|
12317
|
+
data: tooltipData,
|
|
12318
|
+
left: tooltipLeft || 0,
|
|
12319
|
+
top: tooltipTop || 0
|
|
12320
|
+
} : void 0
|
|
12321
|
+
},
|
|
12322
|
+
chartProps: {
|
|
12323
|
+
role: "application",
|
|
12324
|
+
tabIndex: 0,
|
|
12325
|
+
onKeyDown: onChartKeyDown,
|
|
12326
|
+
onFocus: onChartFocus,
|
|
12327
|
+
onBlur: onChartBlur
|
|
12328
|
+
}
|
|
12329
|
+
};
|
|
12330
|
+
};
|
|
12331
|
+
//#endregion
|
|
11806
12332
|
//#region src/charts/private/radial-wipe-animation/radial-wipe-animation.tsx
|
|
11807
12333
|
/**
|
|
11808
12334
|
* Renders a SVG mask that creates a radial wipe animation effect.
|
|
@@ -11855,18 +12381,13 @@ var pie_chart_module_default = {
|
|
|
11855
12381
|
//#region src/charts/pie-chart/pie-chart.tsx
|
|
11856
12382
|
/**
|
|
11857
12383
|
* Default tooltip renderer for pie charts.
|
|
11858
|
-
* Renders
|
|
12384
|
+
* Renders the default `label: value` tooltip content for the hovered segment.
|
|
11859
12385
|
*
|
|
11860
12386
|
* @param {PieChartRenderTooltipParams} params - The tooltip parameters containing the hovered data point
|
|
11861
12387
|
* @return {ReactNode} The rendered tooltip content
|
|
11862
12388
|
*/
|
|
11863
12389
|
const renderDefaultPieTooltip = ({ tooltipData }) => {
|
|
11864
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
11865
|
-
data: tooltipData,
|
|
11866
|
-
top: 0,
|
|
11867
|
-
left: 0,
|
|
11868
|
-
renderContainer: false
|
|
11869
|
-
});
|
|
12390
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data: tooltipData });
|
|
11870
12391
|
};
|
|
11871
12392
|
/**
|
|
11872
12393
|
* Validates the pie chart data
|
|
@@ -11903,20 +12424,13 @@ const LABEL_TEXT_MODIFIER = {
|
|
|
11903
12424
|
* @param {PieChartProps} props - Component props
|
|
11904
12425
|
* @return {JSX.Element} The rendered chart component
|
|
11905
12426
|
*/
|
|
11906
|
-
const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legend = {}, width: propWidth, height: propHeight, size, animation, thickness = 1, padding = 0, gapScale = 0, cornerScale = 0, showLabels = true, legendValueDisplay = "percentage", children = null, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieTooltip, gap = "md" }) => {
|
|
12427
|
+
const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false, className, showLegend = false, legend = {}, width: propWidth, height: propHeight, size, animation, thickness = 1, padding = 0, gapScale = 0, cornerScale = 0, showLabels = true, legendValueDisplay = "percentage", children = null, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieTooltip, ariaLabel, gap = "md" }) => {
|
|
11907
12428
|
const legendInteractive = legend.interactive ?? false;
|
|
11908
12429
|
const legendPosition = legend.position ?? "bottom";
|
|
11909
12430
|
const providerTheme = useGlobalChartsTheme();
|
|
11910
12431
|
const chartId = useChartId(providedChartId);
|
|
11911
|
-
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
11912
|
-
const standaloneScopeClass = useStandaloneScopeClass();
|
|
11913
|
-
const containerRef = (0, react.useRef)(null);
|
|
11914
12432
|
const rootRef = (0, react.useRef)(null);
|
|
11915
12433
|
const [labelRoles, setLabelRoles] = (0, react.useState)(null);
|
|
11916
|
-
const onMouseLeave = (0, react.useCallback)(() => {
|
|
11917
|
-
if (!withTooltips) return;
|
|
11918
|
-
hideTooltip();
|
|
11919
|
-
}, [withTooltips, hideTooltip]);
|
|
11920
12434
|
const { getElementStyles, isSeriesVisible, isColorPaletteResolved } = useGlobalChartsContext();
|
|
11921
12435
|
const { isValid, message } = validateData$1(data);
|
|
11922
12436
|
(0, react.useLayoutEffect)(() => {
|
|
@@ -11960,13 +12474,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
11960
12474
|
metadata: chartMetadata
|
|
11961
12475
|
});
|
|
11962
12476
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
11963
|
-
|
|
11964
|
-
className: (0, clsx.default)("pie-chart", pie_chart_module_default["pie-chart"], className),
|
|
11965
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11966
|
-
className: pie_chart_module_default["error-message"],
|
|
11967
|
-
children: message
|
|
11968
|
-
})
|
|
11969
|
-
});
|
|
12477
|
+
const wipeMask = animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null;
|
|
11970
12478
|
const padAngle = gapScale * (2 * Math.PI / data.length);
|
|
11971
12479
|
const dataWithIndex = visibleData.map((d) => {
|
|
11972
12480
|
const originalIndex = data.findIndex((item) => item.label === d.label);
|
|
@@ -11984,6 +12492,24 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
11984
12492
|
}).color;
|
|
11985
12493
|
}
|
|
11986
12494
|
};
|
|
12495
|
+
const arcs = (0, _visx_shape.pie)({
|
|
12496
|
+
value: accessors.value,
|
|
12497
|
+
padAngle
|
|
12498
|
+
})(dataWithIndex);
|
|
12499
|
+
const navigationArcs = orderArcsForNavigation(arcs);
|
|
12500
|
+
const { chartRef, svgRef, selectedArc, getSegmentHandlers, getKeyboardTooltipAnchor, selectionOutputProps, chartProps } = usePieKeyboardNavigation({
|
|
12501
|
+
navigationArcs,
|
|
12502
|
+
withTooltips,
|
|
12503
|
+
tooltipOffsetX,
|
|
12504
|
+
tooltipOffsetY
|
|
12505
|
+
});
|
|
12506
|
+
if (!isValid) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12507
|
+
className: (0, clsx.default)("pie-chart", pie_chart_module_default["pie-chart"], className),
|
|
12508
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12509
|
+
className: pie_chart_module_default["error-message"],
|
|
12510
|
+
children: message
|
|
12511
|
+
})
|
|
12512
|
+
});
|
|
11987
12513
|
const legendElement = showLegend && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
|
|
11988
12514
|
orientation: legend.orientation ?? "horizontal",
|
|
11989
12515
|
position: legendPosition,
|
|
@@ -12022,102 +12548,96 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
12022
12548
|
const innerRadius = thickness === 0 ? 0 : outerRadius * (1 - thickness);
|
|
12023
12549
|
const maxCornerRadius = (outerRadius - innerRadius) / 2;
|
|
12024
12550
|
const cornerRadius = cornerScale ? Math.min(cornerScale * outerRadius, maxCornerRadius) : 0;
|
|
12551
|
+
const path = (0, _visx_shape.arc)({
|
|
12552
|
+
innerRadius,
|
|
12553
|
+
outerRadius,
|
|
12554
|
+
cornerRadius
|
|
12555
|
+
});
|
|
12556
|
+
const svgLabelSmall = providerTheme.svgLabelSmall;
|
|
12557
|
+
const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
|
|
12558
|
+
const renderLabel = (arcDatum, index) => {
|
|
12559
|
+
if (arcDatum.endAngle - arcDatum.startAngle < .25) return null;
|
|
12560
|
+
const [centroidX, centroidY] = path.centroid(arcDatum);
|
|
12561
|
+
const backgroundWidth = (0, _visx_text.getStringWidth)(arcDatum.data.label, {
|
|
12562
|
+
fontSize,
|
|
12563
|
+
fontFamily: svgLabelSmall?.fontFamily,
|
|
12564
|
+
fontWeight: svgLabelSmall?.fontWeight
|
|
12565
|
+
}) + 12;
|
|
12566
|
+
const backgroundHeight = fontSize + 12;
|
|
12567
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
12568
|
+
className: pie_chart_module_default["pie-chart__label-plate"],
|
|
12569
|
+
x: centroidX - backgroundWidth / 2,
|
|
12570
|
+
y: centroidY - backgroundHeight / 2,
|
|
12571
|
+
width: backgroundWidth,
|
|
12572
|
+
height: backgroundHeight,
|
|
12573
|
+
rx: 4,
|
|
12574
|
+
ry: 4,
|
|
12575
|
+
pointerEvents: "none"
|
|
12576
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
12577
|
+
className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"], LABEL_TEXT_MODIFIER[pickLabelTextColor(accessors.fill(arcDatum.data), labelRoles, "label-inverse")]),
|
|
12578
|
+
x: centroidX,
|
|
12579
|
+
y: centroidY,
|
|
12580
|
+
dy: ".33em",
|
|
12581
|
+
fontSize,
|
|
12582
|
+
textAnchor: "middle",
|
|
12583
|
+
pointerEvents: "none",
|
|
12584
|
+
children: arcDatum.data.label
|
|
12585
|
+
})] }, `label-${index}`);
|
|
12586
|
+
};
|
|
12025
12587
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
12026
|
-
ref:
|
|
12588
|
+
ref: chartRef,
|
|
12027
12589
|
className: pie_chart_module_default["pie-chart__plot"],
|
|
12590
|
+
...chartProps,
|
|
12591
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Pie chart", "jetpack-charts"),
|
|
12028
12592
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
12593
|
+
ref: svgRef,
|
|
12029
12594
|
viewBox: `0 0 ${width} ${height}`,
|
|
12030
12595
|
preserveAspectRatio: "xMidYMid meet",
|
|
12031
12596
|
width,
|
|
12032
12597
|
height,
|
|
12033
|
-
children: [
|
|
12034
|
-
|
|
12035
|
-
|
|
12036
|
-
|
|
12037
|
-
|
|
12038
|
-
|
|
12039
|
-
|
|
12040
|
-
|
|
12041
|
-
|
|
12042
|
-
|
|
12043
|
-
|
|
12044
|
-
|
|
12045
|
-
|
|
12046
|
-
|
|
12047
|
-
|
|
12048
|
-
|
|
12049
|
-
|
|
12050
|
-
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
|
|
12060
|
-
|
|
12061
|
-
|
|
12062
|
-
|
|
12063
|
-
|
|
12064
|
-
|
|
12065
|
-
|
|
12066
|
-
|
|
12067
|
-
|
|
12068
|
-
|
|
12069
|
-
|
|
12070
|
-
|
|
12071
|
-
|
|
12072
|
-
|
|
12073
|
-
|
|
12074
|
-
|
|
12075
|
-
|
|
12076
|
-
groupProps.onMouseMove = handleMouseMove;
|
|
12077
|
-
groupProps.onMouseLeave = onMouseLeave;
|
|
12078
|
-
}
|
|
12079
|
-
const svgLabelSmall = providerTheme.svgLabelSmall;
|
|
12080
|
-
const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
|
|
12081
|
-
const backgroundWidth = (0, _visx_text.getStringWidth)(arc.data.label, {
|
|
12082
|
-
fontSize,
|
|
12083
|
-
fontFamily: svgLabelSmall?.fontFamily,
|
|
12084
|
-
fontWeight: svgLabelSmall?.fontWeight
|
|
12085
|
-
}) + 12;
|
|
12086
|
-
const backgroundHeight = fontSize + 12;
|
|
12087
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
12088
|
-
...groupProps,
|
|
12089
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
12090
|
-
className: pie_chart_module_default["pie-chart__label-plate"],
|
|
12091
|
-
x: centroidX - backgroundWidth / 2,
|
|
12092
|
-
y: centroidY - backgroundHeight / 2,
|
|
12093
|
-
width: backgroundWidth,
|
|
12094
|
-
height: backgroundHeight,
|
|
12095
|
-
rx: 4,
|
|
12096
|
-
ry: 4,
|
|
12097
|
-
pointerEvents: "none"
|
|
12098
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
12099
|
-
className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"], LABEL_TEXT_MODIFIER[pickLabelTextColor(fill, labelRoles, "label-inverse")]),
|
|
12100
|
-
x: centroidX,
|
|
12101
|
-
y: centroidY,
|
|
12102
|
-
dy: ".33em",
|
|
12103
|
-
fontSize,
|
|
12104
|
-
textAnchor: "middle",
|
|
12105
|
-
pointerEvents: "none",
|
|
12106
|
-
children: arc.data.label
|
|
12107
|
-
})] })]
|
|
12108
|
-
}, `arc-${index}`);
|
|
12109
|
-
});
|
|
12110
|
-
}
|
|
12111
|
-
}), !allSegmentsHidden && svgChildren]
|
|
12112
|
-
})]
|
|
12113
|
-
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
12114
|
-
top: tooltipTop || 0,
|
|
12115
|
-
left: tooltipLeft || 0,
|
|
12116
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12117
|
-
className: standaloneScopeClass,
|
|
12118
|
-
role: "tooltip",
|
|
12119
|
-
children: renderTooltip({ tooltipData })
|
|
12120
|
-
})
|
|
12598
|
+
children: [
|
|
12599
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
|
|
12600
|
+
id: `radial-wipe-${chartId}`,
|
|
12601
|
+
radius: outerRadius,
|
|
12602
|
+
innerRadius
|
|
12603
|
+
}) }),
|
|
12604
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12605
|
+
top: centerY,
|
|
12606
|
+
left: centerX,
|
|
12607
|
+
mask: wipeMask,
|
|
12608
|
+
children: allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
|
|
12609
|
+
x: 0,
|
|
12610
|
+
y: 0,
|
|
12611
|
+
width,
|
|
12612
|
+
height,
|
|
12613
|
+
children: getAllHiddenMessage(legendInteractive, "segments")
|
|
12614
|
+
}) : arcs.map((arcDatum, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
|
|
12615
|
+
...getSegmentHandlers(arcDatum.data, navigationArcs.indexOf(arcDatum)),
|
|
12616
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12617
|
+
d: path(arcDatum) || "",
|
|
12618
|
+
fill: accessors.fill(arcDatum.data)
|
|
12619
|
+
})
|
|
12620
|
+
}, `arc-${index}`))
|
|
12621
|
+
}),
|
|
12622
|
+
selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12623
|
+
top: centerY,
|
|
12624
|
+
left: centerX,
|
|
12625
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
|
|
12626
|
+
chartId,
|
|
12627
|
+
d: path(selectedArc) || ""
|
|
12628
|
+
})
|
|
12629
|
+
}),
|
|
12630
|
+
!allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
|
|
12631
|
+
top: centerY,
|
|
12632
|
+
left: centerX,
|
|
12633
|
+
mask: wipeMask,
|
|
12634
|
+
children: [showLabels && arcs.map(renderLabel), svgChildren]
|
|
12635
|
+
})
|
|
12636
|
+
]
|
|
12637
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionOutput, {
|
|
12638
|
+
...selectionOutputProps,
|
|
12639
|
+
keyboardTooltipAnchor: selectedArc && getKeyboardTooltipAnchor(centerX, centerY, path.centroid(selectedArc)),
|
|
12640
|
+
renderTooltip
|
|
12121
12641
|
})]
|
|
12122
12642
|
});
|
|
12123
12643
|
}
|
|
@@ -12152,18 +12672,13 @@ var pie_semi_circle_chart_module_default = {
|
|
|
12152
12672
|
//#region src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx
|
|
12153
12673
|
/**
|
|
12154
12674
|
* Default tooltip renderer for semi-circle pie charts.
|
|
12155
|
-
* Renders
|
|
12675
|
+
* Renders the default `label: value` tooltip content for the hovered segment.
|
|
12156
12676
|
*
|
|
12157
12677
|
* @param {PieSemiCircleChartRenderTooltipParams} params - The tooltip parameters containing the hovered data point
|
|
12158
12678
|
* @return {ReactNode} The rendered tooltip content
|
|
12159
12679
|
*/
|
|
12160
12680
|
const renderDefaultPieSemiCircleTooltip = ({ tooltipData }) => {
|
|
12161
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
12162
|
-
data: tooltipData,
|
|
12163
|
-
top: 0,
|
|
12164
|
-
left: 0,
|
|
12165
|
-
renderContainer: false
|
|
12166
|
-
});
|
|
12681
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data: tooltipData });
|
|
12167
12682
|
};
|
|
12168
12683
|
const PAD_ANGLE = .03;
|
|
12169
12684
|
const DEFAULT_WIDTH$1 = 400;
|
|
@@ -12190,32 +12705,10 @@ const validateData = (data) => {
|
|
|
12190
12705
|
message: ""
|
|
12191
12706
|
};
|
|
12192
12707
|
};
|
|
12193
|
-
const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, thickness = .4, clockwise = true, withTooltips = false, showLegend = false, legend = {}, legendValueDisplay = "percentage", label, animation, note, className, children, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieSemiCircleTooltip, gap = "md" }) => {
|
|
12708
|
+
const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, thickness = .4, clockwise = true, withTooltips = false, showLegend = false, legend = {}, legendValueDisplay = "percentage", label, animation, note, className, children, tooltipOffsetX = 0, tooltipOffsetY = -15, renderTooltip = renderDefaultPieSemiCircleTooltip, ariaLabel, gap = "md" }) => {
|
|
12194
12709
|
const legendInteractive = legend.interactive ?? false;
|
|
12195
12710
|
const legendPosition = legend.position ?? "bottom";
|
|
12196
12711
|
const chartId = useChartId(providedChartId);
|
|
12197
|
-
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
12198
|
-
const standaloneScopeClass = useStandaloneScopeClass();
|
|
12199
|
-
const containerRef = (0, react.useRef)(null);
|
|
12200
|
-
const handleMouseMove = (0, react.useCallback)((event, arc) => {
|
|
12201
|
-
const bounds = containerRef.current?.getBoundingClientRect();
|
|
12202
|
-
if (!bounds) return;
|
|
12203
|
-
showTooltip({
|
|
12204
|
-
tooltipData: arc.data,
|
|
12205
|
-
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
12206
|
-
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
12207
|
-
});
|
|
12208
|
-
}, [
|
|
12209
|
-
showTooltip,
|
|
12210
|
-
tooltipOffsetX,
|
|
12211
|
-
tooltipOffsetY
|
|
12212
|
-
]);
|
|
12213
|
-
const handleMouseLeave = (0, react.useCallback)(() => {
|
|
12214
|
-
hideTooltip();
|
|
12215
|
-
}, [hideTooltip]);
|
|
12216
|
-
const handleArcMouseMove = (0, react.useCallback)((arc) => (event) => {
|
|
12217
|
-
handleMouseMove(event, arc);
|
|
12218
|
-
}, [handleMouseMove]);
|
|
12219
12712
|
const { isValid, message } = validateData(data);
|
|
12220
12713
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
12221
12714
|
const dataWithPercentages = useDataWithPercentages(data);
|
|
@@ -12249,7 +12742,31 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12249
12742
|
metadata: chartMetadata
|
|
12250
12743
|
});
|
|
12251
12744
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
12745
|
+
const wipeMask = animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null;
|
|
12252
12746
|
const effectiveWidth = propWidth || DEFAULT_WIDTH$1;
|
|
12747
|
+
const dataWithIndex = visibleData.map((d) => {
|
|
12748
|
+
const originalIndex = data.findIndex((item) => item.label === d.label);
|
|
12749
|
+
return {
|
|
12750
|
+
...d,
|
|
12751
|
+
index: originalIndex >= 0 ? originalIndex : 0
|
|
12752
|
+
};
|
|
12753
|
+
});
|
|
12754
|
+
const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2;
|
|
12755
|
+
const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2;
|
|
12756
|
+
const arcs = (0, _visx_shape.pie)({
|
|
12757
|
+
value: accessors.value,
|
|
12758
|
+
sort: accessors.sort,
|
|
12759
|
+
padAngle: PAD_ANGLE,
|
|
12760
|
+
startAngle,
|
|
12761
|
+
endAngle
|
|
12762
|
+
})(dataWithIndex);
|
|
12763
|
+
const navigationArcs = orderArcsForNavigation(arcs);
|
|
12764
|
+
const { chartRef, svgRef, selectedArc, getSegmentHandlers, getKeyboardTooltipAnchor, selectionOutputProps, chartProps } = usePieKeyboardNavigation({
|
|
12765
|
+
navigationArcs,
|
|
12766
|
+
withTooltips,
|
|
12767
|
+
tooltipOffsetX,
|
|
12768
|
+
tooltipOffsetY
|
|
12769
|
+
});
|
|
12253
12770
|
if (!isValid) {
|
|
12254
12771
|
const errorWidth = propHeight ? Math.min(propWidth || propHeight * 2, propHeight * 2) : effectiveWidth;
|
|
12255
12772
|
const errorHeight = errorWidth / 2;
|
|
@@ -12268,15 +12785,6 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12268
12785
|
})
|
|
12269
12786
|
});
|
|
12270
12787
|
}
|
|
12271
|
-
const dataWithIndex = visibleData.map((d) => {
|
|
12272
|
-
const originalIndex = data.findIndex((item) => item.label === d.label);
|
|
12273
|
-
return {
|
|
12274
|
-
...d,
|
|
12275
|
-
index: originalIndex >= 0 ? originalIndex : 0
|
|
12276
|
-
};
|
|
12277
|
-
});
|
|
12278
|
-
const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2;
|
|
12279
|
-
const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2;
|
|
12280
12788
|
const legendElement = showLegend && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
|
|
12281
12789
|
orientation: legend.orientation ?? "horizontal",
|
|
12282
12790
|
position: legendPosition,
|
|
@@ -12309,52 +12817,60 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12309
12817
|
const height = width / 2;
|
|
12310
12818
|
const radius = height;
|
|
12311
12819
|
const innerRadius = radius * (1 - thickness);
|
|
12820
|
+
const path = (0, _visx_shape.arc)({
|
|
12821
|
+
innerRadius,
|
|
12822
|
+
outerRadius: radius,
|
|
12823
|
+
cornerRadius: 3
|
|
12824
|
+
});
|
|
12312
12825
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
12313
|
-
ref:
|
|
12826
|
+
ref: chartRef,
|
|
12314
12827
|
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart__plot"],
|
|
12828
|
+
...chartProps,
|
|
12829
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Semi-circle chart", "jetpack-charts"),
|
|
12315
12830
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
12831
|
+
ref: svgRef,
|
|
12316
12832
|
width,
|
|
12317
12833
|
height,
|
|
12318
12834
|
viewBox: `0 0 ${width} ${height}`,
|
|
12319
|
-
children: [
|
|
12320
|
-
|
|
12321
|
-
|
|
12322
|
-
|
|
12323
|
-
|
|
12324
|
-
|
|
12325
|
-
|
|
12326
|
-
|
|
12327
|
-
|
|
12328
|
-
|
|
12329
|
-
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
|
|
12354
|
-
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_text.Text, {
|
|
12835
|
+
children: [
|
|
12836
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
|
|
12837
|
+
id: `radial-wipe-${chartId}`,
|
|
12838
|
+
radius,
|
|
12839
|
+
innerRadius,
|
|
12840
|
+
startAngle: "-180deg",
|
|
12841
|
+
wipePercentage: 50
|
|
12842
|
+
}) }),
|
|
12843
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12844
|
+
top: height,
|
|
12845
|
+
left: width / 2,
|
|
12846
|
+
mask: wipeMask,
|
|
12847
|
+
children: allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
|
|
12848
|
+
x: 0,
|
|
12849
|
+
y: -radius / 2,
|
|
12850
|
+
width,
|
|
12851
|
+
height,
|
|
12852
|
+
children: getAllHiddenMessage(legendInteractive, "segments")
|
|
12853
|
+
}) : arcs.map((arcDatum) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
|
|
12854
|
+
...getSegmentHandlers(arcDatum.data, navigationArcs.indexOf(arcDatum)),
|
|
12855
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12856
|
+
d: path(arcDatum) || "",
|
|
12857
|
+
fill: accessors.fill(arcDatum.data)
|
|
12858
|
+
})
|
|
12859
|
+
}, arcDatum.data.label))
|
|
12860
|
+
}),
|
|
12861
|
+
selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12862
|
+
top: height,
|
|
12863
|
+
left: width / 2,
|
|
12864
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
|
|
12865
|
+
chartId,
|
|
12866
|
+
d: path(selectedArc) || ""
|
|
12867
|
+
})
|
|
12868
|
+
}),
|
|
12869
|
+
!allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
|
|
12870
|
+
top: height,
|
|
12871
|
+
left: width / 2,
|
|
12872
|
+
mask: wipeMask,
|
|
12873
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_text.Text, {
|
|
12358
12874
|
textAnchor: "middle",
|
|
12359
12875
|
verticalAnchor: "start",
|
|
12360
12876
|
y: -40,
|
|
@@ -12366,18 +12882,13 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12366
12882
|
y: -20,
|
|
12367
12883
|
className: pie_semi_circle_chart_module_default.note,
|
|
12368
12884
|
children: note
|
|
12369
|
-
})] }),
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
|
|
12376
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12377
|
-
className: standaloneScopeClass,
|
|
12378
|
-
role: "tooltip",
|
|
12379
|
-
children: renderTooltip({ tooltipData })
|
|
12380
|
-
})
|
|
12885
|
+
})] }), svgChildren]
|
|
12886
|
+
})
|
|
12887
|
+
]
|
|
12888
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionOutput, {
|
|
12889
|
+
...selectionOutputProps,
|
|
12890
|
+
keyboardTooltipAnchor: selectedArc && getKeyboardTooltipAnchor(width / 2, height, path.centroid(selectedArc)),
|
|
12891
|
+
renderTooltip
|
|
12381
12892
|
})]
|
|
12382
12893
|
});
|
|
12383
12894
|
}
|
|
@@ -12631,7 +13142,9 @@ exports.PieSemiCircleChartUnresponsive = PieSemiCircleChart;
|
|
|
12631
13142
|
exports.Sparkline = Sparkline;
|
|
12632
13143
|
exports.SparklineUnresponsive = SparklineUnresponsive;
|
|
12633
13144
|
exports.ThemeProvider = GlobalChartsProvider;
|
|
13145
|
+
exports.TooltipBox = TooltipBox;
|
|
12634
13146
|
exports.TrendIndicator = TrendIndicator;
|
|
13147
|
+
exports.XYChartTooltip = XYChartTooltip;
|
|
12635
13148
|
exports.buildCalendarHeatmapData = buildCalendarHeatmapData;
|
|
12636
13149
|
exports.buildMonthCalendarHeatmapData = buildMonthCalendarHeatmapData;
|
|
12637
13150
|
exports.defaultTheme = defaultTheme;
|