@automattic/charts 4.8.0 → 4.10.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 +28 -0
- package/dist/index.cjs +766 -277
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +72 -8
- package/dist/index.d.cts +54 -15
- package/dist/index.d.ts +54 -15
- package/dist/index.js +770 -281
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/charts/area-chart/area-chart.tsx +7 -3
- package/src/charts/area-chart/test/area-chart.test.tsx +15 -14
- package/src/charts/area-chart/test/tooltip-resolution.test.tsx +2 -2
- package/src/charts/bar-chart/bar-chart.tsx +12 -4
- package/src/charts/bar-chart/test/bar-chart.test.tsx +74 -63
- package/src/charts/bar-list-chart/bar-list-chart.tsx +3 -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 +23 -7
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +22 -0
- package/src/charts/conversion-funnel-chart/types.ts +1 -1
- package/src/charts/geo-chart/geo-chart.tsx +17 -2
- package/src/charts/geo-chart/test/geo-chart.test.tsx +9 -4
- package/src/charts/geo-chart/types.ts +1 -1
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +10 -4
- package/src/charts/heatmap-chart/heatmap-chart.tsx +144 -37
- 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-legend.tsx +14 -2
- package/src/charts/heatmap-chart/private/index.ts +4 -2
- 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 +132 -7
- package/src/charts/heatmap-chart/types.ts +2 -2
- package/src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts +2 -2
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +52 -4
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +60 -9
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +80 -1
- package/src/charts/leaderboard-chart/types.ts +7 -1
- package/src/charts/line-chart/line-chart.tsx +8 -2
- 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 +37 -35
- package/src/charts/line-chart/test/tooltip-resolution.test.tsx +2 -2
- package/src/charts/line-chart/types.ts +3 -3
- package/src/charts/pie-chart/pie-chart.module.scss +3 -0
- package/src/charts/pie-chart/pie-chart.tsx +144 -139
- package/src/charts/pie-chart/test/pie-chart.test.tsx +167 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +3 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +117 -120
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +54 -0
- 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 +49 -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/x-zoom/test/x-zoom.test.tsx +3 -2
- package/src/charts/test/accessible-name.test.tsx +181 -0
- package/src/components/legend/hooks/test/use-chart-legend-items.test.tsx +63 -3
- package/src/components/legend/hooks/use-chart-legend-items.ts +63 -1
- package/src/components/legend/private/base-legend.tsx +27 -15
- package/src/components/legend/test/legend.test.tsx +42 -0
- package/src/components/legend/types.ts +2 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +20 -19
- package/src/components/tooltip/xy-chart-tooltip.tsx +3 -3
- package/src/hooks/test/use-xychart-theme.test.tsx +22 -0
- package/src/hooks/use-xychart-theme.ts +33 -2
- package/src/index.ts +1 -0
- package/src/types.ts +37 -3
- package/src/utils/resolve-font-size.ts +9 -10
- package/src/utils/test/resolve-font-size.test.ts +11 -2
package/dist/index.cjs
CHANGED
|
@@ -671,16 +671,17 @@ function readCustomProperty(varName, styles) {
|
|
|
671
671
|
}
|
|
672
672
|
//#endregion
|
|
673
673
|
//#region src/utils/resolve-font-size.ts
|
|
674
|
+
const toFontSize = (size) => Number.isFinite(size) && size >= 0 ? size : void 0;
|
|
674
675
|
/**
|
|
675
676
|
* Resolve a theme `fontSize` value into a plain number suitable for
|
|
676
677
|
* canvas-based measurement (e.g. `getStringWidth`).
|
|
677
678
|
*
|
|
678
679
|
* Accepts:
|
|
679
|
-
* - A number — returned as-is
|
|
680
|
+
* - A finite, non-negative number — returned as-is
|
|
680
681
|
* - A pixel string like `"12px"` — parsed and returned as a number
|
|
681
682
|
*
|
|
682
|
-
* Returns `undefined` for any other input (missing value,
|
|
683
|
-
* relative units like `rem`/`em`/`%`/`vh`) so callers can fall back to
|
|
683
|
+
* Returns `undefined` for any other input (missing value, a non-finite or
|
|
684
|
+
* negative size, or relative units like `rem`/`em`/`%`/`vh`) so callers can fall back to
|
|
684
685
|
* their own default. Relative units are intentionally rejected because
|
|
685
686
|
* we cannot resolve them to absolute pixels here without a parent
|
|
686
687
|
* computed style, and silently returning the unitless prefix
|
|
@@ -690,12 +691,10 @@ function readCustomProperty(varName, styles) {
|
|
|
690
691
|
* @return Parsed numeric font size in pixels, or `undefined` when unresolvable
|
|
691
692
|
*/
|
|
692
693
|
const resolveFontSize = (val) => {
|
|
693
|
-
if (typeof val === "number") return
|
|
694
|
+
if (typeof val === "number") return toFontSize(val);
|
|
694
695
|
if (typeof val === "string") {
|
|
695
|
-
const match = val.trim().match(
|
|
696
|
-
|
|
697
|
-
const parsed = parseFloat(match[1]);
|
|
698
|
-
return isNaN(parsed) ? void 0 : parsed;
|
|
696
|
+
const match = val.trim().match(/^\+?((?:\d*\.)?\d+)(px)?$/);
|
|
697
|
+
return match ? toFontSize(parseFloat(match[1])) : void 0;
|
|
699
698
|
}
|
|
700
699
|
};
|
|
701
700
|
//#endregion
|
|
@@ -1574,6 +1573,20 @@ const useChartScopeElement = () => (0, react.useContext)(ChartScopeContext);
|
|
|
1574
1573
|
const useStandaloneScopeClass = () => (0, react.useContext)(GlobalChartsContext) ? void 0 : CHART_SCOPE_CLASS;
|
|
1575
1574
|
//#endregion
|
|
1576
1575
|
//#region src/hooks/use-xychart-theme.ts
|
|
1576
|
+
const STARTS_LIKE_A_NUMBER = /^[+-]?[\d.]/;
|
|
1577
|
+
const NON_NEGATIVE_CSS_NUMBER = /^\+?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?:[a-z]+|%)?$/i;
|
|
1578
|
+
const isRenderableFontSize = (fontSize) => {
|
|
1579
|
+
if (typeof fontSize === "number") return resolveFontSize(fontSize) !== void 0;
|
|
1580
|
+
const value = fontSize.trim();
|
|
1581
|
+
if (!STARTS_LIKE_A_NUMBER.test(value)) return true;
|
|
1582
|
+
return NON_NEGATIVE_CSS_NUMBER.test(value) && Number.isFinite(parseFloat(value));
|
|
1583
|
+
};
|
|
1584
|
+
const withRenderableFontSize = (style) => {
|
|
1585
|
+
if (style?.fontSize === void 0 || isRenderableFontSize(style.fontSize)) return style;
|
|
1586
|
+
const rest = { ...style };
|
|
1587
|
+
delete rest.fontSize;
|
|
1588
|
+
return rest;
|
|
1589
|
+
};
|
|
1577
1590
|
const useXYChartTheme = (data) => {
|
|
1578
1591
|
const theme = useGlobalChartsTheme();
|
|
1579
1592
|
const scopeElement = useChartScopeElement();
|
|
@@ -1604,9 +1617,10 @@ const useXYChartTheme = (data) => {
|
|
|
1604
1617
|
yAxisLineStyles: { stroke: CATALOG_POINTERS.axisY },
|
|
1605
1618
|
yTickLineStyles: { stroke: CATALOG_POINTERS.tickY },
|
|
1606
1619
|
svgLabelSmall: {
|
|
1607
|
-
...theme.svgLabelSmall,
|
|
1620
|
+
...withRenderableFontSize(theme.svgLabelSmall),
|
|
1608
1621
|
fill: CATALOG_POINTERS.labelAxis
|
|
1609
|
-
}
|
|
1622
|
+
},
|
|
1623
|
+
svgLabelBig: withRenderableFontSize(theme.svgLabelBig)
|
|
1610
1624
|
});
|
|
1611
1625
|
}, [
|
|
1612
1626
|
theme,
|
|
@@ -2119,7 +2133,7 @@ const getLegendItemAriaLabel = (text, value, visible, interactive) => {
|
|
|
2119
2133
|
if (visible) return;
|
|
2120
2134
|
return (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n._x)("%s: hidden", "hidden non-interactive legend item", "jetpack-charts"), accessibleText);
|
|
2121
2135
|
};
|
|
2122
|
-
const BaseLegend = (0, react.forwardRef)(({ items, className, orientation = "horizontal", alignment = "center", shape = "rect", fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform, itemStyles, itemClassName, labelStyles, labelClassName, shapeStyles, render, interactive = false, chartId }, ref) => {
|
|
2136
|
+
const BaseLegend = (0, react.forwardRef)(({ items: allItems, className, orientation = "horizontal", alignment = "center", shape = "rect", fill = valueOrIdentityString, size = valueOrIdentityString, labelFormat = valueOrIdentity, labelTransform, itemStyles, itemClassName, labelStyles, labelClassName, shapeStyles, render, interactive = false, chartId }, ref) => {
|
|
2123
2137
|
const { margin: itemMargin = "0", flexDirection: itemDirection = "row" } = itemStyles ?? {};
|
|
2124
2138
|
const { justifyContent: labelJustifyContent = "flex-start", flex: labelFlex = "0 0 auto", margin: labelMargin = "0 4px", maxWidth, textOverflow = "wrap" } = labelStyles ?? {};
|
|
2125
2139
|
const { width: shapeWidth = 16, height: shapeHeight = 16, margin: shapeMargin = "2px 4px 2px 0" } = shapeStyles ?? {};
|
|
@@ -2127,6 +2141,16 @@ const BaseLegend = (0, react.forwardRef)(({ items, className, orientation = "hor
|
|
|
2127
2141
|
const context = (0, react.useContext)(GlobalChartsContext);
|
|
2128
2142
|
const chartInstanceContext = (0, react.useContext)(ChartInstanceContext);
|
|
2129
2143
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
2144
|
+
const isSeriesVisible = (0, react.useCallback)((seriesLabel) => {
|
|
2145
|
+
if (chartInstanceContext?.isSeriesVisible) return chartInstanceContext.isSeriesVisible(seriesLabel);
|
|
2146
|
+
if (!chartId || !context) return true;
|
|
2147
|
+
return context.isSeriesVisible(chartId, seriesLabel);
|
|
2148
|
+
}, [
|
|
2149
|
+
chartId,
|
|
2150
|
+
chartInstanceContext,
|
|
2151
|
+
context
|
|
2152
|
+
]);
|
|
2153
|
+
const items = (0, react.useMemo)(() => allItems.filter((item) => item.interactive !== false || !item.describesSeries || isSeriesVisible(item.describesSeries)), [allItems, isSeriesVisible]);
|
|
2130
2154
|
const domain = items.map((item) => item.label);
|
|
2131
2155
|
const legendScale = (0, _visx_scale.scaleOrdinal)({
|
|
2132
2156
|
domain,
|
|
@@ -2149,15 +2173,6 @@ const BaseLegend = (0, react.forwardRef)(({ items, className, orientation = "hor
|
|
|
2149
2173
|
chartId,
|
|
2150
2174
|
context
|
|
2151
2175
|
]);
|
|
2152
|
-
const isSeriesVisible = (0, react.useCallback)((seriesLabel) => {
|
|
2153
|
-
if (chartInstanceContext?.isSeriesVisible) return chartInstanceContext.isSeriesVisible(seriesLabel);
|
|
2154
|
-
if (!chartId || !context) return true;
|
|
2155
|
-
return context.isSeriesVisible(chartId, seriesLabel);
|
|
2156
|
-
}, [
|
|
2157
|
-
chartId,
|
|
2158
|
-
chartInstanceContext,
|
|
2159
|
-
context
|
|
2160
|
-
]);
|
|
2161
2176
|
const createClickHandler = (0, react.useCallback)((seriesLabels, itemInteractive) => {
|
|
2162
2177
|
if (!itemInteractive) return;
|
|
2163
2178
|
return () => handleLegendClick(seriesLabels);
|
|
@@ -2432,6 +2447,34 @@ function buildComparisonLegendItem(seriesData, items, label, getElementStyles, l
|
|
|
2432
2447
|
};
|
|
2433
2448
|
}
|
|
2434
2449
|
/**
|
|
2450
|
+
* Builds one static item per comparison series folded into another series' item, named after
|
|
2451
|
+
* that item and styled like the comparison series itself.
|
|
2452
|
+
* @param seriesData - The series data to search for comparison series
|
|
2453
|
+
* @param items - The legend items already built from the series
|
|
2454
|
+
* @param formatLabel - Names an item after the label of the item it was folded into
|
|
2455
|
+
* @param getElementStyles - Function to get element styles
|
|
2456
|
+
* @param legendShape - The shape type for legend items (string literal or React component)
|
|
2457
|
+
* @return The legend items, in series order
|
|
2458
|
+
*/
|
|
2459
|
+
function buildPerSeriesComparisonItems(seriesData, items, formatLabel, getElementStyles, legendShape) {
|
|
2460
|
+
return seriesData.flatMap((series, index) => {
|
|
2461
|
+
const owner = items.find((item) => item.seriesLabels?.includes(series.label));
|
|
2462
|
+
if (series.options?.type !== "comparison" || !owner || owner.seriesLabels?.[0] === series.label) return [];
|
|
2463
|
+
const { color, shapeStyles } = getElementStyles({
|
|
2464
|
+
data: series,
|
|
2465
|
+
index,
|
|
2466
|
+
legendShape
|
|
2467
|
+
});
|
|
2468
|
+
return [{
|
|
2469
|
+
label: formatLabel(owner.label),
|
|
2470
|
+
color,
|
|
2471
|
+
shapeStyle: shapeStyles,
|
|
2472
|
+
interactive: false,
|
|
2473
|
+
describesSeries: series.label
|
|
2474
|
+
}];
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
/**
|
|
2435
2478
|
* Processes point data into legend items
|
|
2436
2479
|
* @param pointData - The point data to process
|
|
2437
2480
|
* @param getElementStyles - Function to get element styles
|
|
@@ -2467,13 +2510,14 @@ function processPointData(pointData, getElementStyles, showValues, legendValueDi
|
|
|
2467
2510
|
* @return Array of legend items ready for display
|
|
2468
2511
|
*/
|
|
2469
2512
|
function useChartLegendItems(data, options = {}, legendShape) {
|
|
2470
|
-
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, renderGlyph } = options;
|
|
2513
|
+
const { showValues = false, legendValueDisplay = "percentage", withGlyph = false, glyphSize = 8, collapseGroups = false, comparisonItem = false, comparisonSeriesItems, renderGlyph } = options;
|
|
2471
2514
|
const { getElementStyles } = useGlobalChartsContext();
|
|
2472
2515
|
return (0, react.useMemo)(() => {
|
|
2473
2516
|
if (!data || !Array.isArray(data) || data.length === 0) return [];
|
|
2474
2517
|
if ("data" in data[0]) {
|
|
2475
2518
|
const seriesData = data;
|
|
2476
2519
|
const items = processSeriesData(seriesData, getElementStyles, showValues, withGlyph, glyphSize, collapseGroups, renderGlyph, legendShape);
|
|
2520
|
+
if (comparisonSeriesItems) return [...items, ...buildPerSeriesComparisonItems(seriesData, items, comparisonSeriesItems, getElementStyles, legendShape)];
|
|
2477
2521
|
const comparison = comparisonItem ? buildComparisonLegendItem(seriesData, items, typeof comparisonItem === "string" ? comparisonItem : (0, _wordpress_i18n.__)("Comparison period", "jetpack-charts"), getElementStyles, legendShape) : null;
|
|
2478
2522
|
return comparison ? [...items, comparison] : items;
|
|
2479
2523
|
}
|
|
@@ -2487,6 +2531,7 @@ function useChartLegendItems(data, options = {}, legendShape) {
|
|
|
2487
2531
|
glyphSize,
|
|
2488
2532
|
collapseGroups,
|
|
2489
2533
|
comparisonItem,
|
|
2534
|
+
comparisonSeriesItems,
|
|
2490
2535
|
renderGlyph,
|
|
2491
2536
|
legendShape
|
|
2492
2537
|
]);
|
|
@@ -3082,7 +3127,7 @@ const XYChartTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocu
|
|
|
3082
3127
|
/** @deprecated Use `XYChartTooltip`. */
|
|
3083
3128
|
const AccessibleTooltip = XYChartTooltip;
|
|
3084
3129
|
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false, visibleSeriesKey }) => {
|
|
3085
|
-
const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"
|
|
3130
|
+
const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"application\"]") ?? chartRef.current, [chartRef]);
|
|
3086
3131
|
const focusWithoutScrollIfNeeded = (0, react.useCallback)((element) => {
|
|
3087
3132
|
if (preventTooltipScroll) element?.focus({ preventScroll: true });
|
|
3088
3133
|
else element?.focus();
|
|
@@ -3297,11 +3342,13 @@ function useChartChildren(children, chartType) {
|
|
|
3297
3342
|
}
|
|
3298
3343
|
const displayName = child.type?.displayName;
|
|
3299
3344
|
if (displayName === `${chartType}.SVG` || displayName === "Chart.SVG") {
|
|
3300
|
-
|
|
3345
|
+
const { children: svgChildren } = child.props ?? {};
|
|
3346
|
+
if (svgChildren) react.Children.forEach(svgChildren, (svgChild) => {
|
|
3301
3347
|
svg.push(svgChild);
|
|
3302
3348
|
});
|
|
3303
3349
|
} else if (displayName === `${chartType}.HTML` || displayName === "Chart.HTML") {
|
|
3304
|
-
|
|
3350
|
+
const { children: htmlChildren } = child.props ?? {};
|
|
3351
|
+
if (htmlChildren) react.Children.forEach(htmlChildren, (htmlChild) => {
|
|
3305
3352
|
html.push(htmlChild);
|
|
3306
3353
|
});
|
|
3307
3354
|
} else if (child.type === _visx_group.Group) svg.push(child);
|
|
@@ -4123,6 +4170,7 @@ var line_chart_module_default = {
|
|
|
4123
4170
|
"line-chart--animated": "a8ccharts-inuQka-line-chart--animated",
|
|
4124
4171
|
"rise": "a8ccharts-inuQka-rise"
|
|
4125
4172
|
};
|
|
4173
|
+
const isReact18 = react.version.startsWith("18.");
|
|
4126
4174
|
const CloseIcon = () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
4127
4175
|
width: "16",
|
|
4128
4176
|
height: "16",
|
|
@@ -4165,7 +4213,7 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
|
|
|
4165
4213
|
className: line_chart_module_default["line-chart__annotation-label"],
|
|
4166
4214
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4167
4215
|
ref: buttonRef,
|
|
4168
|
-
popovertarget: popoverId,
|
|
4216
|
+
...isReact18 ? { popovertarget: popoverId } : { popoverTarget: popoverId },
|
|
4169
4217
|
className: line_chart_module_default["line-chart__annotation-label-trigger-button"],
|
|
4170
4218
|
style: {
|
|
4171
4219
|
width: `44px`,
|
|
@@ -4193,8 +4241,13 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
|
|
|
4193
4241
|
subtitle
|
|
4194
4242
|
})
|
|
4195
4243
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
4196
|
-
|
|
4197
|
-
|
|
4244
|
+
...isReact18 ? {
|
|
4245
|
+
popovertarget: popoverId,
|
|
4246
|
+
popovertargetaction: "hide"
|
|
4247
|
+
} : {
|
|
4248
|
+
popoverTarget: popoverId,
|
|
4249
|
+
popoverTargetAction: "hide"
|
|
4250
|
+
},
|
|
4198
4251
|
className: line_chart_module_default["line-chart__annotation-label-popover-close-button"],
|
|
4199
4252
|
"aria-label": (0, _wordpress_i18n.__)("Close", "jetpack-charts"),
|
|
4200
4253
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CloseIcon, {})
|
|
@@ -4716,10 +4769,11 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
4716
4769
|
]);
|
|
4717
4770
|
return null;
|
|
4718
4771
|
};
|
|
4719
|
-
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) => {
|
|
4772
|
+
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) => {
|
|
4720
4773
|
const legendInteractive = legend.interactive ?? false;
|
|
4721
4774
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
4722
4775
|
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
4776
|
+
const legendComparisonSeriesItems = legend.comparisonSeriesItems;
|
|
4723
4777
|
const legendShape = legend.shape ?? "line";
|
|
4724
4778
|
const legendPosition = legend.position ?? "bottom";
|
|
4725
4779
|
const formatting = useChartFormatting();
|
|
@@ -4904,12 +4958,14 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4904
4958
|
glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
|
|
4905
4959
|
collapseGroups: legendCollapseGroups,
|
|
4906
4960
|
comparisonItem: legendComparisonItem,
|
|
4961
|
+
comparisonSeriesItems: legendComparisonSeriesItems,
|
|
4907
4962
|
renderGlyph
|
|
4908
4963
|
}), [
|
|
4909
4964
|
withLegendGlyph,
|
|
4910
4965
|
glyphStyle?.radius,
|
|
4911
4966
|
legendCollapseGroups,
|
|
4912
4967
|
legendComparisonItem,
|
|
4968
|
+
legendComparisonSeriesItems,
|
|
4913
4969
|
renderGlyph
|
|
4914
4970
|
]), legendShape);
|
|
4915
4971
|
const chartMetadata = (0, react.useMemo)(() => ({
|
|
@@ -4984,8 +5040,8 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4984
5040
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
4985
5041
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4986
5042
|
ref: chartRef,
|
|
4987
|
-
role: "
|
|
4988
|
-
"aria-label": (0, _wordpress_i18n.__)("Line chart", "jetpack-charts"),
|
|
5043
|
+
role: "application",
|
|
5044
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Line chart", "jetpack-charts"),
|
|
4989
5045
|
tabIndex: 0,
|
|
4990
5046
|
onKeyDown: onChartKeyDown,
|
|
4991
5047
|
onFocus: onChartFocus,
|
|
@@ -4993,6 +5049,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4993
5049
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4994
5050
|
className: xy_plot_module_default["xy-plot"],
|
|
4995
5051
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
5052
|
+
accessibilityLabel: "",
|
|
4996
5053
|
theme,
|
|
4997
5054
|
width,
|
|
4998
5055
|
height: chartHeight,
|
|
@@ -5233,7 +5290,7 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
|
|
|
5233
5290
|
};
|
|
5234
5291
|
//#endregion
|
|
5235
5292
|
//#region src/charts/area-chart/area-chart.tsx
|
|
5236
|
-
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) => {
|
|
5293
|
+
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) => {
|
|
5237
5294
|
const legendInteractive = legend.interactive ?? false;
|
|
5238
5295
|
const legendShape = legend.shape ?? "rect";
|
|
5239
5296
|
const legendPosition = legend.position ?? "bottom";
|
|
@@ -5377,8 +5434,13 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5377
5434
|
withGlyph: false,
|
|
5378
5435
|
glyphSize: 0,
|
|
5379
5436
|
collapseGroups: legend.collapseGroups ?? false,
|
|
5380
|
-
comparisonItem: legend.comparisonItem ?? false
|
|
5381
|
-
|
|
5437
|
+
comparisonItem: legend.comparisonItem ?? false,
|
|
5438
|
+
comparisonSeriesItems: legend.comparisonSeriesItems
|
|
5439
|
+
}), [
|
|
5440
|
+
legend.collapseGroups,
|
|
5441
|
+
legend.comparisonItem,
|
|
5442
|
+
legend.comparisonSeriesItems
|
|
5443
|
+
]), legendShape);
|
|
5382
5444
|
const chartMetadata = (0, react.useMemo)(() => ({
|
|
5383
5445
|
stacked,
|
|
5384
5446
|
stackOffset,
|
|
@@ -5504,8 +5566,8 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5504
5566
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
5505
5567
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5506
5568
|
ref: chartRef,
|
|
5507
|
-
role: "
|
|
5508
|
-
"aria-label": (0, _wordpress_i18n.__)("Area chart", "jetpack-charts"),
|
|
5569
|
+
role: "application",
|
|
5570
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Area chart", "jetpack-charts"),
|
|
5509
5571
|
tabIndex: 0,
|
|
5510
5572
|
onKeyDown: onChartKeyDown,
|
|
5511
5573
|
onFocus: onChartFocus,
|
|
@@ -5513,6 +5575,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
5513
5575
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5514
5576
|
className: xy_plot_module_default["xy-plot"],
|
|
5515
5577
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
5578
|
+
accessibilityLabel: "",
|
|
5516
5579
|
theme,
|
|
5517
5580
|
width,
|
|
5518
5581
|
height: chartHeight,
|
|
@@ -6365,11 +6428,12 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ (0, react_jsx_runtime
|
|
|
6365
6428
|
className: bar_chart_module_default["bar-chart__tooltip-row"],
|
|
6366
6429
|
children: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%1$s: %2$s", "jetpack-charts"), label, value)
|
|
6367
6430
|
});
|
|
6368
|
-
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 }) => {
|
|
6431
|
+
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 }) => {
|
|
6369
6432
|
if (!withTooltips && (withBandHighlight || onBandHighlightChange)) warnOnce("bar-chart-band-highlight-without-tooltips", "BarChart: withBandHighlight and onBandHighlightChange require withTooltips.");
|
|
6370
6433
|
const legendInteractive = legend.interactive ?? false;
|
|
6371
6434
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
6372
6435
|
const legendComparisonItem = legend.comparisonItem ?? false;
|
|
6436
|
+
const legendComparisonSeriesItems = legend.comparisonSeriesItems;
|
|
6373
6437
|
const horizontal = orientation === "horizontal";
|
|
6374
6438
|
const chartId = useChartId(providedChartId);
|
|
6375
6439
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
@@ -6382,8 +6446,13 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6382
6446
|
});
|
|
6383
6447
|
const legendItems = useChartLegendItems(dataSorted, (0, react.useMemo)(() => ({
|
|
6384
6448
|
collapseGroups: legendCollapseGroups,
|
|
6385
|
-
comparisonItem: legendComparisonItem
|
|
6386
|
-
|
|
6449
|
+
comparisonItem: legendComparisonItem,
|
|
6450
|
+
comparisonSeriesItems: legendComparisonSeriesItems
|
|
6451
|
+
}), [
|
|
6452
|
+
legendCollapseGroups,
|
|
6453
|
+
legendComparisonItem,
|
|
6454
|
+
legendComparisonSeriesItems
|
|
6455
|
+
]));
|
|
6387
6456
|
const { getElementStyles } = useGlobalChartsContext();
|
|
6388
6457
|
const isSeriesRendered = (0, react.useCallback)((series) => isSeriesVisible(series.label), [isSeriesVisible]);
|
|
6389
6458
|
const hasWholeNumberValues = (0, react.useMemo)(() => hasOnlyWholeNumbers(dataSorted.filter(isSeriesRendered)), [dataSorted, isSeriesRendered]);
|
|
@@ -6673,9 +6742,9 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6673
6742
|
children: ({ contentHeight }) => {
|
|
6674
6743
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
6675
6744
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6676
|
-
role: "
|
|
6745
|
+
role: "application",
|
|
6677
6746
|
ref: chartRef,
|
|
6678
|
-
"aria-label": (0, _wordpress_i18n.__)("Bar chart", "jetpack-charts"),
|
|
6747
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Bar chart", "jetpack-charts"),
|
|
6679
6748
|
tabIndex: 0,
|
|
6680
6749
|
onKeyDown: onChartKeyDown,
|
|
6681
6750
|
onFocus: onChartFocus,
|
|
@@ -6683,6 +6752,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
6683
6752
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6684
6753
|
className: xy_plot_module_default["xy-plot"],
|
|
6685
6754
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
6755
|
+
accessibilityLabel: "",
|
|
6686
6756
|
theme,
|
|
6687
6757
|
width,
|
|
6688
6758
|
height: chartHeight,
|
|
@@ -6893,7 +6963,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
6893
6963
|
right: 20,
|
|
6894
6964
|
bottom: 0,
|
|
6895
6965
|
top: 0
|
|
6896
|
-
}, className, ...rest }) => {
|
|
6966
|
+
}, className, ariaLabel, ...rest }) => {
|
|
6897
6967
|
const { getElementStyles } = useGlobalChartsContext();
|
|
6898
6968
|
const tintedData = (0, react.useMemo)(() => {
|
|
6899
6969
|
if (data.length > 1) return data;
|
|
@@ -6968,6 +7038,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
6968
7038
|
xScale: chartOptions.xScale,
|
|
6969
7039
|
yScale: chartOptions.yScale
|
|
6970
7040
|
},
|
|
7041
|
+
ariaLabel: ariaLabel ?? (0, _wordpress_i18n.__)("Bar list chart", "jetpack-charts"),
|
|
6971
7042
|
...rest
|
|
6972
7043
|
});
|
|
6973
7044
|
};
|
|
@@ -7043,6 +7114,8 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
7043
7114
|
};
|
|
7044
7115
|
//#endregion
|
|
7045
7116
|
//#region src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx
|
|
7117
|
+
/** Chart height (px) below which the funnel tightens its gaps so the bars keep their room. */
|
|
7118
|
+
const SHORT_CHART_HEIGHT = 180;
|
|
7046
7119
|
/**
|
|
7047
7120
|
* Internal ConversionFunnelChart component with chart registration
|
|
7048
7121
|
*
|
|
@@ -7054,6 +7127,7 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
7054
7127
|
* @param props.loading - Whether the chart is in loading state
|
|
7055
7128
|
* @param props.animation - Whether to show chart animation on initial render or not
|
|
7056
7129
|
* @param props.className - Additional CSS class name
|
|
7130
|
+
* @param props.ariaLabel - Accessible name for the chart group
|
|
7057
7131
|
* @param props.height - Height of the chart container. Falls back to style.height if set, otherwise defaults to "100%".
|
|
7058
7132
|
* @param props.style - Custom styling
|
|
7059
7133
|
* @param props.renderStepLabel - Custom render function for step labels
|
|
@@ -7063,7 +7137,7 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
7063
7137
|
* @param props.tooltipStyle - Inline styles merged over the tooltip box defaults
|
|
7064
7138
|
* @return JSX element representing the conversion funnel chart
|
|
7065
7139
|
*/
|
|
7066
|
-
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
|
|
7140
|
+
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, ariaLabel, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip, tooltipStyle }) => {
|
|
7067
7141
|
const chartId = useChartId(providedChartId);
|
|
7068
7142
|
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
7069
7143
|
const chartRef = (0, react.useRef)(null);
|
|
@@ -7072,10 +7146,13 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7072
7146
|
const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
7073
7147
|
const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
|
|
7074
7148
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
7149
|
+
const [measureChartRef, , chartHeight] = useElementSize();
|
|
7150
|
+
const gap = chartHeight > 0 && chartHeight < SHORT_CHART_HEIGHT ? "sm" : "xl";
|
|
7075
7151
|
const setChartRef = (0, react.useCallback)((node) => {
|
|
7076
7152
|
chartRef.current = node;
|
|
7077
7153
|
setScopeNode(node);
|
|
7078
|
-
|
|
7154
|
+
measureChartRef(node);
|
|
7155
|
+
}, [measureChartRef]);
|
|
7079
7156
|
const clearSelectionAndRef = (0, react.useCallback)(() => {
|
|
7080
7157
|
clearSelection();
|
|
7081
7158
|
selectedBarRef.current = null;
|
|
@@ -7223,7 +7300,9 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7223
7300
|
const maxRate = Math.max(...steps.map((step) => step.rate));
|
|
7224
7301
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7225
7302
|
direction: "column",
|
|
7226
|
-
gap
|
|
7303
|
+
gap,
|
|
7304
|
+
role: "group",
|
|
7305
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Conversion funnel chart", "jetpack-charts"),
|
|
7227
7306
|
ref: setChartRef,
|
|
7228
7307
|
className: (0, clsx.default)("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
7229
7308
|
style: {
|
|
@@ -7254,7 +7333,7 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
7254
7333
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7255
7334
|
direction: "column",
|
|
7256
7335
|
className: (0, clsx.default)(conversion_funnel_chart_module_default["funnel-step"], isColorPaletteResolved && conversion_funnel_chart_module_default["funnel-step--animated"], isBlurred && conversion_funnel_chart_module_default["funnel-step--blurred"]),
|
|
7257
|
-
gap
|
|
7336
|
+
gap,
|
|
7258
7337
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7259
7338
|
direction: "column",
|
|
7260
7339
|
gap: "xs",
|
|
@@ -7448,6 +7527,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
7448
7527
|
*
|
|
7449
7528
|
* @param props - The props for the GeoChart component
|
|
7450
7529
|
* @param props.data - Data in Google Charts format (array of arrays with headers)
|
|
7530
|
+
* @param props.ariaLabel - Accessible name of the chart
|
|
7451
7531
|
* @param props.width - Width of the chart in pixels
|
|
7452
7532
|
* @param props.height - Height of the chart in pixels
|
|
7453
7533
|
* @param props.region - Region to display ('world', 'US', or ISO 3166-1 alpha-2 code)
|
|
@@ -7459,7 +7539,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
7459
7539
|
* @param props.renderPlaceholder - Optional render function for the loading placeholder
|
|
7460
7540
|
* @return A React component displaying an interactive map with data visualization
|
|
7461
7541
|
*/
|
|
7462
|
-
const GeoChartInternal = ({ className, data, width, height, region = "world", resolution = "countries", displayMode = "regions", domain, onError, renderPlaceholder }) => {
|
|
7542
|
+
const GeoChartInternal = ({ className, data, ariaLabel, width, height, region = "world", resolution = "countries", displayMode = "regions", domain, onError, renderPlaceholder }) => {
|
|
7463
7543
|
const { getElementStyles } = useGlobalChartsContext();
|
|
7464
7544
|
const scopeElement = useChartScopeElement();
|
|
7465
7545
|
const containerRef = (0, react.useRef)(null);
|
|
@@ -7547,8 +7627,14 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
7547
7627
|
sanitizedData.hasHtmlTooltips
|
|
7548
7628
|
]);
|
|
7549
7629
|
const chartEvents = (0, react.useMemo)(() => {
|
|
7550
|
-
|
|
7551
|
-
|
|
7630
|
+
const readyEvent = {
|
|
7631
|
+
eventName: "ready",
|
|
7632
|
+
callback: () => {
|
|
7633
|
+
containerRef.current?.querySelectorAll("svg").forEach((svg) => svg.setAttribute("aria-hidden", "true"));
|
|
7634
|
+
}
|
|
7635
|
+
};
|
|
7636
|
+
if (!onError) return [readyEvent];
|
|
7637
|
+
return [readyEvent, {
|
|
7552
7638
|
eventName: "error",
|
|
7553
7639
|
callback: ({ eventArgs }) => {
|
|
7554
7640
|
onError(normalizeGeoChartError(eventArgs));
|
|
@@ -7557,6 +7643,8 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
7557
7643
|
}, [onError]);
|
|
7558
7644
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Center, {
|
|
7559
7645
|
ref: containerRef,
|
|
7646
|
+
role: "group",
|
|
7647
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Geo chart", "jetpack-charts"),
|
|
7560
7648
|
className: (0, clsx.default)("geo-chart", geo_chart_module_default.container, className),
|
|
7561
7649
|
style: {
|
|
7562
7650
|
width,
|
|
@@ -7688,6 +7776,7 @@ var heatmap_chart_module_default = {
|
|
|
7688
7776
|
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
7689
7777
|
"heatmap-chart__legend-scale--bar": "a8ccharts-O3YMOW-heatmap-chart__legend-scale--bar",
|
|
7690
7778
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
7779
|
+
"heatmap-chart__legend-swatch--empty": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch--empty",
|
|
7691
7780
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
7692
7781
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
7693
7782
|
"heatmap-chart--height-capped": "a8ccharts-O3YMOW-heatmap-chart--height-capped"
|
|
@@ -7785,8 +7874,9 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
|
|
|
7785
7874
|
const context = (0, react.useContext)(HeatmapContext);
|
|
7786
7875
|
const { legend } = useGlobalChartsTheme();
|
|
7787
7876
|
if (!context) return null;
|
|
7788
|
-
const { fillVars } = context;
|
|
7877
|
+
const { extent, fillVars } = context;
|
|
7789
7878
|
const labelStyle = legend.labelStyles;
|
|
7879
|
+
const showsEmptyCell = isEmptyValue(0, extent);
|
|
7790
7880
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7791
7881
|
direction: "row",
|
|
7792
7882
|
gap: "xs",
|
|
@@ -7798,12 +7888,12 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
|
|
|
7798
7888
|
style: labelStyle,
|
|
7799
7889
|
children: lessLabel ?? (0, _wordpress_i18n.__)("Less", "jetpack-charts")
|
|
7800
7890
|
}),
|
|
7801
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
7891
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
7802
7892
|
direction: "row",
|
|
7803
7893
|
gap: variant === "bar" ? void 0 : "xs",
|
|
7804
7894
|
"aria-hidden": "true",
|
|
7805
7895
|
className: variant === "bar" ? heatmap_chart_module_default["heatmap-chart__legend-scale--bar"] : void 0,
|
|
7806
|
-
children: Array.from({ length: steps }, (_, index) => {
|
|
7896
|
+
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) => {
|
|
7807
7897
|
const intensity = steps <= 1 ? 1 : index / (steps - 1);
|
|
7808
7898
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7809
7899
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
@@ -7812,7 +7902,7 @@ const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }
|
|
|
7812
7902
|
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
7813
7903
|
}
|
|
7814
7904
|
}, index);
|
|
7815
|
-
})
|
|
7905
|
+
})]
|
|
7816
7906
|
}),
|
|
7817
7907
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
7818
7908
|
variant: "body-sm",
|
|
@@ -7838,9 +7928,11 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
|
7838
7928
|
const ungrouped = () => ({
|
|
7839
7929
|
columns: Array.from({ length: columnCount }, (_, index) => ({
|
|
7840
7930
|
line: firstLine + index,
|
|
7931
|
+
band: 0,
|
|
7841
7932
|
gapBefore: false
|
|
7842
7933
|
})),
|
|
7843
|
-
groups: []
|
|
7934
|
+
groups: [],
|
|
7935
|
+
bands: 1
|
|
7844
7936
|
});
|
|
7845
7937
|
if (!groups || groups.length === 0 || columnCount === 0) return ungrouped();
|
|
7846
7938
|
const spans = groups.map((group) => group.span);
|
|
@@ -7856,11 +7948,13 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
|
7856
7948
|
if (groupIndex > 0) line += 1;
|
|
7857
7949
|
laidOut.push({
|
|
7858
7950
|
...group,
|
|
7859
|
-
line
|
|
7951
|
+
line,
|
|
7952
|
+
band: 0
|
|
7860
7953
|
});
|
|
7861
7954
|
for (let offset = 0; offset < group.span; offset++) {
|
|
7862
7955
|
columns.push({
|
|
7863
7956
|
line,
|
|
7957
|
+
band: 0,
|
|
7864
7958
|
gapBefore: groupIndex > 0 && offset === 0,
|
|
7865
7959
|
group: groupIndex
|
|
7866
7960
|
});
|
|
@@ -7870,13 +7964,99 @@ const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
|
7870
7964
|
while (columns.length < columnCount) {
|
|
7871
7965
|
columns.push({
|
|
7872
7966
|
line,
|
|
7967
|
+
band: 0,
|
|
7873
7968
|
gapBefore: false
|
|
7874
7969
|
});
|
|
7875
7970
|
line += 1;
|
|
7876
7971
|
}
|
|
7877
7972
|
return {
|
|
7878
7973
|
columns,
|
|
7879
|
-
groups: laidOut
|
|
7974
|
+
groups: laidOut,
|
|
7975
|
+
bands: 1
|
|
7976
|
+
};
|
|
7977
|
+
};
|
|
7978
|
+
/**
|
|
7979
|
+
* Wraps the groups onto bands of equal group count, each band starting back at
|
|
7980
|
+
* the first data line so the groups line up in slots down the bands.
|
|
7981
|
+
*
|
|
7982
|
+
* @param layout - The unwrapped layout from `resolveColumnGroups`.
|
|
7983
|
+
* @param bands - Bands to aim for; the groups split as evenly as whole bands allow.
|
|
7984
|
+
* @return The wrapped layout, or null when there is nothing to wrap: one band, one group, or a column outside every group.
|
|
7985
|
+
*/
|
|
7986
|
+
const wrapColumnGroups = (layout, bands) => {
|
|
7987
|
+
const { columns, groups } = layout;
|
|
7988
|
+
if (bands < 2 || groups.length < 2 || columns.some((column) => column.group === void 0)) return null;
|
|
7989
|
+
const perBand = Math.ceil(groups.length / bands);
|
|
7990
|
+
const slotSpans = Array(perBand).fill(0);
|
|
7991
|
+
groups.forEach((group, index) => {
|
|
7992
|
+
const slot = index % perBand;
|
|
7993
|
+
slotSpans[slot] = Math.max(slotSpans[slot], group.span);
|
|
7994
|
+
});
|
|
7995
|
+
const slotLines = [];
|
|
7996
|
+
let line = columns[0].line;
|
|
7997
|
+
slotSpans.forEach((span, slot) => {
|
|
7998
|
+
if (slot > 0) line += 1;
|
|
7999
|
+
slotLines.push(line);
|
|
8000
|
+
line += span;
|
|
8001
|
+
});
|
|
8002
|
+
const wrappedGroups = groups.map((group, index) => ({
|
|
8003
|
+
...group,
|
|
8004
|
+
line: slotLines[index % perBand],
|
|
8005
|
+
band: Math.floor(index / perBand)
|
|
8006
|
+
}));
|
|
8007
|
+
return {
|
|
8008
|
+
columns: columns.map((column) => {
|
|
8009
|
+
const group = column.group;
|
|
8010
|
+
const offset = column.line - groups[group].line;
|
|
8011
|
+
return {
|
|
8012
|
+
...column,
|
|
8013
|
+
line: wrappedGroups[group].line + offset,
|
|
8014
|
+
band: wrappedGroups[group].band,
|
|
8015
|
+
gapBefore: offset === 0 && group % perBand > 0
|
|
8016
|
+
};
|
|
8017
|
+
}),
|
|
8018
|
+
groups: wrappedGroups,
|
|
8019
|
+
bands: Math.ceil(groups.length / perBand),
|
|
8020
|
+
slotSpans
|
|
8021
|
+
};
|
|
8022
|
+
};
|
|
8023
|
+
//#endregion
|
|
8024
|
+
//#region src/charts/heatmap-chart/private/fit-compact-cells.ts
|
|
8025
|
+
/**
|
|
8026
|
+
* Largest whole-pixel square cell, and the band count giving it, for a compact grid in a box.
|
|
8027
|
+
*
|
|
8028
|
+
* @param input - The box, the grid's layout, and its fixed gaps and label sizes.
|
|
8029
|
+
* @return The fit; one band at `minCellSize` when no band count reaches it.
|
|
8030
|
+
*/
|
|
8031
|
+
const fitCompactCells = (input) => {
|
|
8032
|
+
const { width, height, layout, rows, cellGap, groupGap, minCellSize } = input;
|
|
8033
|
+
const columns = layout.columns.length;
|
|
8034
|
+
if (columns === 0 || rows === 0) return {
|
|
8035
|
+
bands: 1,
|
|
8036
|
+
cellSize: minCellSize
|
|
8037
|
+
};
|
|
8038
|
+
const maxBands = Math.max(1, layout.groups.length);
|
|
8039
|
+
const labelHeights = (input.columnLabelHeight ?? 0) + (input.groupLabelHeight ?? 0);
|
|
8040
|
+
const bandTracks = (input.columnLabelHeight === null ? 0 : 1) + rows + (input.groupLabelHeight === null ? 0 : 1);
|
|
8041
|
+
let best = null;
|
|
8042
|
+
for (let target = 1; target <= maxBands; target++) {
|
|
8043
|
+
const wrapped = target > 1 ? wrapColumnGroups(layout, target) : null;
|
|
8044
|
+
const { bands } = wrapped ?? layout;
|
|
8045
|
+
const cellColumns = wrapped ? wrapped.slotSpans.reduce((sum, span) => sum + span, 0) : columns;
|
|
8046
|
+
const gapTracks = wrapped ? wrapped.slotSpans.length - 1 : layout.columns.filter((column) => column.gapBefore).length;
|
|
8047
|
+
const columnTracks = 1 + cellColumns + gapTracks;
|
|
8048
|
+
const byWidth = (width - input.rowLabelWidth - gapTracks * groupGap - (columnTracks - 1) * cellGap) / cellColumns;
|
|
8049
|
+
const rowTracks = bands * bandTracks + (bands - 1);
|
|
8050
|
+
const byHeight = (height - (bands * labelHeights + (bands - 1) * groupGap + (rowTracks - 1) * cellGap)) / (bands * rows);
|
|
8051
|
+
const cellSize = Math.floor(Math.min(byWidth, byHeight));
|
|
8052
|
+
if (cellSize >= minCellSize && (!best || cellSize > best.cellSize)) best = {
|
|
8053
|
+
bands,
|
|
8054
|
+
cellSize
|
|
8055
|
+
};
|
|
8056
|
+
}
|
|
8057
|
+
return best ?? {
|
|
8058
|
+
bands: 1,
|
|
8059
|
+
cellSize: minCellSize
|
|
7880
8060
|
};
|
|
7881
8061
|
};
|
|
7882
8062
|
//#endregion
|
|
@@ -8019,18 +8199,32 @@ const CELL_VALUE_MODIFIER = {
|
|
|
8019
8199
|
white: heatmap_chart_module_default["heatmap-chart__cell-value--white"]
|
|
8020
8200
|
};
|
|
8021
8201
|
const NO_ROW_LABELS = [];
|
|
8022
|
-
const TOOLTIP_BOX_STYLE = { zIndex: 3 };
|
|
8202
|
+
const TOOLTIP_BOX_STYLE$1 = { zIndex: 3 };
|
|
8203
|
+
const largest = (root, selector, size) => Math.max(0, ...Array.from(root.querySelectorAll(selector), (el) => el[size]));
|
|
8204
|
+
const gridBox = (chart, grid) => {
|
|
8205
|
+
let height = chart.clientHeight;
|
|
8206
|
+
const rowGap = parseFloat(getComputedStyle(chart).rowGap) || 0;
|
|
8207
|
+
Array.from(chart.children).forEach((child) => {
|
|
8208
|
+
const { display, position } = getComputedStyle(child);
|
|
8209
|
+
if (child === grid || display === "none" || position === "absolute" || position === "fixed") return;
|
|
8210
|
+
height -= child.offsetHeight + rowGap;
|
|
8211
|
+
});
|
|
8212
|
+
return {
|
|
8213
|
+
width: chart.clientWidth,
|
|
8214
|
+
height
|
|
8215
|
+
};
|
|
8216
|
+
};
|
|
8023
8217
|
const cellName = (info) => info.cellLabel || [
|
|
8024
8218
|
info.groupLabel,
|
|
8025
8219
|
info.columnLabel,
|
|
8026
8220
|
info.rowLabel
|
|
8027
8221
|
].filter(Boolean).join(" ");
|
|
8028
|
-
const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, columnGroups, keyboardNavigation = "grid", ariaLabel, primaryColor, gap = "md", withTooltips = false, renderTooltip, tooltipStyle, children }) => {
|
|
8222
|
+
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 }) => {
|
|
8029
8223
|
const chartId = useChartId(providedChartId);
|
|
8030
8224
|
const tooltipBoxStyle = tooltipStyle ? {
|
|
8031
|
-
...TOOLTIP_BOX_STYLE,
|
|
8225
|
+
...TOOLTIP_BOX_STYLE$1,
|
|
8032
8226
|
...tooltipStyle
|
|
8033
|
-
} : TOOLTIP_BOX_STYLE;
|
|
8227
|
+
} : TOOLTIP_BOX_STYLE$1;
|
|
8034
8228
|
const { getElementStyles, theme } = useGlobalChartsContext();
|
|
8035
8229
|
const scopeElement = useChartScopeElement();
|
|
8036
8230
|
const { heatmapChart: heatmapChartSettings } = theme;
|
|
@@ -8039,8 +8233,9 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8039
8233
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
8040
8234
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
8041
8235
|
const containerRef = (0, react.useRef)(null);
|
|
8236
|
+
const chartRef = (0, react.useRef)(null);
|
|
8042
8237
|
const [labelRoles, setLabelRoles] = (0, react.useState)(null);
|
|
8043
|
-
const getTooltipOrigin = (0, react.useCallback)(() =>
|
|
8238
|
+
const getTooltipOrigin = (0, react.useCallback)(() => chartRef.current?.getBoundingClientRect() ?? null, []);
|
|
8044
8239
|
const { color: primaryColorHex } = getElementStyles({
|
|
8045
8240
|
index: 0,
|
|
8046
8241
|
overrideColor: primaryColor
|
|
@@ -8082,6 +8277,49 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8082
8277
|
const groupLayout = (0, react.useMemo)(() => resolveColumnGroups(columnGroups, columns, 2), [columnGroups, columns]);
|
|
8083
8278
|
const { compactCellGap, compactCellSize, groupGap } = heatmapChartSettings;
|
|
8084
8279
|
const drawValues = showValues ?? !compact;
|
|
8280
|
+
const hasColumnLabels = data.some((column) => Boolean(column.label));
|
|
8281
|
+
const hasGroups = groupLayout.groups.length > 0;
|
|
8282
|
+
const [fit, setFit] = (0, react.useState)(null);
|
|
8283
|
+
const hasSummary = data.some((column) => column.summary);
|
|
8284
|
+
const fitting = compact && fitCells && !hasSummary;
|
|
8285
|
+
if (fitCells && !fitting) warnOnce("heatmap:fitCells", "fitCells applies only in compact mode without summary columns, so the cells keep their size.");
|
|
8286
|
+
useIsomorphicLayoutEffect(() => {
|
|
8287
|
+
const chart = chartRef.current;
|
|
8288
|
+
const grid = containerRef.current;
|
|
8289
|
+
if (!fitting || !chart || !grid) {
|
|
8290
|
+
setFit(null);
|
|
8291
|
+
return;
|
|
8292
|
+
}
|
|
8293
|
+
const measure = () => {
|
|
8294
|
+
const next = fitCompactCells({
|
|
8295
|
+
...gridBox(chart, grid),
|
|
8296
|
+
layout: groupLayout,
|
|
8297
|
+
rows,
|
|
8298
|
+
cellGap: compactCellGap,
|
|
8299
|
+
groupGap,
|
|
8300
|
+
rowLabelWidth: largest(grid, `.${heatmap_chart_module_default["heatmap-chart__row-label"]}`, "offsetWidth"),
|
|
8301
|
+
columnLabelHeight: hasColumnLabels ? largest(grid, `.${heatmap_chart_module_default["heatmap-chart__col-label"]}`, "offsetHeight") : null,
|
|
8302
|
+
groupLabelHeight: hasGroups ? largest(grid, `.${heatmap_chart_module_default["heatmap-chart__group-label"]}`, "offsetHeight") : null,
|
|
8303
|
+
minCellSize: compactCellSize
|
|
8304
|
+
});
|
|
8305
|
+
setFit((previous) => (0, import_fast_deep_equal.default)(previous, next) ? previous : next);
|
|
8306
|
+
};
|
|
8307
|
+
measure();
|
|
8308
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
8309
|
+
const observer = new ResizeObserver(() => (0, react_dom.flushSync)(measure));
|
|
8310
|
+
observer.observe(chart);
|
|
8311
|
+
return () => observer.disconnect();
|
|
8312
|
+
}, [
|
|
8313
|
+
fitting,
|
|
8314
|
+
groupLayout,
|
|
8315
|
+
rows,
|
|
8316
|
+
hasColumnLabels,
|
|
8317
|
+
hasGroups,
|
|
8318
|
+
compactCellGap,
|
|
8319
|
+
compactCellSize,
|
|
8320
|
+
groupGap
|
|
8321
|
+
]);
|
|
8322
|
+
const wrapped = (0, react.useMemo)(() => fit ? wrapColumnGroups(groupLayout, fit.bands) : null, [fit, groupLayout]);
|
|
8085
8323
|
const buildTooltipData = (0, react.useCallback)((columnIndex, rowIndex) => {
|
|
8086
8324
|
const cell = data[columnIndex]?.data[rowIndex];
|
|
8087
8325
|
const group = groupLayout.columns[columnIndex]?.group;
|
|
@@ -8221,21 +8459,25 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8221
8459
|
});
|
|
8222
8460
|
const columnTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellWidth ?? 0}px, ${maxCellWidth ? `${maxCellWidth}px` : "1fr"})`;
|
|
8223
8461
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
8224
|
-
const
|
|
8225
|
-
const
|
|
8226
|
-
const
|
|
8227
|
-
const
|
|
8462
|
+
const placed = wrapped ?? groupLayout;
|
|
8463
|
+
const columnLine = (columnIndex) => placed.columns[columnIndex].line;
|
|
8464
|
+
const bandOf = (columnIndex) => placed.columns[columnIndex].band;
|
|
8465
|
+
const { bands } = placed;
|
|
8466
|
+
const bandRowCount = (hasColumnLabels ? 1 : 0) + rows + (hasGroups ? 1 : 0) + 1;
|
|
8467
|
+
const labelRowOf = (band) => 1 + band * bandRowCount;
|
|
8468
|
+
const dataRowOf = (band, rowIndex) => labelRowOf(band) + (hasColumnLabels ? 1 : 0) + rowIndex;
|
|
8228
8469
|
const dataTrack = (column) => column.summary ? "minmax(auto, max-content)" : columnTrack;
|
|
8229
8470
|
const gapTrack = compact ? `minmax(${groupGap}px, 1fr)` : `${groupGap}px`;
|
|
8230
|
-
const columnTracks = data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ");
|
|
8471
|
+
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(" ");
|
|
8472
|
+
const bandTracks = `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`;
|
|
8231
8473
|
const gridStyle = {
|
|
8232
8474
|
...fillVars,
|
|
8233
8475
|
gridTemplateColumns: `auto ${columnTracks}`,
|
|
8234
|
-
gridTemplateRows:
|
|
8476
|
+
gridTemplateRows: Array(bands).fill(bandTracks).join(` ${groupGap}px `)
|
|
8235
8477
|
};
|
|
8236
8478
|
if (compact) {
|
|
8237
8479
|
gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
|
|
8238
|
-
gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${compactCellSize}px`;
|
|
8480
|
+
gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${fit?.cellSize ?? compactCellSize}px`;
|
|
8239
8481
|
}
|
|
8240
8482
|
const summaryGaps = (columnIndex) => {
|
|
8241
8483
|
if (!data[columnIndex]?.summary) return {};
|
|
@@ -8255,6 +8497,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8255
8497
|
legendChildren: [],
|
|
8256
8498
|
trailingContent: nonLegendChildren,
|
|
8257
8499
|
gap,
|
|
8500
|
+
rootRef: chartRef,
|
|
8258
8501
|
className: (0, clsx.default)("heatmap-chart", heatmap_chart_module_default["heatmap-chart"], className, { [heatmap_chart_module_default["heatmap-chart--height-capped"]]: heightCapped }),
|
|
8259
8502
|
style: {
|
|
8260
8503
|
width: width || void 0,
|
|
@@ -8284,11 +8527,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8284
8527
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
8285
8528
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
|
|
8286
8529
|
gridColumn: 1,
|
|
8287
|
-
gridRow:
|
|
8530
|
+
gridRow: labelRowOf(0)
|
|
8288
8531
|
} }), data.map((column, columnIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8289
8532
|
style: {
|
|
8290
8533
|
gridColumn: columnLine(columnIndex),
|
|
8291
|
-
gridRow:
|
|
8534
|
+
gridRow: labelRowOf(bandOf(columnIndex))
|
|
8292
8535
|
},
|
|
8293
8536
|
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
8294
8537
|
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
@@ -8299,24 +8542,23 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8299
8542
|
}),
|
|
8300
8543
|
Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
8301
8544
|
const labelVisible = !compact || rowIndex % 2 === 0;
|
|
8302
|
-
const gridRow = firstDataRow + rowIndex;
|
|
8303
8545
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8304
8546
|
role: "row",
|
|
8305
8547
|
"aria-rowindex": rowIndex + 1,
|
|
8306
8548
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
8307
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8549
|
+
children: [Array.from({ length: bands }).map((_band, band) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8308
8550
|
"aria-hidden": "true",
|
|
8309
8551
|
className: heatmap_chart_module_default["heatmap-chart__row-label"],
|
|
8310
8552
|
style: {
|
|
8311
8553
|
gridColumn: 1,
|
|
8312
|
-
gridRow
|
|
8554
|
+
gridRow: dataRowOf(band, rowIndex)
|
|
8313
8555
|
},
|
|
8314
8556
|
children: labelVisible ? rowLabels[rowIndex] ?? "" : ""
|
|
8315
|
-
}), data.map((column, columnIndex) => {
|
|
8557
|
+
}, `row-label-${band}`)), data.map((column, columnIndex) => {
|
|
8316
8558
|
const cell = column.data[rowIndex];
|
|
8317
8559
|
const placement = {
|
|
8318
8560
|
gridColumn: columnLine(columnIndex),
|
|
8319
|
-
gridRow
|
|
8561
|
+
gridRow: dataRowOf(bandOf(columnIndex), rowIndex)
|
|
8320
8562
|
};
|
|
8321
8563
|
if (cell?.hidden) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8322
8564
|
"aria-hidden": "true",
|
|
@@ -8366,11 +8608,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
8366
8608
|
role: "row",
|
|
8367
8609
|
"aria-hidden": "true",
|
|
8368
8610
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
8369
|
-
children:
|
|
8611
|
+
children: placed.groups.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8370
8612
|
className: heatmap_chart_module_default["heatmap-chart__group-label"],
|
|
8371
8613
|
style: {
|
|
8372
8614
|
gridColumn: `${group.line} / span ${group.span}`,
|
|
8373
|
-
gridRow:
|
|
8615
|
+
gridRow: dataRowOf(group.band, rows)
|
|
8374
8616
|
},
|
|
8375
8617
|
children: group.label
|
|
8376
8618
|
}, `group-${groupIndex}`))
|
|
@@ -11472,8 +11714,8 @@ const SUBPIXEL_TOLERANCE = .5;
|
|
|
11472
11714
|
* depends on `--a8c-charts-dimension-leaderboard-row-gap`, label wrapping, and
|
|
11473
11715
|
* whatever a caller renders as a label, so any restated number would drift.
|
|
11474
11716
|
*
|
|
11475
|
-
* Every row is a direct grid child marked with `data-row-index`;
|
|
11476
|
-
*
|
|
11717
|
+
* Every row is a `listitem` div, a direct grid child marked with `data-row-index`;
|
|
11718
|
+
* interactive rows hold a button inside it.
|
|
11477
11719
|
*
|
|
11478
11720
|
* @param enabled - Whether to measure at all. When false every row fits.
|
|
11479
11721
|
* @param rowCount - Total number of rows rendered.
|
|
@@ -11605,6 +11847,7 @@ var leaderboard_chart_module_default = {
|
|
|
11605
11847
|
"interactiveRow": "a8ccharts-GovfoW-interactiveRow",
|
|
11606
11848
|
"is-overlay": "a8ccharts-GovfoW-is-overlay",
|
|
11607
11849
|
"label": "a8ccharts-GovfoW-label",
|
|
11850
|
+
"layeredRow": "a8ccharts-GovfoW-layeredRow",
|
|
11608
11851
|
"leaderboardChart": "a8ccharts-GovfoW-leaderboardChart",
|
|
11609
11852
|
"leaderboardChart__content": "a8ccharts-GovfoW-leaderboardChart__content",
|
|
11610
11853
|
"leaderboardChart__content--fit": "a8ccharts-GovfoW-leaderboardChart__content--fit",
|
|
@@ -11613,6 +11856,8 @@ var leaderboard_chart_module_default = {
|
|
|
11613
11856
|
"overlap": "a8ccharts-GovfoW-overlap",
|
|
11614
11857
|
"overlayLabel": "a8ccharts-GovfoW-overlayLabel",
|
|
11615
11858
|
"row": "a8ccharts-GovfoW-row",
|
|
11859
|
+
"rowButton": "a8ccharts-GovfoW-rowButton",
|
|
11860
|
+
"rowItem": "a8ccharts-GovfoW-rowItem",
|
|
11616
11861
|
"stretch": "a8ccharts-GovfoW-stretch",
|
|
11617
11862
|
"valueContainer": "a8ccharts-GovfoW-valueContainer"
|
|
11618
11863
|
};
|
|
@@ -11663,6 +11908,16 @@ const defaultDeltaFormatter = (value) => {
|
|
|
11663
11908
|
const getBarWidth = (share) => `calc(${share}% - var(--a8c-charts-dimension-leaderboard-bar-hover-inset, 0px) * ${share} / 100)`;
|
|
11664
11909
|
const hasPreviousValue = (entry) => entry.previousValue != null && entry.previousShare != null;
|
|
11665
11910
|
const hasDeltaValue = (entry) => hasPreviousValue(entry) && entry.delta != null;
|
|
11911
|
+
/**
|
|
11912
|
+
* A layered row's cell that takes pointer events of its own (a value tooltip)
|
|
11913
|
+
* sits above the row button; pass its clicks on so they still drill down.
|
|
11914
|
+
*
|
|
11915
|
+
* @param event - The click on the row.
|
|
11916
|
+
*/
|
|
11917
|
+
function forwardCellClickToRowButton(event) {
|
|
11918
|
+
if (event.target.closest("a, button")) return;
|
|
11919
|
+
event.currentTarget.querySelector(":scope > button")?.click();
|
|
11920
|
+
}
|
|
11666
11921
|
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, {
|
|
11667
11922
|
className: leaderboard_chart_module_default.label,
|
|
11668
11923
|
children: label
|
|
@@ -11715,9 +11970,10 @@ const BarWithLabel = ({ entry, withComparison, withOverlayLabel, primaryColor, s
|
|
|
11715
11970
|
* @param props.children - Child components for composition API
|
|
11716
11971
|
* @param props.className - Additional CSS class name
|
|
11717
11972
|
* @param props.style - Custom styling for the chart container
|
|
11973
|
+
* @param props.ariaLabel - Accessible name for the list, defaulting to "Leaderboard chart"
|
|
11718
11974
|
* @return JSX element representing the leaderboard chart
|
|
11719
11975
|
*/
|
|
11720
|
-
const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, withComparison = false, withOverlayLabel = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, animation, loading = false, fitRows = false, showLegend = false, legend = {}, legendLabels, gap = "md", className, style, children }) => {
|
|
11976
|
+
const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propWidth, height: propHeight, withComparison = false, withOverlayLabel = false, primaryColor, secondaryColor, valueFormatter = defaultValueFormatter, deltaFormatter = defaultDeltaFormatter, animation, loading = false, fitRows = false, showLegend = false, legend = {}, legendLabels, gap = "md", ariaLabel, className, style, children }) => {
|
|
11721
11977
|
const legendInteractive = legend.interactive ?? false;
|
|
11722
11978
|
const legendPosition = legend.position ?? "bottom";
|
|
11723
11979
|
const chartId = useChartId(providedChartId);
|
|
@@ -11848,6 +12104,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
11848
12104
|
className: leaderboard_chart_module_default.emptyState,
|
|
11849
12105
|
children: getAllHiddenMessage(legendInteractive, "series")
|
|
11850
12106
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default, {
|
|
12107
|
+
role: "list",
|
|
12108
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Leaderboard chart", "jetpack-charts"),
|
|
11851
12109
|
templateColumns: "minmax(0, 1fr) auto",
|
|
11852
12110
|
rowGap: ROW_GAP,
|
|
11853
12111
|
columnGap: COLUMN_GAP,
|
|
@@ -11895,20 +12153,49 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
11895
12153
|
})
|
|
11896
12154
|
]
|
|
11897
12155
|
})] });
|
|
11898
|
-
if (entry.onClick) return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
11899
|
-
|
|
12156
|
+
if (entry.onClick && entry.hasInteractiveLabel) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12157
|
+
role: "listitem",
|
|
11900
12158
|
"data-row-index": rowIndex,
|
|
11901
12159
|
style: rowStyle,
|
|
11902
|
-
className:
|
|
11903
|
-
|
|
11904
|
-
|
|
11905
|
-
|
|
11906
|
-
|
|
11907
|
-
|
|
11908
|
-
|
|
11909
|
-
|
|
12160
|
+
className: leaderboard_chart_module_default.rowItem,
|
|
12161
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12162
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow, leaderboard_chart_module_default.layeredRow),
|
|
12163
|
+
onClick: forwardCellClickToRowButton,
|
|
12164
|
+
children: [
|
|
12165
|
+
rowCells,
|
|
12166
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
12167
|
+
type: "button",
|
|
12168
|
+
className: leaderboard_chart_module_default.rowButton,
|
|
12169
|
+
onClick: entry.onClick,
|
|
12170
|
+
"aria-label": entry.ariaLabel
|
|
12171
|
+
}),
|
|
12172
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_icons.Icon, {
|
|
12173
|
+
className: leaderboard_chart_module_default.chevron,
|
|
12174
|
+
icon: _wordpress_icons.chevronRight,
|
|
12175
|
+
size: 24
|
|
12176
|
+
})
|
|
12177
|
+
]
|
|
12178
|
+
})
|
|
12179
|
+
}, entry.id);
|
|
12180
|
+
if (entry.onClick) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12181
|
+
role: "listitem",
|
|
12182
|
+
"data-row-index": rowIndex,
|
|
12183
|
+
style: rowStyle,
|
|
12184
|
+
className: leaderboard_chart_module_default.rowItem,
|
|
12185
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
12186
|
+
type: "button",
|
|
12187
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.row, leaderboard_chart_module_default.interactiveRow),
|
|
12188
|
+
onClick: entry.onClick,
|
|
12189
|
+
"aria-label": entry.ariaLabel,
|
|
12190
|
+
children: [rowCells, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_icons.Icon, {
|
|
12191
|
+
className: leaderboard_chart_module_default.chevron,
|
|
12192
|
+
icon: _wordpress_icons.chevronRight,
|
|
12193
|
+
size: 24
|
|
12194
|
+
})]
|
|
12195
|
+
})
|
|
11910
12196
|
}, entry.id);
|
|
11911
12197
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12198
|
+
role: "listitem",
|
|
11912
12199
|
"data-row-index": rowIndex,
|
|
11913
12200
|
style: rowStyle,
|
|
11914
12201
|
className: leaderboard_chart_module_default.row,
|
|
@@ -11928,6 +12215,212 @@ LeaderboardChartWithProvider.displayName = "LeaderboardChart";
|
|
|
11928
12215
|
const LeaderboardChart = attachSubComponents(LeaderboardChartWithProvider, { Legend });
|
|
11929
12216
|
const LeaderboardChartResponsive = attachSubComponents(withResponsive(LeaderboardChartWithProvider), { Legend });
|
|
11930
12217
|
//#endregion
|
|
12218
|
+
//#region src/charts/private/pie-keyboard-navigation/order-arcs-for-navigation.ts
|
|
12219
|
+
/**
|
|
12220
|
+
* Orders arcs the way they appear: clockwise from 12 o'clock, which for a semi-circle is left to right.
|
|
12221
|
+
*
|
|
12222
|
+
* @param arcs - Arcs from visx's `pie` factory, in data order.
|
|
12223
|
+
* @return A copy of `arcs` sorted by angular midpoint.
|
|
12224
|
+
*/
|
|
12225
|
+
const orderArcsForNavigation = (arcs) => [...arcs].sort((a, b) => a.startAngle + a.endAngle - (b.startAngle + b.endAngle));
|
|
12226
|
+
//#endregion
|
|
12227
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-selection-announcement.tsx
|
|
12228
|
+
const PieSelectionAnnouncement = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.VisuallyHidden, {
|
|
12229
|
+
role: "status",
|
|
12230
|
+
"aria-atomic": "true",
|
|
12231
|
+
children: data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LabelValueContent, { data })
|
|
12232
|
+
});
|
|
12233
|
+
//#endregion
|
|
12234
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-tooltip.tsx
|
|
12235
|
+
const TOOLTIP_BOX_STYLE = { zIndex: 3 };
|
|
12236
|
+
const PieTooltip = ({ top, left, selectedIndex, tooltipRef, children }) => {
|
|
12237
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
12238
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
12239
|
+
top,
|
|
12240
|
+
left,
|
|
12241
|
+
style: TOOLTIP_BOX_STYLE,
|
|
12242
|
+
children: selectedIndex === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12243
|
+
className: standaloneScopeClass,
|
|
12244
|
+
role: "tooltip",
|
|
12245
|
+
children
|
|
12246
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12247
|
+
ref: tooltipRef,
|
|
12248
|
+
tabIndex: -1,
|
|
12249
|
+
role: "tooltip",
|
|
12250
|
+
"aria-atomic": "true",
|
|
12251
|
+
className: standaloneScopeClass,
|
|
12252
|
+
children
|
|
12253
|
+
}, `chart-tooltip-${selectedIndex}`)
|
|
12254
|
+
});
|
|
12255
|
+
};
|
|
12256
|
+
//#endregion
|
|
12257
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-selection-output.tsx
|
|
12258
|
+
/**
|
|
12259
|
+
* Reports the selected segment: a focused tooltip for a keyboard selection, a pointer tooltip on hover, or a screen reader announcement without tooltips.
|
|
12260
|
+
*
|
|
12261
|
+
* @param {PieSelectionOutputProps} props - Component props
|
|
12262
|
+
* @return {JSX.Element} The announcement region and the tooltip, if any
|
|
12263
|
+
*/
|
|
12264
|
+
const PieSelectionOutput = ({ withTooltips, selectedIndex, selectedData, keyboardTooltipAnchor, pointerTooltip, chartRef, svgRef, tooltipRef, renderTooltip }) => {
|
|
12265
|
+
const [svgOffset, setSvgOffset] = (0, react.useState)({
|
|
12266
|
+
top: 0,
|
|
12267
|
+
left: 0
|
|
12268
|
+
});
|
|
12269
|
+
const showKeyboardTooltip = withTooltips && selectedData && keyboardTooltipAnchor;
|
|
12270
|
+
(0, react.useLayoutEffect)(() => {
|
|
12271
|
+
const chartBounds = chartRef.current?.getBoundingClientRect();
|
|
12272
|
+
const svgBounds = svgRef.current?.getBoundingClientRect();
|
|
12273
|
+
if (!showKeyboardTooltip || !chartBounds || !svgBounds) return;
|
|
12274
|
+
const top = svgBounds.top - chartBounds.top;
|
|
12275
|
+
const left = svgBounds.left - chartBounds.left;
|
|
12276
|
+
setSvgOffset((current) => current.top === top && current.left === left ? current : {
|
|
12277
|
+
top,
|
|
12278
|
+
left
|
|
12279
|
+
});
|
|
12280
|
+
});
|
|
12281
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
12282
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionAnnouncement, { data: withTooltips ? void 0 : selectedData }),
|
|
12283
|
+
showKeyboardTooltip && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieTooltip, {
|
|
12284
|
+
top: svgOffset.top + keyboardTooltipAnchor.top,
|
|
12285
|
+
left: svgOffset.left + keyboardTooltipAnchor.left,
|
|
12286
|
+
selectedIndex,
|
|
12287
|
+
tooltipRef,
|
|
12288
|
+
children: renderTooltip({ tooltipData: selectedData })
|
|
12289
|
+
}),
|
|
12290
|
+
withTooltips && !selectedData && pointerTooltip?.data && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieTooltip, {
|
|
12291
|
+
top: pointerTooltip.top,
|
|
12292
|
+
left: pointerTooltip.left,
|
|
12293
|
+
children: renderTooltip({ tooltipData: pointerTooltip.data })
|
|
12294
|
+
})
|
|
12295
|
+
] });
|
|
12296
|
+
};
|
|
12297
|
+
//#endregion
|
|
12298
|
+
//#region src/charts/private/pie-keyboard-navigation/pie-keyboard-navigation.module.scss
|
|
12299
|
+
var pie_keyboard_navigation_module_default = {
|
|
12300
|
+
"selected-ring__contrast": "a8ccharts-V2HDKq-selected-ring__contrast",
|
|
12301
|
+
"selected-ring__focus": "a8ccharts-V2HDKq-selected-ring__focus"
|
|
12302
|
+
};
|
|
12303
|
+
//#endregion
|
|
12304
|
+
//#region src/charts/private/pie-keyboard-navigation/selected-segment-ring.tsx
|
|
12305
|
+
/**
|
|
12306
|
+
* Encodes `value` for an SVG id, losslessly so distinct chart ids never share a clip path.
|
|
12307
|
+
*
|
|
12308
|
+
* @param value - Any string.
|
|
12309
|
+
* @return `value` with each character outside `[A-Za-z0-9-]` written as `_<hex code point>_`.
|
|
12310
|
+
*/
|
|
12311
|
+
const toSvgId = (value) => Array.from(value, (character) => /[A-Za-z0-9-]/.test(character) ? character : `_${character.codePointAt(0)?.toString(16)}_`).join("");
|
|
12312
|
+
/**
|
|
12313
|
+
* Marks the selected segment with a two-tone ring drawn inside its edge, so the SVG edge cannot cut it off.
|
|
12314
|
+
*
|
|
12315
|
+
* @param {SelectedSegmentRingProps} props - Component props
|
|
12316
|
+
* @return {JSX.Element} The ring
|
|
12317
|
+
*/
|
|
12318
|
+
const SelectedSegmentRing = ({ chartId, d }) => {
|
|
12319
|
+
const clipId = `pie-selected-ring-clip-${toSvgId(chartId)}`;
|
|
12320
|
+
const clipPath = `url(#${clipId})`;
|
|
12321
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
12322
|
+
pointerEvents: "none",
|
|
12323
|
+
"aria-hidden": "true",
|
|
12324
|
+
children: [
|
|
12325
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("clipPath", {
|
|
12326
|
+
id: clipId,
|
|
12327
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d })
|
|
12328
|
+
}),
|
|
12329
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12330
|
+
d,
|
|
12331
|
+
clipPath,
|
|
12332
|
+
className: pie_keyboard_navigation_module_default["selected-ring__contrast"]
|
|
12333
|
+
}),
|
|
12334
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12335
|
+
d,
|
|
12336
|
+
clipPath,
|
|
12337
|
+
className: pie_keyboard_navigation_module_default["selected-ring__focus"]
|
|
12338
|
+
})
|
|
12339
|
+
]
|
|
12340
|
+
});
|
|
12341
|
+
};
|
|
12342
|
+
//#endregion
|
|
12343
|
+
//#region src/charts/private/pie-keyboard-navigation/use-pie-keyboard-navigation.ts
|
|
12344
|
+
const usePieKeyboardNavigation = ({ navigationArcs, withTooltips, tooltipOffsetX, tooltipOffsetY }) => {
|
|
12345
|
+
const chartRef = (0, react.useRef)(null);
|
|
12346
|
+
const svgRef = (0, react.useRef)(null);
|
|
12347
|
+
const [selectedIndex, setSelectedIndex] = (0, react.useState)(void 0);
|
|
12348
|
+
const [isNavigating, setIsNavigating] = (0, react.useState)(false);
|
|
12349
|
+
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
12350
|
+
const { tooltipRef: focusTooltip, onChartFocus, onChartBlur, onChartKeyDown, onChartPointerMove } = useKeyboardNavigation({
|
|
12351
|
+
selectedIndex,
|
|
12352
|
+
setSelectedIndex,
|
|
12353
|
+
isNavigating,
|
|
12354
|
+
setIsNavigating,
|
|
12355
|
+
chartRef,
|
|
12356
|
+
totalPoints: navigationArcs.length,
|
|
12357
|
+
visibleSeriesKey: JSON.stringify(navigationArcs.map((arcDatum) => arcDatum.data.label))
|
|
12358
|
+
});
|
|
12359
|
+
const selectedArc = selectedIndex === void 0 ? void 0 : navigationArcs[selectedIndex];
|
|
12360
|
+
const keyboardTooltip = (0, react.useRef)(null);
|
|
12361
|
+
const tooltipLostFocus = (0, react.useRef)(false);
|
|
12362
|
+
const tooltipRef = (0, react.useCallback)((element) => {
|
|
12363
|
+
if (element) {
|
|
12364
|
+
keyboardTooltip.current = element;
|
|
12365
|
+
focusTooltip(element);
|
|
12366
|
+
} else if (keyboardTooltip.current?.ownerDocument.activeElement === keyboardTooltip.current) tooltipLostFocus.current = true;
|
|
12367
|
+
}, [focusTooltip]);
|
|
12368
|
+
(0, react.useLayoutEffect)(() => {
|
|
12369
|
+
if (!tooltipLostFocus.current) return;
|
|
12370
|
+
tooltipLostFocus.current = false;
|
|
12371
|
+
const { activeElement, body } = chartRef.current?.ownerDocument ?? document;
|
|
12372
|
+
if (activeElement === null || activeElement === body) chartRef.current?.focus();
|
|
12373
|
+
});
|
|
12374
|
+
const getSegmentHandlers = (data, navigationIndex) => ({
|
|
12375
|
+
onMouseMove: (event) => {
|
|
12376
|
+
onChartPointerMove(navigationIndex);
|
|
12377
|
+
if (!withTooltips) return;
|
|
12378
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
12379
|
+
if (!bounds) return;
|
|
12380
|
+
showTooltip({
|
|
12381
|
+
tooltipData: data,
|
|
12382
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
12383
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
12384
|
+
});
|
|
12385
|
+
},
|
|
12386
|
+
onMouseLeave: withTooltips ? hideTooltip : void 0
|
|
12387
|
+
});
|
|
12388
|
+
return {
|
|
12389
|
+
chartRef,
|
|
12390
|
+
svgRef,
|
|
12391
|
+
selectedArc,
|
|
12392
|
+
getSegmentHandlers,
|
|
12393
|
+
getKeyboardTooltipAnchor: (0, react.useCallback)((originX, originY, [x, y]) => withTooltips ? {
|
|
12394
|
+
left: originX + x + tooltipOffsetX,
|
|
12395
|
+
top: originY + y + tooltipOffsetY
|
|
12396
|
+
} : void 0, [
|
|
12397
|
+
withTooltips,
|
|
12398
|
+
tooltipOffsetX,
|
|
12399
|
+
tooltipOffsetY
|
|
12400
|
+
]),
|
|
12401
|
+
selectionOutputProps: {
|
|
12402
|
+
withTooltips,
|
|
12403
|
+
selectedIndex,
|
|
12404
|
+
selectedData: selectedArc?.data,
|
|
12405
|
+
chartRef,
|
|
12406
|
+
svgRef,
|
|
12407
|
+
tooltipRef,
|
|
12408
|
+
pointerTooltip: tooltipOpen ? {
|
|
12409
|
+
data: tooltipData,
|
|
12410
|
+
left: tooltipLeft || 0,
|
|
12411
|
+
top: tooltipTop || 0
|
|
12412
|
+
} : void 0
|
|
12413
|
+
},
|
|
12414
|
+
chartProps: {
|
|
12415
|
+
role: "application",
|
|
12416
|
+
tabIndex: 0,
|
|
12417
|
+
onKeyDown: onChartKeyDown,
|
|
12418
|
+
onFocus: onChartFocus,
|
|
12419
|
+
onBlur: onChartBlur
|
|
12420
|
+
}
|
|
12421
|
+
};
|
|
12422
|
+
};
|
|
12423
|
+
//#endregion
|
|
11931
12424
|
//#region src/charts/private/radial-wipe-animation/radial-wipe-animation.tsx
|
|
11932
12425
|
/**
|
|
11933
12426
|
* Renders a SVG mask that creates a radial wipe animation effect.
|
|
@@ -11968,6 +12461,7 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
|
|
|
11968
12461
|
//#endregion
|
|
11969
12462
|
//#region src/charts/pie-chart/pie-chart.module.scss
|
|
11970
12463
|
var pie_chart_module_default = {
|
|
12464
|
+
"pie-chart": "a8ccharts-gnszbG-pie-chart",
|
|
11971
12465
|
"pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
|
|
11972
12466
|
"pie-chart__label-text": "a8ccharts-gnszbG-pie-chart__label-text",
|
|
11973
12467
|
"pie-chart__label-text--black": "a8ccharts-gnszbG-pie-chart__label-text--black",
|
|
@@ -12023,20 +12517,13 @@ const LABEL_TEXT_MODIFIER = {
|
|
|
12023
12517
|
* @param {PieChartProps} props - Component props
|
|
12024
12518
|
* @return {JSX.Element} The rendered chart component
|
|
12025
12519
|
*/
|
|
12026
|
-
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" }) => {
|
|
12520
|
+
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" }) => {
|
|
12027
12521
|
const legendInteractive = legend.interactive ?? false;
|
|
12028
12522
|
const legendPosition = legend.position ?? "bottom";
|
|
12029
12523
|
const providerTheme = useGlobalChartsTheme();
|
|
12030
12524
|
const chartId = useChartId(providedChartId);
|
|
12031
|
-
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
12032
|
-
const standaloneScopeClass = useStandaloneScopeClass();
|
|
12033
|
-
const containerRef = (0, react.useRef)(null);
|
|
12034
12525
|
const rootRef = (0, react.useRef)(null);
|
|
12035
12526
|
const [labelRoles, setLabelRoles] = (0, react.useState)(null);
|
|
12036
|
-
const onMouseLeave = (0, react.useCallback)(() => {
|
|
12037
|
-
if (!withTooltips) return;
|
|
12038
|
-
hideTooltip();
|
|
12039
|
-
}, [withTooltips, hideTooltip]);
|
|
12040
12527
|
const { getElementStyles, isSeriesVisible, isColorPaletteResolved } = useGlobalChartsContext();
|
|
12041
12528
|
const { isValid, message } = validateData$1(data);
|
|
12042
12529
|
(0, react.useLayoutEffect)(() => {
|
|
@@ -12080,13 +12567,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
12080
12567
|
metadata: chartMetadata
|
|
12081
12568
|
});
|
|
12082
12569
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
12083
|
-
|
|
12084
|
-
className: (0, clsx.default)("pie-chart", pie_chart_module_default["pie-chart"], className),
|
|
12085
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12086
|
-
className: pie_chart_module_default["error-message"],
|
|
12087
|
-
children: message
|
|
12088
|
-
})
|
|
12089
|
-
});
|
|
12570
|
+
const wipeMask = animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null;
|
|
12090
12571
|
const padAngle = gapScale * (2 * Math.PI / data.length);
|
|
12091
12572
|
const dataWithIndex = visibleData.map((d) => {
|
|
12092
12573
|
const originalIndex = data.findIndex((item) => item.label === d.label);
|
|
@@ -12104,6 +12585,24 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
12104
12585
|
}).color;
|
|
12105
12586
|
}
|
|
12106
12587
|
};
|
|
12588
|
+
const arcs = (0, _visx_shape.pie)({
|
|
12589
|
+
value: accessors.value,
|
|
12590
|
+
padAngle
|
|
12591
|
+
})(dataWithIndex);
|
|
12592
|
+
const navigationArcs = orderArcsForNavigation(arcs);
|
|
12593
|
+
const { chartRef, svgRef, selectedArc, getSegmentHandlers, getKeyboardTooltipAnchor, selectionOutputProps, chartProps } = usePieKeyboardNavigation({
|
|
12594
|
+
navigationArcs,
|
|
12595
|
+
withTooltips,
|
|
12596
|
+
tooltipOffsetX,
|
|
12597
|
+
tooltipOffsetY
|
|
12598
|
+
});
|
|
12599
|
+
if (!isValid) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12600
|
+
className: (0, clsx.default)("pie-chart", pie_chart_module_default["pie-chart"], className),
|
|
12601
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12602
|
+
className: pie_chart_module_default["error-message"],
|
|
12603
|
+
children: message
|
|
12604
|
+
})
|
|
12605
|
+
});
|
|
12107
12606
|
const legendElement = showLegend && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
|
|
12108
12607
|
orientation: legend.orientation ?? "horizontal",
|
|
12109
12608
|
position: legendPosition,
|
|
@@ -12142,102 +12641,96 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
12142
12641
|
const innerRadius = thickness === 0 ? 0 : outerRadius * (1 - thickness);
|
|
12143
12642
|
const maxCornerRadius = (outerRadius - innerRadius) / 2;
|
|
12144
12643
|
const cornerRadius = cornerScale ? Math.min(cornerScale * outerRadius, maxCornerRadius) : 0;
|
|
12644
|
+
const path = (0, _visx_shape.arc)({
|
|
12645
|
+
innerRadius,
|
|
12646
|
+
outerRadius,
|
|
12647
|
+
cornerRadius
|
|
12648
|
+
});
|
|
12649
|
+
const svgLabelSmall = providerTheme.svgLabelSmall;
|
|
12650
|
+
const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
|
|
12651
|
+
const renderLabel = (arcDatum, index) => {
|
|
12652
|
+
if (arcDatum.endAngle - arcDatum.startAngle < .25) return null;
|
|
12653
|
+
const [centroidX, centroidY] = path.centroid(arcDatum);
|
|
12654
|
+
const backgroundWidth = (0, _visx_text.getStringWidth)(arcDatum.data.label, {
|
|
12655
|
+
fontSize,
|
|
12656
|
+
fontFamily: svgLabelSmall?.fontFamily,
|
|
12657
|
+
fontWeight: svgLabelSmall?.fontWeight
|
|
12658
|
+
}) + 12;
|
|
12659
|
+
const backgroundHeight = fontSize + 12;
|
|
12660
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
12661
|
+
className: pie_chart_module_default["pie-chart__label-plate"],
|
|
12662
|
+
x: centroidX - backgroundWidth / 2,
|
|
12663
|
+
y: centroidY - backgroundHeight / 2,
|
|
12664
|
+
width: backgroundWidth,
|
|
12665
|
+
height: backgroundHeight,
|
|
12666
|
+
rx: 4,
|
|
12667
|
+
ry: 4,
|
|
12668
|
+
pointerEvents: "none"
|
|
12669
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
12670
|
+
className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"], LABEL_TEXT_MODIFIER[pickLabelTextColor(accessors.fill(arcDatum.data), labelRoles, "label-inverse")]),
|
|
12671
|
+
x: centroidX,
|
|
12672
|
+
y: centroidY,
|
|
12673
|
+
dy: ".33em",
|
|
12674
|
+
fontSize,
|
|
12675
|
+
textAnchor: "middle",
|
|
12676
|
+
pointerEvents: "none",
|
|
12677
|
+
children: arcDatum.data.label
|
|
12678
|
+
})] }, `label-${index}`);
|
|
12679
|
+
};
|
|
12145
12680
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
12146
|
-
ref:
|
|
12681
|
+
ref: chartRef,
|
|
12147
12682
|
className: pie_chart_module_default["pie-chart__plot"],
|
|
12683
|
+
...chartProps,
|
|
12684
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Pie chart", "jetpack-charts"),
|
|
12148
12685
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
12686
|
+
ref: svgRef,
|
|
12149
12687
|
viewBox: `0 0 ${width} ${height}`,
|
|
12150
12688
|
preserveAspectRatio: "xMidYMid meet",
|
|
12151
12689
|
width,
|
|
12152
12690
|
height,
|
|
12153
|
-
children: [
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
|
|
12158
|
-
|
|
12159
|
-
|
|
12160
|
-
|
|
12161
|
-
|
|
12162
|
-
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
|
|
12171
|
-
|
|
12172
|
-
|
|
12173
|
-
|
|
12174
|
-
|
|
12175
|
-
|
|
12176
|
-
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
12185
|
-
|
|
12186
|
-
|
|
12187
|
-
|
|
12188
|
-
|
|
12189
|
-
|
|
12190
|
-
|
|
12191
|
-
|
|
12192
|
-
|
|
12193
|
-
|
|
12194
|
-
|
|
12195
|
-
|
|
12196
|
-
groupProps.onMouseMove = handleMouseMove;
|
|
12197
|
-
groupProps.onMouseLeave = onMouseLeave;
|
|
12198
|
-
}
|
|
12199
|
-
const svgLabelSmall = providerTheme.svgLabelSmall;
|
|
12200
|
-
const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
|
|
12201
|
-
const backgroundWidth = (0, _visx_text.getStringWidth)(arc.data.label, {
|
|
12202
|
-
fontSize,
|
|
12203
|
-
fontFamily: svgLabelSmall?.fontFamily,
|
|
12204
|
-
fontWeight: svgLabelSmall?.fontWeight
|
|
12205
|
-
}) + 12;
|
|
12206
|
-
const backgroundHeight = fontSize + 12;
|
|
12207
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
12208
|
-
...groupProps,
|
|
12209
|
-
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", {
|
|
12210
|
-
className: pie_chart_module_default["pie-chart__label-plate"],
|
|
12211
|
-
x: centroidX - backgroundWidth / 2,
|
|
12212
|
-
y: centroidY - backgroundHeight / 2,
|
|
12213
|
-
width: backgroundWidth,
|
|
12214
|
-
height: backgroundHeight,
|
|
12215
|
-
rx: 4,
|
|
12216
|
-
ry: 4,
|
|
12217
|
-
pointerEvents: "none"
|
|
12218
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
12219
|
-
className: (0, clsx.default)(pie_chart_module_default["pie-chart__label-text"], LABEL_TEXT_MODIFIER[pickLabelTextColor(fill, labelRoles, "label-inverse")]),
|
|
12220
|
-
x: centroidX,
|
|
12221
|
-
y: centroidY,
|
|
12222
|
-
dy: ".33em",
|
|
12223
|
-
fontSize,
|
|
12224
|
-
textAnchor: "middle",
|
|
12225
|
-
pointerEvents: "none",
|
|
12226
|
-
children: arc.data.label
|
|
12227
|
-
})] })]
|
|
12228
|
-
}, `arc-${index}`);
|
|
12229
|
-
});
|
|
12230
|
-
}
|
|
12231
|
-
}), !allSegmentsHidden && svgChildren]
|
|
12232
|
-
})]
|
|
12233
|
-
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
12234
|
-
top: tooltipTop || 0,
|
|
12235
|
-
left: tooltipLeft || 0,
|
|
12236
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12237
|
-
className: standaloneScopeClass,
|
|
12238
|
-
role: "tooltip",
|
|
12239
|
-
children: renderTooltip({ tooltipData })
|
|
12240
|
-
})
|
|
12691
|
+
children: [
|
|
12692
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
|
|
12693
|
+
id: `radial-wipe-${chartId}`,
|
|
12694
|
+
radius: outerRadius,
|
|
12695
|
+
innerRadius
|
|
12696
|
+
}) }),
|
|
12697
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12698
|
+
top: centerY,
|
|
12699
|
+
left: centerX,
|
|
12700
|
+
mask: wipeMask,
|
|
12701
|
+
children: allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
|
|
12702
|
+
x: 0,
|
|
12703
|
+
y: 0,
|
|
12704
|
+
width,
|
|
12705
|
+
height,
|
|
12706
|
+
children: getAllHiddenMessage(legendInteractive, "segments")
|
|
12707
|
+
}) : arcs.map((arcDatum, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
|
|
12708
|
+
...getSegmentHandlers(arcDatum.data, navigationArcs.indexOf(arcDatum)),
|
|
12709
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12710
|
+
d: path(arcDatum) || "",
|
|
12711
|
+
fill: accessors.fill(arcDatum.data)
|
|
12712
|
+
})
|
|
12713
|
+
}, `arc-${index}`))
|
|
12714
|
+
}),
|
|
12715
|
+
selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12716
|
+
top: centerY,
|
|
12717
|
+
left: centerX,
|
|
12718
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
|
|
12719
|
+
chartId,
|
|
12720
|
+
d: path(selectedArc) || ""
|
|
12721
|
+
})
|
|
12722
|
+
}),
|
|
12723
|
+
!allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
|
|
12724
|
+
top: centerY,
|
|
12725
|
+
left: centerX,
|
|
12726
|
+
mask: wipeMask,
|
|
12727
|
+
children: [showLabels && arcs.map(renderLabel), svgChildren]
|
|
12728
|
+
})
|
|
12729
|
+
]
|
|
12730
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionOutput, {
|
|
12731
|
+
...selectionOutputProps,
|
|
12732
|
+
keyboardTooltipAnchor: selectedArc && getKeyboardTooltipAnchor(centerX, centerY, path.centroid(selectedArc)),
|
|
12733
|
+
renderTooltip
|
|
12241
12734
|
})]
|
|
12242
12735
|
});
|
|
12243
12736
|
}
|
|
@@ -12305,32 +12798,10 @@ const validateData = (data) => {
|
|
|
12305
12798
|
message: ""
|
|
12306
12799
|
};
|
|
12307
12800
|
};
|
|
12308
|
-
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" }) => {
|
|
12801
|
+
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" }) => {
|
|
12309
12802
|
const legendInteractive = legend.interactive ?? false;
|
|
12310
12803
|
const legendPosition = legend.position ?? "bottom";
|
|
12311
12804
|
const chartId = useChartId(providedChartId);
|
|
12312
|
-
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
12313
|
-
const standaloneScopeClass = useStandaloneScopeClass();
|
|
12314
|
-
const containerRef = (0, react.useRef)(null);
|
|
12315
|
-
const handleMouseMove = (0, react.useCallback)((event, arc) => {
|
|
12316
|
-
const bounds = containerRef.current?.getBoundingClientRect();
|
|
12317
|
-
if (!bounds) return;
|
|
12318
|
-
showTooltip({
|
|
12319
|
-
tooltipData: arc.data,
|
|
12320
|
-
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
12321
|
-
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
12322
|
-
});
|
|
12323
|
-
}, [
|
|
12324
|
-
showTooltip,
|
|
12325
|
-
tooltipOffsetX,
|
|
12326
|
-
tooltipOffsetY
|
|
12327
|
-
]);
|
|
12328
|
-
const handleMouseLeave = (0, react.useCallback)(() => {
|
|
12329
|
-
hideTooltip();
|
|
12330
|
-
}, [hideTooltip]);
|
|
12331
|
-
const handleArcMouseMove = (0, react.useCallback)((arc) => (event) => {
|
|
12332
|
-
handleMouseMove(event, arc);
|
|
12333
|
-
}, [handleMouseMove]);
|
|
12334
12805
|
const { isValid, message } = validateData(data);
|
|
12335
12806
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
12336
12807
|
const dataWithPercentages = useDataWithPercentages(data);
|
|
@@ -12364,7 +12835,31 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12364
12835
|
metadata: chartMetadata
|
|
12365
12836
|
});
|
|
12366
12837
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
12838
|
+
const wipeMask = animation && !prefersReducedMotion ? `url(#radial-wipe-${chartId})` : null;
|
|
12367
12839
|
const effectiveWidth = propWidth || DEFAULT_WIDTH$1;
|
|
12840
|
+
const dataWithIndex = visibleData.map((d) => {
|
|
12841
|
+
const originalIndex = data.findIndex((item) => item.label === d.label);
|
|
12842
|
+
return {
|
|
12843
|
+
...d,
|
|
12844
|
+
index: originalIndex >= 0 ? originalIndex : 0
|
|
12845
|
+
};
|
|
12846
|
+
});
|
|
12847
|
+
const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2;
|
|
12848
|
+
const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2;
|
|
12849
|
+
const arcs = (0, _visx_shape.pie)({
|
|
12850
|
+
value: accessors.value,
|
|
12851
|
+
sort: accessors.sort,
|
|
12852
|
+
padAngle: PAD_ANGLE,
|
|
12853
|
+
startAngle,
|
|
12854
|
+
endAngle
|
|
12855
|
+
})(dataWithIndex);
|
|
12856
|
+
const navigationArcs = orderArcsForNavigation(arcs);
|
|
12857
|
+
const { chartRef, svgRef, selectedArc, getSegmentHandlers, getKeyboardTooltipAnchor, selectionOutputProps, chartProps } = usePieKeyboardNavigation({
|
|
12858
|
+
navigationArcs,
|
|
12859
|
+
withTooltips,
|
|
12860
|
+
tooltipOffsetX,
|
|
12861
|
+
tooltipOffsetY
|
|
12862
|
+
});
|
|
12368
12863
|
if (!isValid) {
|
|
12369
12864
|
const errorWidth = propHeight ? Math.min(propWidth || propHeight * 2, propHeight * 2) : effectiveWidth;
|
|
12370
12865
|
const errorHeight = errorWidth / 2;
|
|
@@ -12383,15 +12878,6 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12383
12878
|
})
|
|
12384
12879
|
});
|
|
12385
12880
|
}
|
|
12386
|
-
const dataWithIndex = visibleData.map((d) => {
|
|
12387
|
-
const originalIndex = data.findIndex((item) => item.label === d.label);
|
|
12388
|
-
return {
|
|
12389
|
-
...d,
|
|
12390
|
-
index: originalIndex >= 0 ? originalIndex : 0
|
|
12391
|
-
};
|
|
12392
|
-
});
|
|
12393
|
-
const startAngle = clockwise ? -Math.PI / 2 : Math.PI / 2;
|
|
12394
|
-
const endAngle = clockwise ? Math.PI / 2 : -Math.PI / 2;
|
|
12395
12881
|
const legendElement = showLegend && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Legend, {
|
|
12396
12882
|
orientation: legend.orientation ?? "horizontal",
|
|
12397
12883
|
position: legendPosition,
|
|
@@ -12424,52 +12910,60 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12424
12910
|
const height = width / 2;
|
|
12425
12911
|
const radius = height;
|
|
12426
12912
|
const innerRadius = radius * (1 - thickness);
|
|
12913
|
+
const path = (0, _visx_shape.arc)({
|
|
12914
|
+
innerRadius,
|
|
12915
|
+
outerRadius: radius,
|
|
12916
|
+
cornerRadius: 3
|
|
12917
|
+
});
|
|
12427
12918
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
12428
|
-
ref:
|
|
12919
|
+
ref: chartRef,
|
|
12429
12920
|
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart__plot"],
|
|
12921
|
+
...chartProps,
|
|
12922
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Semi-circle chart", "jetpack-charts"),
|
|
12430
12923
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
12924
|
+
ref: svgRef,
|
|
12431
12925
|
width,
|
|
12432
12926
|
height,
|
|
12433
12927
|
viewBox: `0 0 ${width} ${height}`,
|
|
12434
|
-
children: [
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
|
|
12443
|
-
|
|
12444
|
-
|
|
12445
|
-
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
|
|
12465
|
-
|
|
12466
|
-
|
|
12467
|
-
|
|
12468
|
-
|
|
12469
|
-
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_text.Text, {
|
|
12928
|
+
children: [
|
|
12929
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RadialWipeAnimation, {
|
|
12930
|
+
id: `radial-wipe-${chartId}`,
|
|
12931
|
+
radius,
|
|
12932
|
+
innerRadius,
|
|
12933
|
+
startAngle: "-180deg",
|
|
12934
|
+
wipePercentage: 50
|
|
12935
|
+
}) }),
|
|
12936
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12937
|
+
top: height,
|
|
12938
|
+
left: width / 2,
|
|
12939
|
+
mask: wipeMask,
|
|
12940
|
+
children: allSegmentsHidden ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SvgEmptyState, {
|
|
12941
|
+
x: 0,
|
|
12942
|
+
y: -radius / 2,
|
|
12943
|
+
width,
|
|
12944
|
+
height,
|
|
12945
|
+
children: getAllHiddenMessage(legendInteractive, "segments")
|
|
12946
|
+
}) : arcs.map((arcDatum) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
|
|
12947
|
+
...getSegmentHandlers(arcDatum.data, navigationArcs.indexOf(arcDatum)),
|
|
12948
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
12949
|
+
d: path(arcDatum) || "",
|
|
12950
|
+
fill: accessors.fill(arcDatum.data)
|
|
12951
|
+
})
|
|
12952
|
+
}, arcDatum.data.label))
|
|
12953
|
+
}),
|
|
12954
|
+
selectedArc && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_group.Group, {
|
|
12955
|
+
top: height,
|
|
12956
|
+
left: width / 2,
|
|
12957
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectedSegmentRing, {
|
|
12958
|
+
chartId,
|
|
12959
|
+
d: path(selectedArc) || ""
|
|
12960
|
+
})
|
|
12961
|
+
}),
|
|
12962
|
+
!allSegmentsHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, {
|
|
12963
|
+
top: height,
|
|
12964
|
+
left: width / 2,
|
|
12965
|
+
mask: wipeMask,
|
|
12966
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_group.Group, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_text.Text, {
|
|
12473
12967
|
textAnchor: "middle",
|
|
12474
12968
|
verticalAnchor: "start",
|
|
12475
12969
|
y: -40,
|
|
@@ -12481,18 +12975,13 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
12481
12975
|
y: -20,
|
|
12482
12976
|
className: pie_semi_circle_chart_module_default.note,
|
|
12483
12977
|
children: note
|
|
12484
|
-
})] }),
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
12492
|
-
className: standaloneScopeClass,
|
|
12493
|
-
role: "tooltip",
|
|
12494
|
-
children: renderTooltip({ tooltipData })
|
|
12495
|
-
})
|
|
12978
|
+
})] }), svgChildren]
|
|
12979
|
+
})
|
|
12980
|
+
]
|
|
12981
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PieSelectionOutput, {
|
|
12982
|
+
...selectionOutputProps,
|
|
12983
|
+
keyboardTooltipAnchor: selectedArc && getKeyboardTooltipAnchor(width / 2, height, path.centroid(selectedArc)),
|
|
12984
|
+
renderTooltip
|
|
12496
12985
|
})]
|
|
12497
12986
|
});
|
|
12498
12987
|
}
|