@automattic/charts 4.1.0 → 4.2.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/TOKENS.md +7 -5
- package/dist/index.cjs +1115 -471
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +39 -1
- package/dist/index.d.cts +116 -16
- package/dist/index.d.ts +116 -16
- package/dist/index.js +1115 -473
- package/dist/index.js.map +1 -1
- package/package.json +11 -11
- package/src/charts/area-chart/area-chart.tsx +2 -1
- package/src/charts/area-chart/private/overlays.tsx +1 -2
- package/src/charts/area-chart/test/area-chart.test.tsx +31 -0
- package/src/charts/bar-chart/bar-chart.tsx +67 -17
- package/src/charts/bar-chart/index.ts +1 -1
- package/src/charts/bar-chart/private/band-highlight.tsx +85 -0
- package/src/charts/bar-chart/private/band-scale.ts +13 -0
- package/src/charts/bar-chart/private/band-tooltip.tsx +138 -0
- package/src/charts/bar-chart/private/comparison-bars.tsx +5 -10
- package/src/charts/bar-chart/private/index.ts +2 -0
- package/src/charts/bar-chart/private/test/band-highlight.test.tsx +109 -0
- package/src/charts/bar-chart/private/test/band-tooltip.test.ts +26 -0
- package/src/charts/bar-chart/private/truncated-tick-component.tsx +1 -1
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +1 -1
- package/src/charts/bar-chart/test/bar-chart-pointer-events.test.tsx +11 -23
- package/src/charts/bar-chart/test/bar-chart.test.tsx +565 -1
- package/src/charts/bar-list-chart/bar-list-chart.tsx +5 -3
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +1 -1
- package/src/charts/conversion-funnel-chart/types.ts +4 -2
- package/src/charts/geo-chart/types.ts +4 -2
- package/src/charts/heatmap-chart/{private/build-calendar-data.ts → build-calendar-data.ts} +15 -45
- package/src/charts/heatmap-chart/build-month-calendar-data.ts +124 -0
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +32 -0
- package/src/charts/heatmap-chart/heatmap-chart.tsx +191 -114
- package/src/charts/heatmap-chart/index.ts +15 -3
- package/src/charts/heatmap-chart/private/civil-day.ts +26 -0
- package/src/charts/heatmap-chart/private/column-groups.ts +71 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +19 -3
- package/src/charts/heatmap-chart/private/index.ts +2 -2
- package/src/charts/heatmap-chart/private/keyboard-navigation.ts +201 -0
- package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +37 -1
- package/src/charts/heatmap-chart/test/build-month-calendar-data.test.ts +194 -0
- package/src/charts/heatmap-chart/test/column-groups.test.ts +83 -0
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +428 -2
- package/src/charts/heatmap-chart/test/keyboard-navigation.test.ts +25 -0
- package/src/charts/heatmap-chart/test/use-calendar-heatmap-data.test.tsx +1 -1
- package/src/charts/heatmap-chart/test/use-month-calendar-heatmap-data.test.tsx +90 -0
- package/src/charts/heatmap-chart/test/zoned-calendar-data.test.ts +1 -1
- package/src/charts/heatmap-chart/test/zoned-month-calendar-data.test.ts +23 -0
- package/src/charts/heatmap-chart/types.ts +88 -3
- package/src/charts/heatmap-chart/use-calendar-heatmap-data.ts +2 -2
- package/src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts +34 -0
- package/src/charts/leaderboard-chart/types.ts +13 -14
- package/src/charts/line-chart/line-chart.tsx +3 -2
- package/src/charts/line-chart/private/line-chart-annotation.tsx +1 -1
- package/src/charts/line-chart/test/line-chart.test.tsx +31 -0
- package/src/charts/line-chart/types.ts +2 -2
- package/src/charts/private/time-axis-options.ts +1 -1
- package/src/charts/private/with-responsive/with-responsive.tsx +2 -2
- package/src/charts/private/x-zoom/test/x-zoom.test.tsx +1 -3
- package/src/charts/private/x-zoom/x-zoom.tsx +1 -2
- package/src/components/legend/private/base-legend.tsx +1 -1
- package/src/components/tooltip/accessible-tooltip.tsx +146 -37
- package/src/components/tooltip/base-tooltip.module.scss +6 -1
- package/src/components/tooltip/private/bounded-tooltip.tsx +12 -6
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +160 -0
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +17 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +29 -3
- package/src/components/tooltip/xy-chart-tooltip.tsx +11 -11
- package/src/hooks/test/use-element-size.test.tsx +13 -13
- package/src/hooks/use-xychart-theme.ts +1 -1
- package/src/index.ts +7 -1
- package/src/providers/chart-context/themes.ts +1 -0
- package/src/styles/chart-scope.scss +11 -3
- package/src/styles/test/chart-scope.test.ts +36 -2
- package/src/types.ts +6 -13
- package/src/utils/format-metric-value.ts +4 -4
- package/src/utils/get-edge-tick-widths.ts +1 -1
- package/src/utils/get-styles.ts +1 -1
- package/src/visx/types.ts +7 -10
package/dist/index.cjs
CHANGED
|
@@ -983,7 +983,8 @@ const defaultTheme = {
|
|
|
983
983
|
},
|
|
984
984
|
heatmapChart: {
|
|
985
985
|
compactCellGap: 2,
|
|
986
|
-
compactCellSize: 11
|
|
986
|
+
compactCellSize: 11,
|
|
987
|
+
groupGap: 24
|
|
987
988
|
}
|
|
988
989
|
};
|
|
989
990
|
//#endregion
|
|
@@ -2183,7 +2184,10 @@ function useChartLegendItems(data, options = {}, legendShape) {
|
|
|
2183
2184
|
}
|
|
2184
2185
|
//#endregion
|
|
2185
2186
|
//#region src/components/tooltip/base-tooltip.module.scss
|
|
2186
|
-
var base_tooltip_module_default = {
|
|
2187
|
+
var base_tooltip_module_default = {
|
|
2188
|
+
"surface": "a8ccharts--zY0xG-surface",
|
|
2189
|
+
"tooltip": "a8ccharts--zY0xG-tooltip"
|
|
2190
|
+
};
|
|
2187
2191
|
//#endregion
|
|
2188
2192
|
//#region src/components/tooltip/base-tooltip.tsx
|
|
2189
2193
|
const DefaultTooltipContent = ({ data }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
@@ -2233,7 +2237,8 @@ const findClippingAncestor = (wrapper) => {
|
|
|
2233
2237
|
/**
|
|
2234
2238
|
* Where the box goes, in wrapper coordinates. Automatic placement flips to
|
|
2235
2239
|
* the side that clips less, then clamps inside `bounds`; below-axis placement
|
|
2236
|
-
* is centered on the anchor and clamped horizontally
|
|
2240
|
+
* is centered on the anchor and clamped horizontally; beside placement preserves
|
|
2241
|
+
* the anchor's y and only flips horizontally before bounds clamping.
|
|
2237
2242
|
*
|
|
2238
2243
|
* The flip measures against the visible part of the wrapper, its intersection
|
|
2239
2244
|
* with `bounds`. Only the clamp is bound by the page: a box that fits inside the
|
|
@@ -2247,7 +2252,7 @@ const findClippingAncestor = (wrapper) => {
|
|
|
2247
2252
|
* @param params.offsetTop - Gap between the anchor and the box, vertically.
|
|
2248
2253
|
* @param params.box - Rendered size of the box.
|
|
2249
2254
|
* @param params.wrapper - The wrapper's own edges, in wrapper coordinates.
|
|
2250
|
-
* @param params.placement -
|
|
2255
|
+
* @param params.placement - Below-axis, beside without vertical flipping, or automatic flipping.
|
|
2251
2256
|
* @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
|
|
2252
2257
|
* @return The box's top-left corner; fixed placement preserves the axis's subpixel y.
|
|
2253
2258
|
*/
|
|
@@ -2271,7 +2276,8 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2271
2276
|
const upY = top - offsetTop - box.height;
|
|
2272
2277
|
const downOverflow = downY + box.height - fit.bottom;
|
|
2273
2278
|
const upOverflow = fit.top - upY;
|
|
2274
|
-
let y =
|
|
2279
|
+
let y = top;
|
|
2280
|
+
if (placement !== "beside") y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
|
|
2275
2281
|
x = clamp(x, bounds.left, bounds.right, box.width);
|
|
2276
2282
|
y = clamp(y, bounds.top, bounds.bottom, box.height);
|
|
2277
2283
|
return {
|
|
@@ -2287,8 +2293,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2287
2293
|
* alone would let the box spill into an `overflow: hidden` card and be cut off.
|
|
2288
2294
|
*
|
|
2289
2295
|
* Re-measures on every render, so a box whose content changes width between
|
|
2290
|
-
* two hovers is placed for its current size.
|
|
2291
|
-
* below-axis exception.
|
|
2296
|
+
* two hovers is placed for its current size.
|
|
2292
2297
|
*
|
|
2293
2298
|
* @param props - visx `Tooltip` props.
|
|
2294
2299
|
* @param props.left - Anchor x, in wrapper coordinates.
|
|
@@ -2298,7 +2303,7 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bo
|
|
|
2298
2303
|
* @param props.style - Box styles; visx's defaults unless `unstyled`.
|
|
2299
2304
|
* @param props.unstyled - Skip `style` and leave the box bare.
|
|
2300
2305
|
* @param props.children - Box content.
|
|
2301
|
-
* @param props.placement -
|
|
2306
|
+
* @param props.placement - Below-axis, beside without vertical flipping, or automatic flipping.
|
|
2302
2307
|
* @return The tooltip box.
|
|
2303
2308
|
*/
|
|
2304
2309
|
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = _visx_tooltip.defaultStyles, unstyled = false, children, placement = "auto", ...rest }) => {
|
|
@@ -2401,7 +2406,6 @@ const crosshairPaintProps = (props = {}) => {
|
|
|
2401
2406
|
};
|
|
2402
2407
|
const DEFAULT_GLYPH_RADIUS = 4;
|
|
2403
2408
|
const FALLBACK_COLOR = "#222";
|
|
2404
|
-
const DEFAULT_TOOLTIP_Z_INDEX = 3;
|
|
2405
2409
|
const PORTAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
2406
2410
|
"scroll",
|
|
2407
2411
|
"debounce",
|
|
@@ -2429,7 +2433,7 @@ const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ (0, react_js
|
|
|
2429
2433
|
seriesKey: key,
|
|
2430
2434
|
...props
|
|
2431
2435
|
}, key);
|
|
2432
|
-
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", zIndex =
|
|
2436
|
+
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", tooltipAnchorTop, zIndex = 3, style, ...rest }) => {
|
|
2433
2437
|
const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
|
|
2434
2438
|
const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = (0, react.useContext)(_visx_xychart.DataContext) || {};
|
|
2435
2439
|
const tooltipContent = renderTooltip ? renderTooltip({
|
|
@@ -2484,12 +2488,12 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2484
2488
|
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2485
2489
|
const marginTop = margin?.top ?? 0;
|
|
2486
2490
|
const marginLeft = margin?.left ?? 0;
|
|
2487
|
-
const TooltipComponent = detectBounds || tooltipPlacement
|
|
2491
|
+
const TooltipComponent = detectBounds || tooltipPlacement !== "auto" ? BoundedTooltip : _visx_tooltip.Tooltip;
|
|
2488
2492
|
const boxStyle = {
|
|
2489
2493
|
..._visx_tooltip.defaultStyles,
|
|
2490
2494
|
zIndex,
|
|
2491
2495
|
backgroundColor: theme?.backgroundColor ?? "white",
|
|
2492
|
-
boxShadow: `0 1px 2px ${theme?.htmlLabel?.color ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2496
|
+
boxShadow: `0 1px 2px ${isValidHexColor(theme?.htmlLabel?.color) ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2493
2497
|
...theme?.htmlLabel,
|
|
2494
2498
|
...style
|
|
2495
2499
|
};
|
|
@@ -2521,11 +2525,11 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2521
2525
|
]
|
|
2522
2526
|
}), container && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipComponent, {
|
|
2523
2527
|
left: tooltipLeft,
|
|
2524
|
-
top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipTop,
|
|
2528
|
+
top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipAnchorTop ?? tooltipTop,
|
|
2525
2529
|
style: boxStyle,
|
|
2526
2530
|
applyPositionStyle: true,
|
|
2527
2531
|
...tooltipProps,
|
|
2528
|
-
...tooltipPlacement
|
|
2532
|
+
...tooltipPlacement !== "auto" && { placement: tooltipPlacement },
|
|
2529
2533
|
children: tooltipContent
|
|
2530
2534
|
}), container)] });
|
|
2531
2535
|
};
|
|
@@ -2591,11 +2595,32 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2591
2595
|
return flattened;
|
|
2592
2596
|
}, [series, mode]);
|
|
2593
2597
|
const hasKeyboardSelection = (0, react.useRef)(false);
|
|
2598
|
+
const closeTooltipNow = (0, react.useCallback)(() => {
|
|
2599
|
+
tooltipContext?.updateTooltip({
|
|
2600
|
+
tooltipOpen: false,
|
|
2601
|
+
tooltipLeft: void 0,
|
|
2602
|
+
tooltipTop: void 0,
|
|
2603
|
+
tooltipData: void 0
|
|
2604
|
+
});
|
|
2605
|
+
}, []);
|
|
2606
|
+
const chartId = (0, react.useContext)(ChartInstanceContext)?.chartId;
|
|
2607
|
+
const { getHiddenSeries } = useGlobalChartsContext();
|
|
2608
|
+
const hiddenSeriesKey = chartId ? JSON.stringify([...getHiddenSeries(chartId)].sort()) : void 0;
|
|
2609
|
+
const lastHiddenSeriesKey = (0, react.useRef)(hiddenSeriesKey);
|
|
2610
|
+
(0, react.useEffect)(() => {
|
|
2611
|
+
const changed = lastHiddenSeriesKey.current !== hiddenSeriesKey;
|
|
2612
|
+
lastHiddenSeriesKey.current = hiddenSeriesKey;
|
|
2613
|
+
if (changed && selectedIndex === void 0) closeTooltipNow();
|
|
2614
|
+
}, [
|
|
2615
|
+
hiddenSeriesKey,
|
|
2616
|
+
selectedIndex,
|
|
2617
|
+
closeTooltipNow
|
|
2618
|
+
]);
|
|
2594
2619
|
(0, react.useEffect)(() => {
|
|
2595
2620
|
if (selectedIndex === void 0) {
|
|
2596
2621
|
if (hasKeyboardSelection.current) {
|
|
2597
2622
|
hasKeyboardSelection.current = false;
|
|
2598
|
-
|
|
2623
|
+
closeTooltipNow();
|
|
2599
2624
|
}
|
|
2600
2625
|
return;
|
|
2601
2626
|
}
|
|
@@ -2664,15 +2689,45 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2664
2689
|
renderTooltip: focusableRenderTooltip
|
|
2665
2690
|
});
|
|
2666
2691
|
};
|
|
2667
|
-
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false }) => {
|
|
2692
|
+
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false, visibleSeriesKey }) => {
|
|
2693
|
+
const getChartRoot = (0, react.useCallback)(() => chartRef.current?.closest("[role=\"grid\"]") ?? chartRef.current, [chartRef]);
|
|
2694
|
+
const focusWithoutScrollIfNeeded = (0, react.useCallback)((element) => {
|
|
2695
|
+
if (preventTooltipScroll) element?.focus({ preventScroll: true });
|
|
2696
|
+
else element?.focus();
|
|
2697
|
+
}, [preventTooltipScroll]);
|
|
2698
|
+
const tooltipRef = (0, react.useCallback)((element) => {
|
|
2699
|
+
if (element && selectedIndex !== void 0) focusWithoutScrollIfNeeded(element);
|
|
2700
|
+
}, [focusWithoutScrollIfNeeded, selectedIndex]);
|
|
2701
|
+
const previousTotalPoints = (0, react.useRef)(totalPoints);
|
|
2702
|
+
const previousVisibleSeriesKey = (0, react.useRef)(visibleSeriesKey);
|
|
2703
|
+
(0, react.useEffect)(() => {
|
|
2704
|
+
const countChanged = previousTotalPoints.current !== totalPoints;
|
|
2705
|
+
const seriesChanged = previousVisibleSeriesKey.current !== visibleSeriesKey;
|
|
2706
|
+
previousTotalPoints.current = totalPoints;
|
|
2707
|
+
previousVisibleSeriesKey.current = visibleSeriesKey;
|
|
2708
|
+
if (!countChanged && !seriesChanged || selectedIndex === void 0) return;
|
|
2709
|
+
const { activeElement } = document;
|
|
2710
|
+
const focusIsInChart = activeElement !== null && !!getChartRoot()?.contains(activeElement);
|
|
2711
|
+
if (totalPoints === 0 || !focusIsInChart || !countChanged) {
|
|
2712
|
+
setSelectedIndex(void 0);
|
|
2713
|
+
setIsNavigating(false);
|
|
2714
|
+
if (focusIsInChart) focusWithoutScrollIfNeeded(getChartRoot());
|
|
2715
|
+
return;
|
|
2716
|
+
}
|
|
2717
|
+
setSelectedIndex(Math.min(selectedIndex, totalPoints - 1));
|
|
2718
|
+
}, [
|
|
2719
|
+
selectedIndex,
|
|
2720
|
+
totalPoints,
|
|
2721
|
+
visibleSeriesKey,
|
|
2722
|
+
setSelectedIndex,
|
|
2723
|
+
setIsNavigating,
|
|
2724
|
+
getChartRoot,
|
|
2725
|
+
focusWithoutScrollIfNeeded
|
|
2726
|
+
]);
|
|
2668
2727
|
return {
|
|
2669
|
-
tooltipRef
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
else element.focus();
|
|
2673
|
-
}
|
|
2674
|
-
}, [preventTooltipScroll, selectedIndex]),
|
|
2675
|
-
onChartFocus: (0, react.useCallback)(() => {
|
|
2728
|
+
tooltipRef,
|
|
2729
|
+
onChartFocus: (0, react.useCallback)((event) => {
|
|
2730
|
+
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
2676
2731
|
if (!isNavigating && selectedIndex !== void 0) setSelectedIndex(0);
|
|
2677
2732
|
}, [
|
|
2678
2733
|
isNavigating,
|
|
@@ -2683,38 +2738,34 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
|
|
|
2683
2738
|
setIsNavigating(false);
|
|
2684
2739
|
}, [setIsNavigating]),
|
|
2685
2740
|
onChartKeyDown: (0, react.useCallback)((event) => {
|
|
2686
|
-
if (
|
|
2687
|
-
|
|
2688
|
-
|
|
2741
|
+
if (event.key === "Tab" || event.key === "Escape") {
|
|
2742
|
+
if (event.key === "Escape" && selectedIndex !== void 0) event.preventDefault();
|
|
2743
|
+
focusWithoutScrollIfNeeded(getChartRoot());
|
|
2689
2744
|
setSelectedIndex(void 0);
|
|
2690
2745
|
setIsNavigating(false);
|
|
2691
2746
|
return;
|
|
2692
2747
|
}
|
|
2748
|
+
if (totalPoints === 0) return;
|
|
2693
2749
|
const currentSelectedIndex = selectedIndex === void 0 ? -1 : selectedIndex;
|
|
2694
|
-
if (
|
|
2695
|
-
|
|
2696
|
-
setSelectedIndex(void 0);
|
|
2697
|
-
setIsNavigating(false);
|
|
2698
|
-
return;
|
|
2699
|
-
}
|
|
2700
|
-
event.preventDefault();
|
|
2701
|
-
if (["ArrowRight"].includes(event.key)) {
|
|
2750
|
+
if (event.key === "ArrowRight") {
|
|
2751
|
+
event.preventDefault();
|
|
2702
2752
|
setIsNavigating(true);
|
|
2703
|
-
setSelectedIndex((currentSelectedIndex + 1
|
|
2704
|
-
} else if (
|
|
2753
|
+
setSelectedIndex(Math.min(currentSelectedIndex + 1, totalPoints - 1));
|
|
2754
|
+
} else if (event.key === "ArrowLeft") {
|
|
2755
|
+
event.preventDefault();
|
|
2705
2756
|
setIsNavigating(true);
|
|
2706
|
-
setSelectedIndex((currentSelectedIndex - 1
|
|
2707
|
-
} else if (event.key === "
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
} else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) onActivate?.(selectedIndex);
|
|
2757
|
+
setSelectedIndex(Math.max(currentSelectedIndex - 1, 0));
|
|
2758
|
+
} else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) {
|
|
2759
|
+
event.preventDefault();
|
|
2760
|
+
onActivate?.(selectedIndex);
|
|
2761
|
+
}
|
|
2712
2762
|
}, [
|
|
2713
2763
|
totalPoints,
|
|
2714
2764
|
selectedIndex,
|
|
2715
2765
|
setSelectedIndex,
|
|
2716
2766
|
setIsNavigating,
|
|
2717
|
-
|
|
2767
|
+
getChartRoot,
|
|
2768
|
+
focusWithoutScrollIfNeeded,
|
|
2718
2769
|
onActivate
|
|
2719
2770
|
])
|
|
2720
2771
|
};
|
|
@@ -4318,6 +4369,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4318
4369
|
children: ({ contentHeight }) => {
|
|
4319
4370
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
4320
4371
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4372
|
+
ref: chartRef,
|
|
4321
4373
|
role: "grid",
|
|
4322
4374
|
"aria-label": (0, _wordpress_i18n.__)("Line chart", "jetpack-charts"),
|
|
4323
4375
|
tabIndex: 0,
|
|
@@ -4325,7 +4377,6 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4325
4377
|
onFocus: onChartFocus,
|
|
4326
4378
|
onBlur: onChartBlur,
|
|
4327
4379
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4328
|
-
ref: chartRef,
|
|
4329
4380
|
className: xy_plot_module_default["xy-plot"],
|
|
4330
4381
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
4331
4382
|
theme,
|
|
@@ -4823,6 +4874,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4823
4874
|
children: ({ contentHeight }) => {
|
|
4824
4875
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
4825
4876
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4877
|
+
ref: chartRef,
|
|
4826
4878
|
role: "grid",
|
|
4827
4879
|
"aria-label": (0, _wordpress_i18n.__)("Area chart", "jetpack-charts"),
|
|
4828
4880
|
tabIndex: 0,
|
|
@@ -4830,7 +4882,6 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4830
4882
|
onFocus: onChartFocus,
|
|
4831
4883
|
onBlur: onChartBlur,
|
|
4832
4884
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4833
|
-
ref: chartRef,
|
|
4834
4885
|
className: xy_plot_module_default["xy-plot"],
|
|
4835
4886
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
4836
4887
|
theme,
|
|
@@ -5272,6 +5323,20 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
5272
5323
|
]);
|
|
5273
5324
|
}
|
|
5274
5325
|
//#endregion
|
|
5326
|
+
//#region src/charts/bar-chart/private/band-scale.ts
|
|
5327
|
+
/**
|
|
5328
|
+
* Match the inner slot scale used by visx BarGroup.
|
|
5329
|
+
* @param keys - Visible primary series keys.
|
|
5330
|
+
* @param bandwidth - Category band width.
|
|
5331
|
+
* @param padding - Padding between slots.
|
|
5332
|
+
* @return The grouped bar scale.
|
|
5333
|
+
*/
|
|
5334
|
+
const createGroupScale = (keys, bandwidth, padding) => (0, _visx_scale.scaleBand)({
|
|
5335
|
+
domain: keys,
|
|
5336
|
+
range: [0, bandwidth],
|
|
5337
|
+
padding
|
|
5338
|
+
});
|
|
5339
|
+
//#endregion
|
|
5275
5340
|
//#region src/charts/bar-chart/private/comparison-bars-geometry.ts
|
|
5276
5341
|
/**
|
|
5277
5342
|
* Output position of a value scale's baseline: zero if in-domain, else the
|
|
@@ -5344,11 +5409,7 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
5344
5409
|
const valueScale = horizontal ? xScale : yScale;
|
|
5345
5410
|
const bandwidth = bandScale.bandwidth ? bandScale.bandwidth() : 0;
|
|
5346
5411
|
if (!bandwidth) return null;
|
|
5347
|
-
const groupScale = (
|
|
5348
|
-
domain: primaryKeys,
|
|
5349
|
-
range: [0, bandwidth],
|
|
5350
|
-
padding: groupPadding
|
|
5351
|
-
});
|
|
5412
|
+
const groupScale = createGroupScale(primaryKeys, bandwidth, groupPadding);
|
|
5352
5413
|
const slotThickness = groupScale.bandwidth();
|
|
5353
5414
|
const baseline = getValueScaleBaseline(valueScale);
|
|
5354
5415
|
const bandAccessor = horizontal ? yAccessor : xAccessor;
|
|
@@ -5400,6 +5461,163 @@ const ComparisonBars = ({ comparisonEntries, primaryKeys, groupPadding, horizont
|
|
|
5400
5461
|
});
|
|
5401
5462
|
};
|
|
5402
5463
|
//#endregion
|
|
5464
|
+
//#region src/charts/bar-chart/private/band-highlight.tsx
|
|
5465
|
+
/**
|
|
5466
|
+
* Render and report the active band using the chart’s registered scales.
|
|
5467
|
+
* @param root0 - Highlight options.
|
|
5468
|
+
* @param root0.visible - Whether to paint the band.
|
|
5469
|
+
* @param root0.horizontal - Whether categories run vertically.
|
|
5470
|
+
* @param root0.onChange - Receives selected band geometry.
|
|
5471
|
+
* @return The optional band highlight.
|
|
5472
|
+
*/
|
|
5473
|
+
function BandHighlight({ visible, horizontal, onChange }) {
|
|
5474
|
+
const { xScale, yScale, dataRegistry, margin, innerWidth, innerHeight } = (0, react.useContext)(_visx_xychart.DataContext);
|
|
5475
|
+
const { tooltipOpen, tooltipData } = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
5476
|
+
const nearest = tooltipData?.nearestDatum;
|
|
5477
|
+
const selection = (0, react.useMemo)(() => {
|
|
5478
|
+
if (!tooltipOpen || !nearest) return null;
|
|
5479
|
+
const scale = horizontal ? yScale : xScale;
|
|
5480
|
+
const entry = dataRegistry?.get(nearest.key);
|
|
5481
|
+
const accessor = horizontal ? entry?.yAccessor : entry?.xAccessor;
|
|
5482
|
+
if (!scale?.bandwidth || !accessor) return null;
|
|
5483
|
+
const position = scale(accessor(nearest.datum));
|
|
5484
|
+
if (position === void 0 || !Number.isFinite(position)) return null;
|
|
5485
|
+
return {
|
|
5486
|
+
datum: nearest.datum,
|
|
5487
|
+
x: horizontal ? margin?.left ?? 0 : position,
|
|
5488
|
+
y: horizontal ? position : margin?.top ?? 0,
|
|
5489
|
+
width: horizontal ? innerWidth : scale.bandwidth(),
|
|
5490
|
+
height: horizontal ? scale.bandwidth() : innerHeight
|
|
5491
|
+
};
|
|
5492
|
+
}, [
|
|
5493
|
+
tooltipOpen,
|
|
5494
|
+
nearest,
|
|
5495
|
+
horizontal,
|
|
5496
|
+
xScale,
|
|
5497
|
+
yScale,
|
|
5498
|
+
dataRegistry,
|
|
5499
|
+
margin,
|
|
5500
|
+
innerWidth,
|
|
5501
|
+
innerHeight
|
|
5502
|
+
]);
|
|
5503
|
+
const stableSelection = useDeepMemo(selection);
|
|
5504
|
+
const onChangeRef = (0, react.useRef)(onChange);
|
|
5505
|
+
onChangeRef.current = onChange;
|
|
5506
|
+
(0, react.useEffect)(() => {
|
|
5507
|
+
onChangeRef.current?.(stableSelection);
|
|
5508
|
+
}, [stableSelection]);
|
|
5509
|
+
(0, react.useEffect)(() => () => onChangeRef.current?.(null), []);
|
|
5510
|
+
if (!visible || !selection) return null;
|
|
5511
|
+
const { x, y, width, height } = selection;
|
|
5512
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
5513
|
+
x,
|
|
5514
|
+
y,
|
|
5515
|
+
width,
|
|
5516
|
+
height,
|
|
5517
|
+
pointerEvents: "none",
|
|
5518
|
+
fill: CATALOG_POINTERS.surfaceSecondary
|
|
5519
|
+
});
|
|
5520
|
+
}
|
|
5521
|
+
//#endregion
|
|
5522
|
+
//#region src/charts/bar-chart/private/band-tooltip.tsx
|
|
5523
|
+
/**
|
|
5524
|
+
* Find a category by its painted center, including outer padding and reversed ranges.
|
|
5525
|
+
* @param data - Registered series points.
|
|
5526
|
+
* @param accessor - Category accessor.
|
|
5527
|
+
* @param scale - Rendered category band scale.
|
|
5528
|
+
* @param position - Pointer coordinate on the category axis.
|
|
5529
|
+
* @return Index of the nearest category, or -1 when none is registered.
|
|
5530
|
+
*/
|
|
5531
|
+
function nearestBandIndex(data, accessor, scale, position) {
|
|
5532
|
+
let nearest = -1;
|
|
5533
|
+
let distance = Infinity;
|
|
5534
|
+
data.forEach((datum, index) => {
|
|
5535
|
+
const start = scale(accessor(datum));
|
|
5536
|
+
if (start === void 0) return;
|
|
5537
|
+
const candidate = Math.abs(start + scale.bandwidth() / 2 - position);
|
|
5538
|
+
if (candidate < distance) {
|
|
5539
|
+
distance = candidate;
|
|
5540
|
+
nearest = index;
|
|
5541
|
+
}
|
|
5542
|
+
});
|
|
5543
|
+
return nearest;
|
|
5544
|
+
}
|
|
5545
|
+
/**
|
|
5546
|
+
* Correct visx's range-based band inversion, which omits outer padding.
|
|
5547
|
+
* @param root0 - Registered series selection.
|
|
5548
|
+
* @param root0.keys - Visible series keys.
|
|
5549
|
+
* @param root0.groupPadding - Padding between grouped bars.
|
|
5550
|
+
* @param root0.withTooltips - Whether pointer events update the tooltip.
|
|
5551
|
+
* @param root0.onPointerDown - Receives the corrected pointer-down datum.
|
|
5552
|
+
* @param root0.onPointerUp - Receives the corrected pointer-up datum.
|
|
5553
|
+
* @return No visual content.
|
|
5554
|
+
*/
|
|
5555
|
+
function BandTooltip({ keys, groupPadding, withTooltips, onPointerDown, onPointerUp }) {
|
|
5556
|
+
const { xScale, yScale, dataRegistry, horizontal } = (0, react.useContext)(_visx_xychart.DataContext);
|
|
5557
|
+
const { showTooltip } = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
5558
|
+
const scale = horizontal ? yScale : xScale;
|
|
5559
|
+
const bandwidth = scale?.bandwidth?.() ?? 0;
|
|
5560
|
+
const groupScale = (0, react.useMemo)(() => createGroupScale(keys, bandwidth, groupPadding), [
|
|
5561
|
+
keys,
|
|
5562
|
+
bandwidth,
|
|
5563
|
+
groupPadding
|
|
5564
|
+
]);
|
|
5565
|
+
const getSelections = (0, react.useCallback)((params) => {
|
|
5566
|
+
const point = params?.svgPoint;
|
|
5567
|
+
if (!point || !scale?.bandwidth) return [];
|
|
5568
|
+
const selections = [];
|
|
5569
|
+
for (const key of keys) {
|
|
5570
|
+
const entry = dataRegistry?.get(key);
|
|
5571
|
+
if (!entry) continue;
|
|
5572
|
+
const accessor = horizontal ? entry.yAccessor : entry.xAccessor;
|
|
5573
|
+
const index = nearestBandIndex(entry.data, accessor, scale, horizontal ? point.y : point.x);
|
|
5574
|
+
if (index < 0) continue;
|
|
5575
|
+
const datum = entry.data[index];
|
|
5576
|
+
const start = Number(scale(accessor(datum))) + Number(groupScale(key));
|
|
5577
|
+
const end = start + groupScale.step();
|
|
5578
|
+
const position = horizontal ? point.y : point.x;
|
|
5579
|
+
const distance = position >= start && position <= end ? 0 : Math.abs(position - (start + end) / 2);
|
|
5580
|
+
selections.push({
|
|
5581
|
+
event: params.event,
|
|
5582
|
+
key,
|
|
5583
|
+
datum,
|
|
5584
|
+
index,
|
|
5585
|
+
svgPoint: point,
|
|
5586
|
+
distanceX: horizontal ? 0 : distance,
|
|
5587
|
+
distanceY: horizontal ? distance : 0
|
|
5588
|
+
});
|
|
5589
|
+
}
|
|
5590
|
+
return selections;
|
|
5591
|
+
}, [
|
|
5592
|
+
scale,
|
|
5593
|
+
dataRegistry,
|
|
5594
|
+
horizontal,
|
|
5595
|
+
keys,
|
|
5596
|
+
groupScale
|
|
5597
|
+
]);
|
|
5598
|
+
const handlePointer = (0, react.useCallback)((params) => {
|
|
5599
|
+
const selections = getSelections(params);
|
|
5600
|
+
if (withTooltips && params?.event.type !== "pointerup") selections.forEach(showTooltip);
|
|
5601
|
+
const callback = params?.event.type === "pointerdown" ? onPointerDown : onPointerUp;
|
|
5602
|
+
if (params?.event.type === "pointermove" || !callback) return;
|
|
5603
|
+
const nearest = selections.reduce((best, selection) => {
|
|
5604
|
+
const distance = (value) => Math.hypot(value.distanceX, value.distanceY);
|
|
5605
|
+
return !best || distance(selection) <= distance(best) ? selection : best;
|
|
5606
|
+
}, void 0);
|
|
5607
|
+
if (nearest) callback(nearest);
|
|
5608
|
+
}, [
|
|
5609
|
+
getSelections,
|
|
5610
|
+
withTooltips,
|
|
5611
|
+
showTooltip,
|
|
5612
|
+
onPointerDown,
|
|
5613
|
+
onPointerUp
|
|
5614
|
+
]);
|
|
5615
|
+
(0, _visx_xychart.useEventEmitter)("pointermove", withTooltips ? handlePointer : void 0);
|
|
5616
|
+
(0, _visx_xychart.useEventEmitter)("pointerdown", handlePointer);
|
|
5617
|
+
(0, _visx_xychart.useEventEmitter)("pointerup", onPointerUp ? handlePointer : void 0);
|
|
5618
|
+
return null;
|
|
5619
|
+
}
|
|
5620
|
+
//#endregion
|
|
5403
5621
|
//#region src/charts/bar-chart/bar-chart.tsx
|
|
5404
5622
|
const validateData$2 = (data) => {
|
|
5405
5623
|
if (!data?.length) return "No data available";
|
|
@@ -5411,7 +5629,7 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ (0, react_jsx_runtime
|
|
|
5411
5629
|
className: bar_chart_module_default["bar-chart__tooltip-row"],
|
|
5412
5630
|
children: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%1$s: %2$s", "jetpack-charts"), label, value)
|
|
5413
5631
|
});
|
|
5414
|
-
const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
5632
|
+
const BarChartInternal = ({ data, chartId: providedChartId, width, height, className, margin, withTooltips = false, showLegend = false, legend = {}, gridVisibility: gridVisibilityProp, renderTooltip, tooltipPlacement, tooltipAnchorTop, options = {}, orientation = "vertical", withPatterns = false, showZeroValues = false, withBandHighlight = false, onBandHighlightChange, defaultHiddenSeries, animation, children, gap = "md", onPointerDown, onPointerUp, onDatumActivate }) => {
|
|
5415
5633
|
const legendInteractive = legend.interactive ?? false;
|
|
5416
5634
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
5417
5635
|
const horizontal = orientation === "horizontal";
|
|
@@ -5437,8 +5655,6 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5437
5655
|
}, [height]);
|
|
5438
5656
|
const [selectedIndex, setSelectedIndex] = (0, react.useState)(void 0);
|
|
5439
5657
|
const [isNavigating, setIsNavigating] = (0, react.useState)(false);
|
|
5440
|
-
const primarySeriesForNav = dataWithVisibleZeros.filter((s) => s.options?.type !== "comparison");
|
|
5441
|
-
const totalPoints = Math.max(0, ...primarySeriesForNav.map((s) => s.data?.length || 0)) * primarySeriesForNav.length;
|
|
5442
5658
|
const seriesWithVisibility = (0, react.useMemo)(() => dataWithVisibleZeros.map((series, index) => ({
|
|
5443
5659
|
series,
|
|
5444
5660
|
index,
|
|
@@ -5448,6 +5664,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5448
5664
|
return seriesWithVisibility.every(({ isVisible }) => !isVisible);
|
|
5449
5665
|
}, [seriesWithVisibility]);
|
|
5450
5666
|
const primaryEntries = (0, react.useMemo)(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
|
|
5667
|
+
const totalPoints = Math.max(0, ...primaryEntries.map((e) => e.series.data.length)) * primaryEntries.length;
|
|
5451
5668
|
const primaryKeys = (0, react.useMemo)(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
|
|
5452
5669
|
const primarySeries = (0, react.useMemo)(() => primaryEntries.map(({ series }) => series), [primaryEntries]);
|
|
5453
5670
|
const activateSelectedBar = (0, react.useCallback)((index) => {
|
|
@@ -5462,6 +5679,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5462
5679
|
key: series.label
|
|
5463
5680
|
});
|
|
5464
5681
|
}, [primaryEntries, onDatumActivate]);
|
|
5682
|
+
const visibleSeriesKey = (0, react.useMemo)(() => JSON.stringify(primaryKeys), [primaryKeys]);
|
|
5465
5683
|
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
5466
5684
|
selectedIndex,
|
|
5467
5685
|
setSelectedIndex,
|
|
@@ -5469,7 +5687,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5469
5687
|
setIsNavigating,
|
|
5470
5688
|
chartRef,
|
|
5471
5689
|
totalPoints,
|
|
5472
|
-
onActivate: activateSelectedBar
|
|
5690
|
+
onActivate: activateSelectedBar,
|
|
5691
|
+
visibleSeriesKey
|
|
5473
5692
|
});
|
|
5474
5693
|
const comparisonEntries = (0, react.useMemo)(() => {
|
|
5475
5694
|
const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
|
|
@@ -5532,7 +5751,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5532
5751
|
chartOptions.yScale,
|
|
5533
5752
|
horizontal
|
|
5534
5753
|
]);
|
|
5535
|
-
const getBarBackground = (0, react.useCallback)((index) => () => withPatterns ? `url(#${getPatternId(chartId, index)})` : getElementStyles({
|
|
5754
|
+
const getBarBackground = (0, react.useCallback)((index) => (datum) => withPatterns ? `url(#${getPatternId(chartId, index)})` : datum.color ?? getElementStyles({
|
|
5536
5755
|
data: dataSorted[index],
|
|
5537
5756
|
index
|
|
5538
5757
|
}).color, [
|
|
@@ -5702,13 +5921,13 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5702
5921
|
const chartHeight = contentHeight > 0 ? contentHeight : height;
|
|
5703
5922
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5704
5923
|
role: "grid",
|
|
5924
|
+
ref: chartRef,
|
|
5705
5925
|
"aria-label": (0, _wordpress_i18n.__)("Bar chart", "jetpack-charts"),
|
|
5706
5926
|
tabIndex: 0,
|
|
5707
5927
|
onKeyDown: onChartKeyDown,
|
|
5708
5928
|
onFocus: onChartFocus,
|
|
5709
5929
|
onBlur: onChartBlur,
|
|
5710
5930
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5711
|
-
ref: chartRef,
|
|
5712
5931
|
className: xy_plot_module_default["xy-plot"],
|
|
5713
5932
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
5714
5933
|
theme,
|
|
@@ -5721,15 +5940,24 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5721
5940
|
xScale,
|
|
5722
5941
|
yScale,
|
|
5723
5942
|
horizontal,
|
|
5724
|
-
onPointerDown,
|
|
5725
|
-
onPointerUp,
|
|
5726
5943
|
pointerEventsDataKey: "nearest",
|
|
5727
5944
|
children: [
|
|
5728
|
-
|
|
5945
|
+
withTooltips && (withBandHighlight || onBandHighlightChange) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BandHighlight, {
|
|
5946
|
+
visible: withBandHighlight,
|
|
5947
|
+
horizontal,
|
|
5948
|
+
onChange: onBandHighlightChange
|
|
5949
|
+
}),
|
|
5950
|
+
!allSeriesHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Grid, {
|
|
5729
5951
|
columns: gridVisibility.includes("y"),
|
|
5952
|
+
rows: false,
|
|
5953
|
+
numTicks: 4,
|
|
5954
|
+
tickValues: chartOptions.axis.x.tickValues
|
|
5955
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Grid, {
|
|
5956
|
+
columns: false,
|
|
5730
5957
|
rows: gridVisibility.includes("x"),
|
|
5731
|
-
numTicks: 4
|
|
5732
|
-
|
|
5958
|
+
numTicks: 4,
|
|
5959
|
+
tickValues: chartOptions.axis.y.tickValues
|
|
5960
|
+
})] }),
|
|
5733
5961
|
withPatterns && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: dataSorted.map((seriesData, index) => renderPattern(index, getElementStyles({
|
|
5734
5962
|
data: seriesData,
|
|
5735
5963
|
index
|
|
@@ -5765,8 +5993,17 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5765
5993
|
colorAccessor: getBarBackground(index)
|
|
5766
5994
|
}, seriesData?.label))
|
|
5767
5995
|
}),
|
|
5996
|
+
(withTooltips || onPointerDown || onPointerUp) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BandTooltip, {
|
|
5997
|
+
keys: primaryKeys,
|
|
5998
|
+
groupPadding,
|
|
5999
|
+
withTooltips,
|
|
6000
|
+
onPointerDown,
|
|
6001
|
+
onPointerUp
|
|
6002
|
+
}),
|
|
5768
6003
|
!allSeriesHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, { ...chartOptions.axis.x }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Axis, { ...chartOptions.axis.y })] }),
|
|
5769
6004
|
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccessibleTooltip, {
|
|
6005
|
+
tooltipPlacement,
|
|
6006
|
+
tooltipAnchorTop,
|
|
5770
6007
|
detectBounds: true,
|
|
5771
6008
|
snapTooltipToDatumX: true,
|
|
5772
6009
|
snapTooltipToDatumY: true,
|
|
@@ -6588,8 +6825,11 @@ var heatmap_chart_module_default = {
|
|
|
6588
6825
|
"heatmap-chart__gap-start": "a8ccharts-O3YMOW-heatmap-chart__gap-start",
|
|
6589
6826
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
6590
6827
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
6828
|
+
"heatmap-chart__grid--flex-gaps": "a8ccharts-O3YMOW-heatmap-chart__grid--flex-gaps",
|
|
6591
6829
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
6830
|
+
"heatmap-chart__group-label": "a8ccharts-O3YMOW-heatmap-chart__group-label",
|
|
6592
6831
|
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
6832
|
+
"heatmap-chart__legend-scale--bar": "a8ccharts-O3YMOW-heatmap-chart__legend-scale--bar",
|
|
6593
6833
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
6594
6834
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
6595
6835
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
@@ -6634,290 +6874,267 @@ const getNormalizedValue = (value, extent) => {
|
|
|
6634
6874
|
return Math.min(1, Math.max(0, (value - min) / (max - min)));
|
|
6635
6875
|
};
|
|
6636
6876
|
//#endregion
|
|
6637
|
-
//#region src/charts/heatmap-chart/private/
|
|
6638
|
-
|
|
6639
|
-
const
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
const
|
|
6647
|
-
const
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
*/
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6877
|
+
//#region src/charts/heatmap-chart/private/heatmap-context.ts
|
|
6878
|
+
/** Shared by the chart and legend without importing back from `heatmap-chart.tsx`. */
|
|
6879
|
+
const HeatmapContext = (0, react.createContext)(null);
|
|
6880
|
+
//#endregion
|
|
6881
|
+
//#region src/charts/heatmap-chart/private/heatmap-legend.tsx
|
|
6882
|
+
const HeatmapLegend = ({ steps = 5, variant = "swatches", lessLabel, moreLabel }) => {
|
|
6883
|
+
const context = (0, react.useContext)(HeatmapContext);
|
|
6884
|
+
const { legend } = useGlobalChartsTheme();
|
|
6885
|
+
if (!context) return null;
|
|
6886
|
+
const { primaryColorHex } = context;
|
|
6887
|
+
const labelStyle = legend.labelStyles;
|
|
6888
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
6889
|
+
direction: "row",
|
|
6890
|
+
gap: "xs",
|
|
6891
|
+
align: "center",
|
|
6892
|
+
children: [
|
|
6893
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6894
|
+
variant: "body-sm",
|
|
6895
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6896
|
+
style: labelStyle,
|
|
6897
|
+
children: lessLabel ?? (0, _wordpress_i18n.__)("Less", "jetpack-charts")
|
|
6898
|
+
}),
|
|
6899
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Stack, {
|
|
6900
|
+
direction: "row",
|
|
6901
|
+
gap: variant === "bar" ? void 0 : "xs",
|
|
6902
|
+
"aria-hidden": "true",
|
|
6903
|
+
className: variant === "bar" ? heatmap_chart_module_default["heatmap-chart__legend-scale--bar"] : void 0,
|
|
6904
|
+
children: Array.from({ length: steps }, (_, index) => {
|
|
6905
|
+
const intensity = steps <= 1 ? 1 : index / (steps - 1);
|
|
6906
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6907
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
6908
|
+
style: {
|
|
6909
|
+
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6910
|
+
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
6911
|
+
}
|
|
6912
|
+
}, index);
|
|
6913
|
+
})
|
|
6914
|
+
}),
|
|
6915
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6916
|
+
variant: "body-sm",
|
|
6917
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6918
|
+
style: labelStyle,
|
|
6919
|
+
children: moreLabel ?? (0, _wordpress_i18n.__)("More", "jetpack-charts")
|
|
6920
|
+
})
|
|
6921
|
+
]
|
|
6922
|
+
});
|
|
6669
6923
|
};
|
|
6924
|
+
//#endregion
|
|
6925
|
+
//#region src/charts/heatmap-chart/private/column-groups.ts
|
|
6926
|
+
const isSpan = (span) => Number.isInteger(span) && span > 0;
|
|
6670
6927
|
/**
|
|
6671
|
-
*
|
|
6928
|
+
* Validates column groups and lays them over the columns.
|
|
6672
6929
|
*
|
|
6673
|
-
* @param
|
|
6674
|
-
* @
|
|
6930
|
+
* @param groups - Groups as passed to the chart.
|
|
6931
|
+
* @param columnCount - Number of data columns.
|
|
6932
|
+
* @param firstLine - Grid column line of the first data column.
|
|
6933
|
+
* @return Grid column lines for every column and group; no groups when the input was unusable.
|
|
6675
6934
|
*/
|
|
6676
|
-
const
|
|
6677
|
-
const
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6935
|
+
const resolveColumnGroups = (groups, columnCount, firstLine) => {
|
|
6936
|
+
const ungrouped = () => ({
|
|
6937
|
+
columns: Array.from({ length: columnCount }, (_, index) => ({
|
|
6938
|
+
line: firstLine + index,
|
|
6939
|
+
gapBefore: false
|
|
6940
|
+
})),
|
|
6941
|
+
groups: []
|
|
6942
|
+
});
|
|
6943
|
+
if (!groups || groups.length === 0 || columnCount === 0) return ungrouped();
|
|
6944
|
+
const spans = groups.map((group) => group.span);
|
|
6945
|
+
const total = spans.reduce((sum, span) => sum + span, 0);
|
|
6946
|
+
if (!spans.every(isSpan) || total > columnCount) {
|
|
6947
|
+
warnOnce(`heatmap:columnGroups:${JSON.stringify(spans)}:${columnCount}`, `columnGroups spans ${JSON.stringify(spans)} must be positive integers that fit the ${columnCount} columns, so no groups are drawn.`);
|
|
6948
|
+
return ungrouped();
|
|
6949
|
+
}
|
|
6950
|
+
const columns = [];
|
|
6951
|
+
const laidOut = [];
|
|
6952
|
+
let line = firstLine;
|
|
6953
|
+
groups.forEach((group, groupIndex) => {
|
|
6954
|
+
if (groupIndex > 0) line += 1;
|
|
6955
|
+
laidOut.push({
|
|
6956
|
+
...group,
|
|
6957
|
+
line
|
|
6958
|
+
});
|
|
6959
|
+
for (let offset = 0; offset < group.span; offset++) {
|
|
6960
|
+
columns.push({
|
|
6961
|
+
line,
|
|
6962
|
+
gapBefore: groupIndex > 0 && offset === 0,
|
|
6963
|
+
group: groupIndex
|
|
6964
|
+
});
|
|
6965
|
+
line += 1;
|
|
6966
|
+
}
|
|
6967
|
+
});
|
|
6968
|
+
while (columns.length < columnCount) {
|
|
6969
|
+
columns.push({
|
|
6970
|
+
line,
|
|
6971
|
+
gapBefore: false
|
|
6972
|
+
});
|
|
6973
|
+
line += 1;
|
|
6974
|
+
}
|
|
6975
|
+
return {
|
|
6976
|
+
columns,
|
|
6977
|
+
groups: laidOut
|
|
6978
|
+
};
|
|
6681
6979
|
};
|
|
6980
|
+
//#endregion
|
|
6981
|
+
//#region src/charts/heatmap-chart/private/keyboard-navigation.ts
|
|
6982
|
+
const ARROW_KEYS = [
|
|
6983
|
+
"ArrowLeft",
|
|
6984
|
+
"ArrowRight",
|
|
6985
|
+
"ArrowUp",
|
|
6986
|
+
"ArrowDown"
|
|
6987
|
+
];
|
|
6988
|
+
const PAGE_KEYS = ["PageUp", "PageDown"];
|
|
6989
|
+
const isNavigationKey = (key, mode) => ARROW_KEYS.includes(key) || mode === "calendar" && PAGE_KEYS.includes(key);
|
|
6990
|
+
const inGrid = (grid, { column, row }) => column >= 0 && column < grid.columns && row >= 0 && row < grid.rows;
|
|
6991
|
+
const firstSelectable = (grid, cells) => cells.find((cell) => inGrid(grid, cell) && !grid.isInert(cell.column, cell.row));
|
|
6682
6992
|
/**
|
|
6683
|
-
*
|
|
6993
|
+
* Column-major scan for the first selectable cell.
|
|
6684
6994
|
*
|
|
6685
|
-
* @param
|
|
6686
|
-
* @return
|
|
6995
|
+
* @param grid - The grid.
|
|
6996
|
+
* @return The cell, or undefined when every slot is inert.
|
|
6687
6997
|
*/
|
|
6688
|
-
const
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
});
|
|
6693
|
-
return (date) => {
|
|
6694
|
-
const parts = formatter.formatToParts(date);
|
|
6695
|
-
const read = (type) => parts.find((part) => part.type === type)?.value ?? "";
|
|
6696
|
-
const key = `${pad(Number(read("year")), 4)}-${read("month")}-${read("day")}`;
|
|
6697
|
-
return civilDate(key) ? key : null;
|
|
6998
|
+
const firstGridCell = (grid) => {
|
|
6999
|
+
for (let column = 0; column < grid.columns; column++) for (let row = 0; row < grid.rows; row++) if (!grid.isInert(column, row)) return {
|
|
7000
|
+
column,
|
|
7001
|
+
row
|
|
6698
7002
|
};
|
|
6699
7003
|
};
|
|
6700
7004
|
/**
|
|
6701
|
-
*
|
|
6702
|
-
*
|
|
6703
|
-
* A `Date`, or a string carrying `Z` or an offset, is an instant read in the host's
|
|
6704
|
-
* zone. Anything else is a wall clock the host wrote, so its date part is the day.
|
|
7005
|
+
* Steps across the grid in the key's direction, past inert slots, staying put at the edge.
|
|
6705
7006
|
*
|
|
6706
|
-
* @param
|
|
6707
|
-
* @param
|
|
6708
|
-
* @
|
|
7007
|
+
* @param grid - The grid.
|
|
7008
|
+
* @param from - The selected cell.
|
|
7009
|
+
* @param key - The arrow key.
|
|
7010
|
+
* @return The next cell, or undefined to keep the selection.
|
|
6709
7011
|
*/
|
|
6710
|
-
const
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
7012
|
+
const stepGridCell = (grid, from, key) => {
|
|
7013
|
+
const step = {
|
|
7014
|
+
ArrowRight: [1, 0],
|
|
7015
|
+
ArrowLeft: [-1, 0],
|
|
7016
|
+
ArrowDown: [0, 1],
|
|
7017
|
+
ArrowUp: [0, -1]
|
|
7018
|
+
}[key];
|
|
7019
|
+
if (!step) return;
|
|
7020
|
+
const [stepColumn, stepRow] = step;
|
|
7021
|
+
let cell = from;
|
|
7022
|
+
do
|
|
7023
|
+
cell = {
|
|
7024
|
+
column: cell.column + stepColumn,
|
|
7025
|
+
row: cell.row + stepRow
|
|
7026
|
+
};
|
|
7027
|
+
while (inGrid(grid, cell) && grid.isInert(cell.column, cell.row));
|
|
7028
|
+
return inGrid(grid, cell) ? cell : void 0;
|
|
7029
|
+
};
|
|
7030
|
+
/**
|
|
7031
|
+
* Every slot of the blocks in reading order: block by block, each a row at a time.
|
|
7032
|
+
*
|
|
7033
|
+
* @param grid - The grid.
|
|
7034
|
+
* @param blocks - The blocks, left to right.
|
|
7035
|
+
* @return The slots in order.
|
|
7036
|
+
*/
|
|
7037
|
+
const readingOrder = (grid, blocks) => blocks.flatMap((block) => Array.from({ length: grid.rows }, (_row, row) => Array.from({ length: block.end - block.start }, (_offset, offset) => ({
|
|
7038
|
+
column: block.start + offset,
|
|
7039
|
+
row
|
|
7040
|
+
}))).flat());
|
|
7041
|
+
const blockOf = (blocks, column) => blocks.findIndex((block) => column >= block.start && column < block.end);
|
|
7042
|
+
/**
|
|
7043
|
+
* The slots after a cell down its column (or before it, going up), continuing at the
|
|
7044
|
+
* same column offset of each following block.
|
|
7045
|
+
*
|
|
7046
|
+
* @param grid - The grid.
|
|
7047
|
+
* @param blocks - The blocks, left to right.
|
|
7048
|
+
* @param from - The selected cell.
|
|
7049
|
+
* @param direction - 1 downwards, -1 upwards.
|
|
7050
|
+
* @return The slots in order.
|
|
7051
|
+
*/
|
|
7052
|
+
const columnOrderFrom = (grid, blocks, from, direction) => {
|
|
7053
|
+
const blockIndex = blockOf(blocks, from.column);
|
|
7054
|
+
if (blockIndex < 0) return [];
|
|
7055
|
+
const offset = from.column - blocks[blockIndex].start;
|
|
7056
|
+
const cells = [];
|
|
7057
|
+
const pushRows = (column, startRow) => {
|
|
7058
|
+
for (let row = startRow; row >= 0 && row < grid.rows; row += direction) cells.push({
|
|
7059
|
+
column,
|
|
7060
|
+
row
|
|
7061
|
+
});
|
|
7062
|
+
};
|
|
7063
|
+
pushRows(from.column, from.row + direction);
|
|
7064
|
+
for (let index = blockIndex + direction; index >= 0 && index < blocks.length; index += direction) {
|
|
7065
|
+
const column = blocks[index].start + offset;
|
|
7066
|
+
if (column < blocks[index].end) pushRows(column, direction === 1 ? 0 : grid.rows - 1);
|
|
6714
7067
|
}
|
|
6715
|
-
|
|
6716
|
-
if (!text) return null;
|
|
6717
|
-
if (!hasTimezone(text)) return writtenDayKey(text);
|
|
6718
|
-
const parsed = (0, date_fns.parseISO)(text);
|
|
6719
|
-
return isNaN(parsed.getTime()) ? null : readInstant(parsed);
|
|
7068
|
+
return cells;
|
|
6720
7069
|
};
|
|
6721
7070
|
/**
|
|
6722
|
-
*
|
|
7071
|
+
* The first selectable cell in calendar reading order.
|
|
6723
7072
|
*
|
|
6724
|
-
* @param
|
|
6725
|
-
* @param
|
|
6726
|
-
* @return The
|
|
7073
|
+
* @param grid - The grid.
|
|
7074
|
+
* @param blocks - The blocks, left to right.
|
|
7075
|
+
* @return The cell, or undefined when every slot is inert.
|
|
6727
7076
|
*/
|
|
6728
|
-
const
|
|
7077
|
+
const firstCalendarCell = (grid, blocks) => firstSelectable(grid, readingOrder(grid, blocks));
|
|
6729
7078
|
/**
|
|
6730
|
-
*
|
|
7079
|
+
* Steps through the blocks as pages of a calendar: Left/Right by one slot in reading
|
|
7080
|
+
* order, Up/Down by one row (into the neighboring block past the edge), Page Up/Down
|
|
7081
|
+
* to the same slot of the neighboring block or its nearest selectable cell.
|
|
6731
7082
|
*
|
|
6732
|
-
* @param
|
|
6733
|
-
* @param
|
|
6734
|
-
* @
|
|
7083
|
+
* @param grid - The grid.
|
|
7084
|
+
* @param blocks - The blocks, left to right.
|
|
7085
|
+
* @param from - The selected cell.
|
|
7086
|
+
* @param key - The navigation key.
|
|
7087
|
+
* @return The next cell, or undefined to keep the selection.
|
|
6735
7088
|
*/
|
|
6736
|
-
const
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
|
|
6743
|
-
|
|
6744
|
-
|
|
6745
|
-
|
|
6746
|
-
|
|
6747
|
-
|
|
6748
|
-
const
|
|
6749
|
-
|
|
6750
|
-
|
|
6751
|
-
|
|
6752
|
-
const
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
/**
|
|
6758
|
-
* Resolve one grid bound: an unparseable or narrowing value falls back to the
|
|
6759
|
-
* series' own bound, so the grid can only ever be widened.
|
|
6760
|
-
*
|
|
6761
|
-
* @param bound - Requested bound as `yyyy-MM-dd`, if any.
|
|
6762
|
-
* @param fallback - The series' own bound on this side.
|
|
6763
|
-
* @param direction - Which way the bound is allowed to move.
|
|
6764
|
-
* @return The day key to draw to.
|
|
6765
|
-
*/
|
|
6766
|
-
const widenTo = (bound, fallback, direction) => {
|
|
6767
|
-
const key = bound ? writtenDayKey(bound) : null;
|
|
6768
|
-
if (!key) {
|
|
6769
|
-
if (bound) warnOnce(`heatmap:gridSpan:${bound}`, `gridSpan.${direction === "earlier" ? "start" : "end"} ${JSON.stringify(bound)} is not a \`yyyy-MM-dd\` day, so the grid is drawn over the series' own span.`);
|
|
6770
|
-
return fallback;
|
|
6771
|
-
}
|
|
6772
|
-
if (direction === "earlier") return key < fallback ? key : fallback;
|
|
6773
|
-
return key > fallback ? key : fallback;
|
|
6774
|
-
};
|
|
6775
|
-
/**
|
|
6776
|
-
* Lay a day-bucketed series out as calendar columns.
|
|
6777
|
-
*
|
|
6778
|
-
* @param series - Points to bucket.
|
|
6779
|
-
* @param options - Grid shape, plus the locale and zone to read days in.
|
|
6780
|
-
* @return Columns and row labels for `HeatmapChart`.
|
|
6781
|
-
*/
|
|
6782
|
-
const buildCalendarHeatmapData = (series, options = {}) => {
|
|
6783
|
-
const weekStartsOn = options.weekStartsOn ?? 1;
|
|
6784
|
-
const hideOutOfRangeDays = options.hideOutOfRangeDays ?? true;
|
|
6785
|
-
const { locale, timeZone } = sanitizeFormatting({
|
|
6786
|
-
locale: options.locale,
|
|
6787
|
-
timeZone: options.timeZone
|
|
6788
|
-
});
|
|
6789
|
-
const readInstant = instantDayReader(timeZone);
|
|
6790
|
-
const valueByDay = /* @__PURE__ */ new Map();
|
|
6791
|
-
let minDayKey;
|
|
6792
|
-
let maxDayKey;
|
|
6793
|
-
for (const point of series) {
|
|
6794
|
-
const key = pointDayKey(point, readInstant);
|
|
6795
|
-
if (!key) {
|
|
6796
|
-
const offending = point.dateString ?? (point.date && String(point.date));
|
|
6797
|
-
warnOnce(`heatmap:unreadableDate:${offending}`, offending ? `${JSON.stringify(offending)} is not a day this can read, so its point is left out of the calendar. A \`dateString\` must start \`yyyy-MM-dd\`.` : "A point carries neither `date` nor `dateString`, so it is left out of the calendar.");
|
|
6798
|
-
continue;
|
|
6799
|
-
}
|
|
6800
|
-
valueByDay.set(key, point.value);
|
|
6801
|
-
if (!minDayKey || key < minDayKey) minDayKey = key;
|
|
6802
|
-
if (!maxDayKey || key > maxDayKey) maxDayKey = key;
|
|
6803
|
-
}
|
|
6804
|
-
if (!minDayKey || !maxDayKey) return {
|
|
6805
|
-
data: [],
|
|
6806
|
-
rowLabels: []
|
|
6807
|
-
};
|
|
6808
|
-
const requestedMinDayKey = widenTo(options.gridSpan?.start, minDayKey, "earlier");
|
|
6809
|
-
const gridMaxDayKey = widenTo(options.gridSpan?.end, maxDayKey, "later");
|
|
6810
|
-
const requestedMinDate = civilDate(requestedMinDayKey);
|
|
6811
|
-
const gridMaxDate = civilDate(gridMaxDayKey);
|
|
6812
|
-
const labelFormatting = {
|
|
6813
|
-
locale,
|
|
6814
|
-
timeZone: "UTC"
|
|
6815
|
-
};
|
|
6816
|
-
const formatWeekday = createDateFormatter({ weekday: "short" }, labelFormatting);
|
|
6817
|
-
const formatMonth = createDateFormatter({ month: "short" }, labelFormatting);
|
|
6818
|
-
const formatDay = createDateFormatter({
|
|
6819
|
-
weekday: "short",
|
|
6820
|
-
month: "short",
|
|
6821
|
-
day: "numeric",
|
|
6822
|
-
year: "numeric"
|
|
6823
|
-
}, labelFormatting);
|
|
6824
|
-
const gridStart = startOfCivilWeek(requestedMinDate, weekStartsOn);
|
|
6825
|
-
const gridMinDayKey = requestedMinDayKey < minDayKey ? civilKey(gridStart) : requestedMinDayKey;
|
|
6826
|
-
const weekCount = civilWeekSpan(gridStart, gridMaxDate, weekStartsOn);
|
|
6827
|
-
const rowLabels = Array.from({ length: 7 }, (_, row) => LABELLED_ROWS.includes(row) ? formatWeekday(addCivilDays(gridStart, row)) : "");
|
|
6828
|
-
const MIN_FIRST_MONTH_WEEKS = 2;
|
|
6829
|
-
const firstMonth = gridStart.getUTCMonth();
|
|
6830
|
-
let firstMonthWeeks = 0;
|
|
6831
|
-
while (firstMonthWeeks < weekCount && addCivilDays(gridStart, firstMonthWeeks * 7).getUTCMonth() === firstMonth) firstMonthWeeks++;
|
|
6832
|
-
const showFirstMonthLabel = !(firstMonthWeeks < weekCount) || firstMonthWeeks >= MIN_FIRST_MONTH_WEEKS;
|
|
6833
|
-
const data = [];
|
|
6834
|
-
let previousMonth = -1;
|
|
6835
|
-
for (let week = 0; week < weekCount; week++) {
|
|
6836
|
-
const columnStart = addCivilDays(gridStart, week * 7);
|
|
6837
|
-
const month = columnStart.getUTCMonth();
|
|
6838
|
-
const label = month !== previousMonth && (week !== 0 || showFirstMonthLabel) ? formatMonth(columnStart) : "";
|
|
6839
|
-
previousMonth = month;
|
|
6840
|
-
const cells = [];
|
|
6841
|
-
for (let row = 0; row < 7; row++) {
|
|
6842
|
-
const day = addCivilDays(gridStart, week * 7 + row);
|
|
6843
|
-
const key = civilKey(day);
|
|
6844
|
-
const cell = {
|
|
6845
|
-
label: formatDay(day),
|
|
6846
|
-
value: valueByDay.has(key) ? valueByDay.get(key) : null
|
|
6847
|
-
};
|
|
6848
|
-
if (key < gridMinDayKey || key > gridMaxDayKey) {
|
|
6849
|
-
if (hideOutOfRangeDays) cell.hidden = true;
|
|
6850
|
-
} else if (key < minDayKey || key > maxDayKey) cell.placeholder = true;
|
|
6851
|
-
cells.push(cell);
|
|
6852
|
-
}
|
|
6853
|
-
data.push({
|
|
6854
|
-
label,
|
|
6855
|
-
data: cells
|
|
6856
|
-
});
|
|
6857
|
-
}
|
|
6858
|
-
return {
|
|
6859
|
-
data,
|
|
6860
|
-
rowLabels
|
|
6861
|
-
};
|
|
6862
|
-
};
|
|
6863
|
-
//#endregion
|
|
6864
|
-
//#region src/charts/heatmap-chart/private/heatmap-context.ts
|
|
6865
|
-
/** Shared by the chart and legend without importing back from `heatmap-chart.tsx`. */
|
|
6866
|
-
const HeatmapContext = (0, react.createContext)(null);
|
|
6867
|
-
//#endregion
|
|
6868
|
-
//#region src/charts/heatmap-chart/private/heatmap-legend.tsx
|
|
6869
|
-
const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
6870
|
-
const context = (0, react.useContext)(HeatmapContext);
|
|
6871
|
-
const { legend } = useGlobalChartsTheme();
|
|
6872
|
-
if (!context) return null;
|
|
6873
|
-
const { primaryColorHex } = context;
|
|
6874
|
-
const labelStyle = legend.labelStyles;
|
|
6875
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
6876
|
-
direction: "row",
|
|
6877
|
-
gap: "xs",
|
|
6878
|
-
align: "center",
|
|
6879
|
-
children: [
|
|
6880
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6881
|
-
variant: "body-sm",
|
|
6882
|
-
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6883
|
-
style: labelStyle,
|
|
6884
|
-
children: lessLabel ?? (0, _wordpress_i18n.__)("Less", "jetpack-charts")
|
|
6885
|
-
}),
|
|
6886
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Stack, {
|
|
6887
|
-
direction: "row",
|
|
6888
|
-
gap: "xs",
|
|
6889
|
-
children: Array.from({ length: steps }, (_, index) => {
|
|
6890
|
-
const intensity = steps <= 1 ? 1 : index / (steps - 1);
|
|
6891
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6892
|
-
"aria-hidden": "true",
|
|
6893
|
-
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
6894
|
-
style: {
|
|
6895
|
-
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6896
|
-
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
6897
|
-
}
|
|
6898
|
-
}, index);
|
|
6899
|
-
})
|
|
6900
|
-
}),
|
|
6901
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6902
|
-
variant: "body-sm",
|
|
6903
|
-
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6904
|
-
style: labelStyle,
|
|
6905
|
-
children: moreLabel ?? (0, _wordpress_i18n.__)("More", "jetpack-charts")
|
|
6906
|
-
})
|
|
6907
|
-
]
|
|
6908
|
-
});
|
|
7089
|
+
const stepCalendarCell = (grid, blocks, from, key) => {
|
|
7090
|
+
if (key === "ArrowRight" || key === "ArrowLeft") {
|
|
7091
|
+
const order = readingOrder(grid, blocks);
|
|
7092
|
+
const index = order.findIndex((cell) => cell.column === from.column && cell.row === from.row);
|
|
7093
|
+
if (index < 0) return;
|
|
7094
|
+
const ahead = key === "ArrowRight" ? order.slice(index + 1) : order.slice(0, index).reverse();
|
|
7095
|
+
return firstSelectable(grid, ahead);
|
|
7096
|
+
}
|
|
7097
|
+
if (key === "ArrowDown" || key === "ArrowUp") return firstSelectable(grid, columnOrderFrom(grid, blocks, from, key === "ArrowDown" ? 1 : -1));
|
|
7098
|
+
const blockIndex = blockOf(blocks, from.column);
|
|
7099
|
+
const target = blocks[blockIndex + (key === "PageDown" ? 1 : -1)];
|
|
7100
|
+
if (blockIndex < 0 || !target) return;
|
|
7101
|
+
const same = {
|
|
7102
|
+
column: target.start + (from.column - blocks[blockIndex].start),
|
|
7103
|
+
row: from.row
|
|
7104
|
+
};
|
|
7105
|
+
const page = readingOrder(grid, [target]);
|
|
7106
|
+
const at = page.findIndex((cell) => cell.row > same.row || cell.row === same.row && cell.column >= same.column);
|
|
7107
|
+
const after = at === -1 ? [] : page.slice(at);
|
|
7108
|
+
const before = page.slice(0, at === -1 ? page.length : at).reverse();
|
|
7109
|
+
return firstSelectable(grid, after) ?? firstSelectable(grid, before);
|
|
6909
7110
|
};
|
|
6910
7111
|
//#endregion
|
|
6911
7112
|
//#region src/charts/heatmap-chart/heatmap-chart.tsx
|
|
6912
7113
|
const CELL_MIX_FLOOR = .15;
|
|
6913
7114
|
const NO_ROW_LABELS = [];
|
|
6914
|
-
const
|
|
7115
|
+
const TOOLTIP_BOX_STYLES = {
|
|
7116
|
+
light: {
|
|
7117
|
+
..._visx_tooltip.defaultStyles,
|
|
7118
|
+
zIndex: 3
|
|
7119
|
+
},
|
|
7120
|
+
dark: { zIndex: 3 }
|
|
7121
|
+
};
|
|
7122
|
+
const cellName = (info) => info.cellLabel || [
|
|
7123
|
+
info.groupLabel,
|
|
7124
|
+
info.columnLabel,
|
|
7125
|
+
info.rowLabel
|
|
7126
|
+
].filter(Boolean).join(" ");
|
|
7127
|
+
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, tooltipVariant = "light", tooltipStyle, children }) => {
|
|
6915
7128
|
const chartId = useChartId(providedChartId);
|
|
7129
|
+
const tooltipBoxStyle = tooltipStyle ? {
|
|
7130
|
+
...TOOLTIP_BOX_STYLES[tooltipVariant],
|
|
7131
|
+
...tooltipStyle
|
|
7132
|
+
} : TOOLTIP_BOX_STYLES[tooltipVariant];
|
|
6916
7133
|
const { getElementStyles, theme } = useGlobalChartsContext();
|
|
6917
7134
|
const scopeElement = useChartScopeElement();
|
|
6918
7135
|
const { heatmapChart: heatmapChartSettings } = theme;
|
|
6919
7136
|
const { nonLegendChildren } = useChartChildren(children, "HeatmapChart");
|
|
6920
|
-
const [
|
|
7137
|
+
const [selected, setSelected] = (0, react.useState)();
|
|
6921
7138
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
6922
7139
|
const standaloneScopeClass = useStandaloneScopeClass();
|
|
6923
7140
|
const containerRef = (0, react.useRef)(null);
|
|
@@ -6936,69 +7153,75 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6936
7153
|
}), [extent, primaryColorHex]);
|
|
6937
7154
|
const columns = data.length;
|
|
6938
7155
|
const rows = Math.max(0, ...data.map((column) => column.data.length));
|
|
6939
|
-
const
|
|
7156
|
+
const groupLayout = (0, react.useMemo)(() => resolveColumnGroups(columnGroups, columns, 2), [columnGroups, columns]);
|
|
7157
|
+
const { compactCellGap, compactCellSize, groupGap } = heatmapChartSettings;
|
|
6940
7158
|
const drawValues = showValues ?? !compact;
|
|
6941
7159
|
const buildTooltipData = (0, react.useCallback)((columnIndex, rowIndex) => {
|
|
6942
7160
|
const cell = data[columnIndex]?.data[rowIndex];
|
|
7161
|
+
const group = groupLayout.columns[columnIndex]?.group;
|
|
6943
7162
|
return {
|
|
6944
7163
|
value: cell?.value ?? null,
|
|
6945
7164
|
rowLabel: rowLabels[rowIndex],
|
|
6946
7165
|
columnLabel: data[columnIndex]?.label,
|
|
7166
|
+
groupLabel: group === void 0 ? void 0 : groupLayout.groups[group]?.label,
|
|
6947
7167
|
cellLabel: cell?.label,
|
|
6948
7168
|
row: rowIndex,
|
|
6949
7169
|
column: columnIndex
|
|
6950
7170
|
};
|
|
6951
|
-
}, [
|
|
7171
|
+
}, [
|
|
7172
|
+
data,
|
|
7173
|
+
rowLabels,
|
|
7174
|
+
groupLayout
|
|
7175
|
+
]);
|
|
6952
7176
|
const onChartBlur = (0, react.useCallback)(() => {
|
|
6953
|
-
|
|
7177
|
+
setSelected(void 0);
|
|
6954
7178
|
hideTooltip();
|
|
6955
7179
|
}, [hideTooltip]);
|
|
6956
7180
|
const isCellInert = (0, react.useCallback)((col, row) => {
|
|
6957
7181
|
const cell = data[col]?.data[row];
|
|
6958
7182
|
return cell?.hidden === true || cell?.placeholder === true;
|
|
6959
7183
|
}, [data]);
|
|
7184
|
+
const blocks = (0, react.useMemo)(() => {
|
|
7185
|
+
const grouped = groupLayout.groups.map((group, index) => {
|
|
7186
|
+
const start = groupLayout.columns.findIndex((column) => column.group === index);
|
|
7187
|
+
return {
|
|
7188
|
+
start,
|
|
7189
|
+
end: start + group.span
|
|
7190
|
+
};
|
|
7191
|
+
});
|
|
7192
|
+
const groupedEnd = grouped.length ? grouped[grouped.length - 1].end : 0;
|
|
7193
|
+
return groupedEnd < columns ? [...grouped, {
|
|
7194
|
+
start: groupedEnd,
|
|
7195
|
+
end: columns
|
|
7196
|
+
}] : grouped;
|
|
7197
|
+
}, [groupLayout, columns]);
|
|
6960
7198
|
const onChartKeyDown = (0, react.useCallback)((event) => {
|
|
6961
|
-
if (![
|
|
6962
|
-
"ArrowLeft",
|
|
6963
|
-
"ArrowRight",
|
|
6964
|
-
"ArrowUp",
|
|
6965
|
-
"ArrowDown",
|
|
6966
|
-
"Escape",
|
|
6967
|
-
"Tab"
|
|
6968
|
-
].includes(event.key)) return;
|
|
6969
7199
|
if (event.key === "Tab" || event.key === "Escape") {
|
|
6970
|
-
|
|
7200
|
+
setSelected(void 0);
|
|
6971
7201
|
hideTooltip();
|
|
6972
7202
|
return;
|
|
6973
7203
|
}
|
|
7204
|
+
if (!isNavigationKey(event.key, keyboardNavigation)) return;
|
|
6974
7205
|
event.preventDefault();
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
7206
|
+
const grid = {
|
|
7207
|
+
columns,
|
|
7208
|
+
rows,
|
|
7209
|
+
isInert: isCellInert
|
|
7210
|
+
};
|
|
7211
|
+
if (selected === void 0) {
|
|
7212
|
+
setSelected(keyboardNavigation === "calendar" ? firstCalendarCell(grid, blocks) : firstGridCell(grid));
|
|
6980
7213
|
return;
|
|
6981
7214
|
}
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
if (event.key === "ArrowRight") stepCol = 1;
|
|
6985
|
-
else if (event.key === "ArrowLeft") stepCol = -1;
|
|
6986
|
-
else if (event.key === "ArrowDown") stepRow = 1;
|
|
6987
|
-
else if (event.key === "ArrowUp") stepRow = -1;
|
|
6988
|
-
let col = Math.floor(selectedIndex / rows);
|
|
6989
|
-
let row = selectedIndex % rows;
|
|
6990
|
-
do {
|
|
6991
|
-
col += stepCol;
|
|
6992
|
-
row += stepRow;
|
|
6993
|
-
} while (col >= 0 && col < columns && row >= 0 && row < rows && isCellInert(col, row));
|
|
6994
|
-
if (col < 0 || col >= columns || row < 0 || row >= rows) return;
|
|
6995
|
-
setSelectedIndex(col * rows + row);
|
|
7215
|
+
const next = keyboardNavigation === "calendar" ? stepCalendarCell(grid, blocks, selected, event.key) : stepGridCell(grid, selected, event.key);
|
|
7216
|
+
if (next) setSelected(next);
|
|
6996
7217
|
}, [
|
|
6997
7218
|
rows,
|
|
6998
7219
|
columns,
|
|
6999
|
-
|
|
7220
|
+
selected,
|
|
7000
7221
|
hideTooltip,
|
|
7001
|
-
isCellInert
|
|
7222
|
+
isCellInert,
|
|
7223
|
+
keyboardNavigation,
|
|
7224
|
+
blocks
|
|
7002
7225
|
]);
|
|
7003
7226
|
const handleCellMouseMove = (0, react.useCallback)((event) => {
|
|
7004
7227
|
if (!withTooltips) return;
|
|
@@ -7018,35 +7241,47 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7018
7241
|
buildTooltipData,
|
|
7019
7242
|
getTooltipOrigin
|
|
7020
7243
|
]);
|
|
7244
|
+
const getCellElement = (0, react.useCallback)((col, row) => typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null, [chartId]);
|
|
7021
7245
|
const handleCellMouseLeave = (0, react.useCallback)(() => {
|
|
7022
|
-
if (withTooltips &&
|
|
7246
|
+
if (withTooltips && selected === void 0) hideTooltip();
|
|
7023
7247
|
}, [
|
|
7024
7248
|
withTooltips,
|
|
7025
|
-
|
|
7249
|
+
selected,
|
|
7026
7250
|
hideTooltip
|
|
7027
7251
|
]);
|
|
7028
7252
|
(0, react.useEffect)(() => {
|
|
7029
|
-
if (
|
|
7253
|
+
if (selected && (selected.column >= columns || selected.row >= rows)) setSelected(void 0);
|
|
7254
|
+
}, [
|
|
7255
|
+
selected,
|
|
7256
|
+
columns,
|
|
7257
|
+
rows
|
|
7258
|
+
]);
|
|
7259
|
+
(0, react.useEffect)(() => {
|
|
7260
|
+
if (selected === void 0) return;
|
|
7261
|
+
getCellElement(selected.column, selected.row)?.scrollIntoView?.({
|
|
7262
|
+
block: "nearest",
|
|
7263
|
+
inline: "nearest"
|
|
7264
|
+
});
|
|
7265
|
+
}, [selected, getCellElement]);
|
|
7266
|
+
(0, react.useEffect)(() => {
|
|
7267
|
+
if (!withTooltips || selected === void 0) return;
|
|
7030
7268
|
const origin = getTooltipOrigin();
|
|
7031
7269
|
if (!origin) return;
|
|
7032
|
-
const
|
|
7033
|
-
const row = selectedIndex % rows;
|
|
7034
|
-
const rect = (typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null)?.getBoundingClientRect();
|
|
7270
|
+
const rect = getCellElement(selected.column, selected.row)?.getBoundingClientRect();
|
|
7035
7271
|
showTooltip({
|
|
7036
7272
|
tooltipLeft: rect ? rect.left + rect.width / 2 - origin.left : 0,
|
|
7037
7273
|
tooltipTop: rect ? rect.top + rect.height / 2 - origin.top : 0,
|
|
7038
|
-
tooltipData: buildTooltipData(
|
|
7274
|
+
tooltipData: buildTooltipData(selected.column, selected.row)
|
|
7039
7275
|
});
|
|
7040
7276
|
}, [
|
|
7041
|
-
|
|
7277
|
+
selected,
|
|
7042
7278
|
withTooltips,
|
|
7043
|
-
|
|
7044
|
-
chartId,
|
|
7279
|
+
getCellElement,
|
|
7045
7280
|
buildTooltipData,
|
|
7046
7281
|
showTooltip,
|
|
7047
7282
|
getTooltipOrigin
|
|
7048
7283
|
]);
|
|
7049
|
-
const defaultRenderTooltip = (0, react.useCallback)((info) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: info
|
|
7284
|
+
const defaultRenderTooltip = (0, react.useCallback)((info) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: cellName(info) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: info.value === null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(info.value) })] }), []);
|
|
7050
7285
|
if (!columns || !rows) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Center, {
|
|
7051
7286
|
className: (0, clsx.default)("heatmap-chart", heatmap_chart_module_default["heatmap-chart"], className),
|
|
7052
7287
|
style: {
|
|
@@ -7060,10 +7295,16 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7060
7295
|
});
|
|
7061
7296
|
const columnTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellWidth ?? 0}px, ${maxCellWidth ? `${maxCellWidth}px` : "1fr"})`;
|
|
7062
7297
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
7298
|
+
const hasColumnLabels = data.some((column) => Boolean(column.label));
|
|
7299
|
+
const hasGroups = groupLayout.groups.length > 0;
|
|
7300
|
+
const columnLine = (columnIndex) => groupLayout.columns[columnIndex].line;
|
|
7301
|
+
const firstDataRow = hasColumnLabels ? 2 : 1;
|
|
7302
|
+
const dataTrack = (column) => column.summary ? "minmax(auto, max-content)" : columnTrack;
|
|
7303
|
+
const gapTrack = compact ? `minmax(${groupGap}px, 1fr)` : `${groupGap}px`;
|
|
7063
7304
|
const gridStyle = {
|
|
7064
7305
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
7065
|
-
gridTemplateColumns: `auto ${data.
|
|
7066
|
-
gridTemplateRows:
|
|
7306
|
+
gridTemplateColumns: `auto ${data.map((column, columnIndex) => groupLayout.columns[columnIndex].gapBefore ? `${gapTrack} ${dataTrack(column)}` : dataTrack(column)).join(" ")}`,
|
|
7307
|
+
gridTemplateRows: `${hasColumnLabels ? "auto " : ""}repeat(${rows}, ${rowTrack})${hasGroups ? " auto" : ""}`
|
|
7067
7308
|
};
|
|
7068
7309
|
if (compact) {
|
|
7069
7310
|
gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
|
|
@@ -7076,7 +7317,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7076
7317
|
[heatmap_chart_module_default["heatmap-chart__gap-end"]]: columnIndex < columns - 1 && !data[columnIndex + 1]?.summary
|
|
7077
7318
|
};
|
|
7078
7319
|
};
|
|
7079
|
-
const activeDescendant =
|
|
7320
|
+
const activeDescendant = selected ? `${chartId}-cell-${selected.column}-${selected.row}` : void 0;
|
|
7080
7321
|
const heightCapped = !compact && Boolean(maxCellHeight);
|
|
7081
7322
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HeatmapContext.Provider, {
|
|
7082
7323
|
value: heatmapContext,
|
|
@@ -7096,7 +7337,7 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7096
7337
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7097
7338
|
ref: containerRef,
|
|
7098
7339
|
role: "grid",
|
|
7099
|
-
"aria-label": (0, _wordpress_i18n.__)("Heatmap chart", "jetpack-charts"),
|
|
7340
|
+
"aria-label": ariaLabel ?? (0, _wordpress_i18n.__)("Heatmap chart", "jetpack-charts"),
|
|
7100
7341
|
"aria-rowcount": rows,
|
|
7101
7342
|
"aria-colcount": columns,
|
|
7102
7343
|
"aria-activedescendant": activeDescendant,
|
|
@@ -7105,76 +7346,115 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
7105
7346
|
onKeyDown: onChartKeyDown,
|
|
7106
7347
|
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__grid"], {
|
|
7107
7348
|
[heatmap_chart_module_default["heatmap-chart__grid--compact"]]: compact,
|
|
7349
|
+
[heatmap_chart_module_default["heatmap-chart__grid--flex-gaps"]]: compact && hasGroups,
|
|
7108
7350
|
[heatmap_chart_module_default["heatmap-chart__grid--height-capped"]]: heightCapped
|
|
7109
7351
|
}),
|
|
7110
7352
|
style: gridStyle,
|
|
7111
|
-
children: [
|
|
7112
|
-
|
|
7113
|
-
"aria-hidden": "true",
|
|
7114
|
-
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
7115
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), data.map((column, columnIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7116
|
-
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
7117
|
-
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
7118
|
-
...summaryGaps(columnIndex)
|
|
7119
|
-
}),
|
|
7120
|
-
children: column.label
|
|
7121
|
-
}, `col-${columnIndex}`))]
|
|
7122
|
-
}), Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
7123
|
-
const labelVisible = !compact || rowIndex % 2 === 0;
|
|
7124
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7353
|
+
children: [
|
|
7354
|
+
hasColumnLabels && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7125
7355
|
role: "row",
|
|
7126
|
-
"aria-
|
|
7356
|
+
"aria-hidden": "true",
|
|
7127
7357
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
7128
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7358
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
|
|
7359
|
+
gridColumn: 1,
|
|
7360
|
+
gridRow: 1
|
|
7361
|
+
} }), data.map((column, columnIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7362
|
+
style: {
|
|
7363
|
+
gridColumn: columnLine(columnIndex),
|
|
7364
|
+
gridRow: 1
|
|
7365
|
+
},
|
|
7366
|
+
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
7367
|
+
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
7368
|
+
...summaryGaps(columnIndex)
|
|
7369
|
+
}),
|
|
7370
|
+
children: column.label
|
|
7371
|
+
}, `col-${columnIndex}`))]
|
|
7372
|
+
}),
|
|
7373
|
+
Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
7374
|
+
const labelVisible = !compact || rowIndex % 2 === 0;
|
|
7375
|
+
const gridRow = firstDataRow + rowIndex;
|
|
7376
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
7377
|
+
role: "row",
|
|
7378
|
+
"aria-rowindex": rowIndex + 1,
|
|
7379
|
+
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
7380
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7139
7381
|
"aria-hidden": "true",
|
|
7140
|
-
className:
|
|
7141
|
-
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7149
|
-
|
|
7150
|
-
|
|
7151
|
-
|
|
7152
|
-
|
|
7153
|
-
|
|
7154
|
-
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
[heatmap_chart_module_default["heatmap-chart__cell--
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7382
|
+
className: heatmap_chart_module_default["heatmap-chart__row-label"],
|
|
7383
|
+
style: {
|
|
7384
|
+
gridColumn: 1,
|
|
7385
|
+
gridRow
|
|
7386
|
+
},
|
|
7387
|
+
children: labelVisible ? rowLabels[rowIndex] ?? "" : ""
|
|
7388
|
+
}), data.map((column, columnIndex) => {
|
|
7389
|
+
const cell = column.data[rowIndex];
|
|
7390
|
+
const placement = {
|
|
7391
|
+
gridColumn: columnLine(columnIndex),
|
|
7392
|
+
gridRow
|
|
7393
|
+
};
|
|
7394
|
+
if (cell?.hidden) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7395
|
+
"aria-hidden": "true",
|
|
7396
|
+
style: placement,
|
|
7397
|
+
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--hidden"])
|
|
7398
|
+
}, `cell-${columnIndex}-${rowIndex}`);
|
|
7399
|
+
if (cell?.placeholder) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7400
|
+
"aria-hidden": "true",
|
|
7401
|
+
style: placement,
|
|
7402
|
+
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__cell"], heatmap_chart_module_default["heatmap-chart__cell--placeholder"])
|
|
7403
|
+
}, `cell-${columnIndex}-${rowIndex}`);
|
|
7404
|
+
const value = cell?.value ?? null;
|
|
7405
|
+
const present = isPresent(value);
|
|
7406
|
+
const filled = present && !column.summary;
|
|
7407
|
+
const normalized = filled ? getNormalizedValue(value, extent) : 0;
|
|
7408
|
+
const info = buildTooltipData(columnIndex, rowIndex);
|
|
7409
|
+
const accessibleLabel = `${cellName(info)}: ${info.value === null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(info.value)}`;
|
|
7410
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7411
|
+
id: `${chartId}-cell-${columnIndex}-${rowIndex}`,
|
|
7412
|
+
role: "gridcell",
|
|
7413
|
+
tabIndex: -1,
|
|
7414
|
+
"aria-colindex": columnIndex + 1,
|
|
7415
|
+
"aria-label": accessibleLabel,
|
|
7416
|
+
"data-column": columnIndex,
|
|
7417
|
+
"data-row": rowIndex,
|
|
7418
|
+
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__cell"], {
|
|
7419
|
+
[heatmap_chart_module_default["heatmap-chart__cell--filled"]]: filled,
|
|
7420
|
+
[heatmap_chart_module_default["heatmap-chart__cell--strong"]]: filled && cellHasLightText(normalized),
|
|
7421
|
+
[heatmap_chart_module_default["heatmap-chart__cell--summary"]]: column.summary,
|
|
7422
|
+
...summaryGaps(columnIndex),
|
|
7423
|
+
[heatmap_chart_module_default["heatmap-chart__cell--selected"]]: selected?.column === columnIndex && selected?.row === rowIndex
|
|
7424
|
+
}),
|
|
7425
|
+
style: {
|
|
7426
|
+
...placement,
|
|
7427
|
+
...filled ? { "--a8c-charts-heatmap-cell-intensity": normalized } : {}
|
|
7428
|
+
},
|
|
7429
|
+
onMouseMove: handleCellMouseMove,
|
|
7430
|
+
onMouseLeave: handleCellMouseLeave,
|
|
7431
|
+
children: (drawValues || column.summary) && present && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7432
|
+
className: heatmap_chart_module_default["heatmap-chart__cell-value"],
|
|
7433
|
+
children: (0, _automattic_number_formatters.formatNumberCompact)(value)
|
|
7434
|
+
})
|
|
7435
|
+
}, `cell-${columnIndex}-${rowIndex}`);
|
|
7436
|
+
})]
|
|
7437
|
+
}, `row-${rowIndex}`);
|
|
7438
|
+
}),
|
|
7439
|
+
hasGroups && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7440
|
+
role: "row",
|
|
7441
|
+
"aria-hidden": "true",
|
|
7442
|
+
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
7443
|
+
children: groupLayout.groups.map((group, groupIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7444
|
+
className: heatmap_chart_module_default["heatmap-chart__group-label"],
|
|
7445
|
+
style: {
|
|
7446
|
+
gridColumn: `${group.line} / span ${group.span}`,
|
|
7447
|
+
gridRow: firstDataRow + rows
|
|
7448
|
+
},
|
|
7449
|
+
children: group.label
|
|
7450
|
+
}, `group-${groupIndex}`))
|
|
7451
|
+
})
|
|
7452
|
+
]
|
|
7175
7453
|
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
7176
7454
|
top: tooltipTop,
|
|
7177
7455
|
left: tooltipLeft,
|
|
7456
|
+
className: tooltipVariant === "dark" ? base_tooltip_module_default.surface : void 0,
|
|
7457
|
+
style: tooltipBoxStyle,
|
|
7178
7458
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7179
7459
|
className: standaloneScopeClass,
|
|
7180
7460
|
role: "tooltip",
|
|
@@ -7200,6 +7480,342 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ (0, react_jsx_run
|
|
|
7200
7480
|
HeatmapChartResponsiveInner.displayName = "HeatmapChart";
|
|
7201
7481
|
const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
|
|
7202
7482
|
//#endregion
|
|
7483
|
+
//#region src/charts/heatmap-chart/private/civil-day.ts
|
|
7484
|
+
const DAY_MS = 864e5;
|
|
7485
|
+
const KEY_OPTIONS = {
|
|
7486
|
+
calendar: "gregory",
|
|
7487
|
+
numberingSystem: "latn",
|
|
7488
|
+
year: "numeric",
|
|
7489
|
+
month: "2-digit",
|
|
7490
|
+
day: "2-digit"
|
|
7491
|
+
};
|
|
7492
|
+
const DATE_PREFIX = /^(\d{4})-(\d{2})-(\d{2})/;
|
|
7493
|
+
/**
|
|
7494
|
+
* Label formatters for UTC proxies, so both calendar layouts name a day alike.
|
|
7495
|
+
*
|
|
7496
|
+
* `gregory` keeps a locale whose default calendar is not Gregorian (fa-IR) from
|
|
7497
|
+
* splitting one grid month across two names.
|
|
7498
|
+
*
|
|
7499
|
+
* @param locale - BCP 47 locale.
|
|
7500
|
+
* @return Weekday, month and full-day formatters.
|
|
7501
|
+
*/
|
|
7502
|
+
const civilLabelFormatters = (locale) => {
|
|
7503
|
+
const formatting = {
|
|
7504
|
+
locale,
|
|
7505
|
+
timeZone: "UTC"
|
|
7506
|
+
};
|
|
7507
|
+
return {
|
|
7508
|
+
formatWeekday: createDateFormatter({
|
|
7509
|
+
weekday: "short",
|
|
7510
|
+
calendar: "gregory"
|
|
7511
|
+
}, formatting),
|
|
7512
|
+
formatMonth: createDateFormatter({
|
|
7513
|
+
month: "short",
|
|
7514
|
+
calendar: "gregory"
|
|
7515
|
+
}, formatting),
|
|
7516
|
+
formatMonthYear: createDateFormatter({
|
|
7517
|
+
month: "short",
|
|
7518
|
+
year: "numeric",
|
|
7519
|
+
calendar: "gregory"
|
|
7520
|
+
}, formatting),
|
|
7521
|
+
formatDay: createDateFormatter({
|
|
7522
|
+
weekday: "short",
|
|
7523
|
+
month: "short",
|
|
7524
|
+
day: "numeric",
|
|
7525
|
+
year: "numeric",
|
|
7526
|
+
calendar: "gregory"
|
|
7527
|
+
}, formatting)
|
|
7528
|
+
};
|
|
7529
|
+
};
|
|
7530
|
+
const pad = (value, length) => String(value).padStart(length, "0");
|
|
7531
|
+
/**
|
|
7532
|
+
* The day a UTC proxy stands for.
|
|
7533
|
+
*
|
|
7534
|
+
* @param date - UTC proxy.
|
|
7535
|
+
* @return Its day key.
|
|
7536
|
+
*/
|
|
7537
|
+
const civilKey = (date) => `${pad(date.getUTCFullYear(), 4)}-${pad(date.getUTCMonth() + 1, 2)}-${pad(date.getUTCDate(), 2)}`;
|
|
7538
|
+
/**
|
|
7539
|
+
* A day key as a UTC-midnight proxy. UTC has no DST, so every step below is exactly
|
|
7540
|
+
* `DAY_MS`.
|
|
7541
|
+
*
|
|
7542
|
+
* @param key - Day key.
|
|
7543
|
+
* @return The proxy, or null when the key names no real day.
|
|
7544
|
+
*/
|
|
7545
|
+
const civilDate = (key) => {
|
|
7546
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(key);
|
|
7547
|
+
if (!match) return null;
|
|
7548
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
7549
|
+
date.setUTCFullYear(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
|
|
7550
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
7551
|
+
return civilKey(date) === key ? date : null;
|
|
7552
|
+
};
|
|
7553
|
+
/**
|
|
7554
|
+
* The day a written date names, ignoring any time and zone it carries.
|
|
7555
|
+
*
|
|
7556
|
+
* @param text - `yyyy-MM-dd`, optionally followed by a time.
|
|
7557
|
+
* @return Its day key, or null.
|
|
7558
|
+
*/
|
|
7559
|
+
const writtenDayKey = (text) => {
|
|
7560
|
+
const match = DATE_PREFIX.exec(text);
|
|
7561
|
+
if (!match) return null;
|
|
7562
|
+
const key = `${match[1]}-${match[2]}-${match[3]}`;
|
|
7563
|
+
return civilDate(key) ? key : null;
|
|
7564
|
+
};
|
|
7565
|
+
/**
|
|
7566
|
+
* Reads the day an instant falls on in a zone.
|
|
7567
|
+
*
|
|
7568
|
+
* @param timeZone - IANA zone name; absent leaves the runtime's own.
|
|
7569
|
+
* @return Reader taking a `Date`, null for a day no key can hold.
|
|
7570
|
+
*/
|
|
7571
|
+
const instantDayReader = (timeZone) => {
|
|
7572
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
7573
|
+
...KEY_OPTIONS,
|
|
7574
|
+
timeZone
|
|
7575
|
+
});
|
|
7576
|
+
return (date) => {
|
|
7577
|
+
const parts = formatter.formatToParts(date);
|
|
7578
|
+
const read = (type) => parts.find((part) => part.type === type)?.value ?? "";
|
|
7579
|
+
const key = `${pad(Number(read("year")), 4)}-${read("month")}-${read("day")}`;
|
|
7580
|
+
return civilDate(key) ? key : null;
|
|
7581
|
+
};
|
|
7582
|
+
};
|
|
7583
|
+
/**
|
|
7584
|
+
* The day a series point belongs to.
|
|
7585
|
+
*
|
|
7586
|
+
* A `Date`, or a string carrying `Z` or an offset, is an instant read in the host's
|
|
7587
|
+
* zone. Anything else is a wall clock the host wrote, so its date part is the day.
|
|
7588
|
+
*
|
|
7589
|
+
* @param point - Series point.
|
|
7590
|
+
* @param readInstant - Reader from `instantDayReader`.
|
|
7591
|
+
* @return Its day key, or null when the point carries no usable date.
|
|
7592
|
+
*/
|
|
7593
|
+
const pointDayKey = (point, readInstant) => {
|
|
7594
|
+
if (point.date instanceof Date && !isNaN(point.date.getTime())) {
|
|
7595
|
+
const key = readInstant(point.date);
|
|
7596
|
+
if (key) return key;
|
|
7597
|
+
}
|
|
7598
|
+
const text = point.dateString;
|
|
7599
|
+
if (!text) return null;
|
|
7600
|
+
if (!hasTimezone(text)) return writtenDayKey(text);
|
|
7601
|
+
const parsed = (0, date_fns.parseISO)(text);
|
|
7602
|
+
return isNaN(parsed.getTime()) ? null : readInstant(parsed);
|
|
7603
|
+
};
|
|
7604
|
+
/**
|
|
7605
|
+
* Steps a proxy by whole days.
|
|
7606
|
+
*
|
|
7607
|
+
* @param date - UTC proxy.
|
|
7608
|
+
* @param days - Days to add; may be negative.
|
|
7609
|
+
* @return The shifted proxy.
|
|
7610
|
+
*/
|
|
7611
|
+
const addCivilDays = (date, days) => new Date(date.getTime() + days * DAY_MS);
|
|
7612
|
+
/**
|
|
7613
|
+
* Rounds a proxy down to its week.
|
|
7614
|
+
*
|
|
7615
|
+
* @param date - UTC proxy.
|
|
7616
|
+
* @param weekStartsOn - 0 for Sunday, 1 for Monday.
|
|
7617
|
+
* @return The proxy for that week's first day.
|
|
7618
|
+
*/
|
|
7619
|
+
const startOfCivilWeek = (date, weekStartsOn) => {
|
|
7620
|
+
const daysSinceWeekStart = (date.getUTCDay() - weekStartsOn + 7) % 7;
|
|
7621
|
+
return addCivilDays(date, -daysSinceWeekStart);
|
|
7622
|
+
};
|
|
7623
|
+
/**
|
|
7624
|
+
* Counts the columns a span needs.
|
|
7625
|
+
*
|
|
7626
|
+
* @param from - Earlier UTC proxy.
|
|
7627
|
+
* @param to - Later UTC proxy.
|
|
7628
|
+
* @param weekStartsOn - 0 for Sunday, 1 for Monday.
|
|
7629
|
+
* @return Columns needed to cover the span, inclusive.
|
|
7630
|
+
*/
|
|
7631
|
+
const civilWeekSpan = (from, to, weekStartsOn) => Math.floor((startOfCivilWeek(to, weekStartsOn).getTime() - startOfCivilWeek(from, weekStartsOn).getTime()) / (7 * DAY_MS)) + 1;
|
|
7632
|
+
//#endregion
|
|
7633
|
+
//#region src/charts/heatmap-chart/build-calendar-data.ts
|
|
7634
|
+
/** Rows that get a weekday label (Mon, Wed, Fri with a Monday week start). */
|
|
7635
|
+
const LABELLED_ROWS = [
|
|
7636
|
+
0,
|
|
7637
|
+
2,
|
|
7638
|
+
4
|
|
7639
|
+
];
|
|
7640
|
+
/**
|
|
7641
|
+
* Resolve one grid bound: an unparseable or narrowing value falls back to the
|
|
7642
|
+
* series' own bound, so the grid can only ever be widened.
|
|
7643
|
+
*
|
|
7644
|
+
* @param bound - Requested bound as `yyyy-MM-dd`, if any.
|
|
7645
|
+
* @param fallback - The series' own bound on this side.
|
|
7646
|
+
* @param direction - Which way the bound is allowed to move.
|
|
7647
|
+
* @return The day key to draw to.
|
|
7648
|
+
*/
|
|
7649
|
+
const widenTo = (bound, fallback, direction) => {
|
|
7650
|
+
const key = bound ? writtenDayKey(bound) : null;
|
|
7651
|
+
if (!key) {
|
|
7652
|
+
if (bound) warnOnce(`heatmap:gridSpan:${bound}`, `gridSpan.${direction === "earlier" ? "start" : "end"} ${JSON.stringify(bound)} is not a \`yyyy-MM-dd\` day, so the grid is drawn over the series' own span.`);
|
|
7653
|
+
return fallback;
|
|
7654
|
+
}
|
|
7655
|
+
if (direction === "earlier") return key < fallback ? key : fallback;
|
|
7656
|
+
return key > fallback ? key : fallback;
|
|
7657
|
+
};
|
|
7658
|
+
/**
|
|
7659
|
+
* Lay a day-bucketed series out as calendar columns.
|
|
7660
|
+
*
|
|
7661
|
+
* @param series - Points to bucket.
|
|
7662
|
+
* @param options - Grid shape, plus the locale and zone to read days in.
|
|
7663
|
+
* @return Columns and row labels for `HeatmapChart`.
|
|
7664
|
+
*/
|
|
7665
|
+
const buildCalendarHeatmapData = (series, options = {}) => {
|
|
7666
|
+
const weekStartsOn = options.weekStartsOn ?? 1;
|
|
7667
|
+
const hideOutOfRangeDays = options.hideOutOfRangeDays ?? true;
|
|
7668
|
+
const { locale, timeZone } = sanitizeFormatting({
|
|
7669
|
+
locale: options.locale,
|
|
7670
|
+
timeZone: options.timeZone
|
|
7671
|
+
});
|
|
7672
|
+
const readInstant = instantDayReader(timeZone);
|
|
7673
|
+
const valueByDay = /* @__PURE__ */ new Map();
|
|
7674
|
+
let minDayKey;
|
|
7675
|
+
let maxDayKey;
|
|
7676
|
+
for (const point of series) {
|
|
7677
|
+
const key = pointDayKey(point, readInstant);
|
|
7678
|
+
if (!key) {
|
|
7679
|
+
const offending = point.dateString ?? (point.date && String(point.date));
|
|
7680
|
+
warnOnce(`heatmap:unreadableDate:${offending}`, offending ? `${JSON.stringify(offending)} is not a day this can read, so its point is left out of the calendar. A \`dateString\` must start \`yyyy-MM-dd\`.` : "A point carries neither `date` nor `dateString`, so it is left out of the calendar.");
|
|
7681
|
+
continue;
|
|
7682
|
+
}
|
|
7683
|
+
valueByDay.set(key, point.value);
|
|
7684
|
+
if (!minDayKey || key < minDayKey) minDayKey = key;
|
|
7685
|
+
if (!maxDayKey || key > maxDayKey) maxDayKey = key;
|
|
7686
|
+
}
|
|
7687
|
+
if (!minDayKey || !maxDayKey) return {
|
|
7688
|
+
data: [],
|
|
7689
|
+
rowLabels: []
|
|
7690
|
+
};
|
|
7691
|
+
const requestedMinDayKey = widenTo(options.gridSpan?.start, minDayKey, "earlier");
|
|
7692
|
+
const gridMaxDayKey = widenTo(options.gridSpan?.end, maxDayKey, "later");
|
|
7693
|
+
const requestedMinDate = civilDate(requestedMinDayKey);
|
|
7694
|
+
const gridMaxDate = civilDate(gridMaxDayKey);
|
|
7695
|
+
const { formatWeekday, formatMonth, formatDay } = civilLabelFormatters(locale);
|
|
7696
|
+
const gridStart = startOfCivilWeek(requestedMinDate, weekStartsOn);
|
|
7697
|
+
const gridMinDayKey = requestedMinDayKey < minDayKey ? civilKey(gridStart) : requestedMinDayKey;
|
|
7698
|
+
const weekCount = civilWeekSpan(gridStart, gridMaxDate, weekStartsOn);
|
|
7699
|
+
const rowLabels = Array.from({ length: 7 }, (_, row) => LABELLED_ROWS.includes(row) ? formatWeekday(addCivilDays(gridStart, row)) : "");
|
|
7700
|
+
const MIN_FIRST_MONTH_WEEKS = 2;
|
|
7701
|
+
const firstMonth = gridStart.getUTCMonth();
|
|
7702
|
+
let firstMonthWeeks = 0;
|
|
7703
|
+
while (firstMonthWeeks < weekCount && addCivilDays(gridStart, firstMonthWeeks * 7).getUTCMonth() === firstMonth) firstMonthWeeks++;
|
|
7704
|
+
const showFirstMonthLabel = !(firstMonthWeeks < weekCount) || firstMonthWeeks >= MIN_FIRST_MONTH_WEEKS;
|
|
7705
|
+
const data = [];
|
|
7706
|
+
let previousMonth = -1;
|
|
7707
|
+
for (let week = 0; week < weekCount; week++) {
|
|
7708
|
+
const columnStart = addCivilDays(gridStart, week * 7);
|
|
7709
|
+
const month = columnStart.getUTCMonth();
|
|
7710
|
+
const label = month !== previousMonth && (week !== 0 || showFirstMonthLabel) ? formatMonth(columnStart) : "";
|
|
7711
|
+
previousMonth = month;
|
|
7712
|
+
const cells = [];
|
|
7713
|
+
for (let row = 0; row < 7; row++) {
|
|
7714
|
+
const day = addCivilDays(gridStart, week * 7 + row);
|
|
7715
|
+
const key = civilKey(day);
|
|
7716
|
+
const cell = {
|
|
7717
|
+
label: formatDay(day),
|
|
7718
|
+
value: valueByDay.has(key) ? valueByDay.get(key) : null
|
|
7719
|
+
};
|
|
7720
|
+
if (key < gridMinDayKey || key > gridMaxDayKey) {
|
|
7721
|
+
if (hideOutOfRangeDays) cell.hidden = true;
|
|
7722
|
+
} else if (key < minDayKey || key > maxDayKey) cell.placeholder = true;
|
|
7723
|
+
cells.push(cell);
|
|
7724
|
+
}
|
|
7725
|
+
data.push({
|
|
7726
|
+
label,
|
|
7727
|
+
data: cells
|
|
7728
|
+
});
|
|
7729
|
+
}
|
|
7730
|
+
return {
|
|
7731
|
+
data,
|
|
7732
|
+
rowLabels
|
|
7733
|
+
};
|
|
7734
|
+
};
|
|
7735
|
+
//#endregion
|
|
7736
|
+
//#region src/charts/heatmap-chart/build-month-calendar-data.ts
|
|
7737
|
+
/** Week rows per month, fixed so every month block is the same height. */
|
|
7738
|
+
const MONTH_ROWS = 6;
|
|
7739
|
+
const DAYS_PER_WEEK = 7;
|
|
7740
|
+
const startOfCivilMonth = (date) => {
|
|
7741
|
+
const first = new Date(date.getTime());
|
|
7742
|
+
first.setUTCDate(1);
|
|
7743
|
+
return first;
|
|
7744
|
+
};
|
|
7745
|
+
const startOfNextCivilMonth = (date) => {
|
|
7746
|
+
const next = startOfCivilMonth(date);
|
|
7747
|
+
next.setUTCMonth(next.getUTCMonth() + 1);
|
|
7748
|
+
return next;
|
|
7749
|
+
};
|
|
7750
|
+
/**
|
|
7751
|
+
* Lay a day-keyed map out as one month calendar per month, weekdays across and
|
|
7752
|
+
* weeks down, for `HeatmapChart` with `columnGroups`.
|
|
7753
|
+
*
|
|
7754
|
+
* @param valueByDay - Value per `yyyy-MM-dd`. A missing day is `null`.
|
|
7755
|
+
* @param range - The measured days; every month from `start`'s through `end`'s is drawn.
|
|
7756
|
+
* @param options - Week start and label locale.
|
|
7757
|
+
* @return Columns and one group per month; empty for an invalid or reversed range.
|
|
7758
|
+
*/
|
|
7759
|
+
const buildMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
|
|
7760
|
+
const start = civilDate(range.start);
|
|
7761
|
+
const end = civilDate(range.end);
|
|
7762
|
+
if (!start || !end || start.getTime() > end.getTime()) {
|
|
7763
|
+
warnOnce(`heatmap:monthRange:${range.start}:${range.end}`, `range ${JSON.stringify(range)} must be two \`yyyy-MM-dd\` days with start on or before end, so the calendar is empty.`);
|
|
7764
|
+
return {
|
|
7765
|
+
data: [],
|
|
7766
|
+
columnGroups: []
|
|
7767
|
+
};
|
|
7768
|
+
}
|
|
7769
|
+
const startKey = civilKey(start);
|
|
7770
|
+
const endKey = civilKey(end);
|
|
7771
|
+
const weekStartsOn = options.weekStartsOn ?? 1;
|
|
7772
|
+
const { locale } = sanitizeFormatting({ locale: options.locale });
|
|
7773
|
+
for (const key of Object.keys(valueByDay)) if (!civilDate(key)) warnOnce(`heatmap:monthKey:${key}`, `${JSON.stringify(key)} is not a \`yyyy-MM-dd\` day, so its value is left out of the calendar.`);
|
|
7774
|
+
const readValue = (key) => {
|
|
7775
|
+
const value = valueByDay[key];
|
|
7776
|
+
return isPresent(value) ? value : null;
|
|
7777
|
+
};
|
|
7778
|
+
const { formatMonth, formatMonthYear, formatDay } = civilLabelFormatters(locale);
|
|
7779
|
+
const data = [];
|
|
7780
|
+
const columnGroups = [];
|
|
7781
|
+
const lastMonthStart = startOfCivilMonth(end);
|
|
7782
|
+
const formatGroup = (lastMonthStart.getUTCFullYear() - start.getUTCFullYear()) * 12 + lastMonthStart.getUTCMonth() - start.getUTCMonth() + 1 > 12 ? formatMonthYear : formatMonth;
|
|
7783
|
+
for (let monthStart = startOfCivilMonth(start); monthStart.getTime() <= lastMonthStart.getTime(); monthStart = startOfNextCivilMonth(monthStart)) {
|
|
7784
|
+
const monthStartKey = civilKey(monthStart);
|
|
7785
|
+
const monthEndKey = civilKey(addCivilDays(startOfNextCivilMonth(monthStart), -1));
|
|
7786
|
+
const gridStart = startOfCivilWeek(monthStart, weekStartsOn);
|
|
7787
|
+
for (let weekday = 0; weekday < DAYS_PER_WEEK; weekday++) {
|
|
7788
|
+
const cells = [];
|
|
7789
|
+
for (let week = 0; week < MONTH_ROWS; week++) {
|
|
7790
|
+
const day = addCivilDays(gridStart, week * DAYS_PER_WEEK + weekday);
|
|
7791
|
+
const key = civilKey(day);
|
|
7792
|
+
if (key < monthStartKey || key > monthEndKey) cells.push({
|
|
7793
|
+
value: null,
|
|
7794
|
+
hidden: true
|
|
7795
|
+
});
|
|
7796
|
+
else if (key < startKey || key > endKey) cells.push({
|
|
7797
|
+
label: formatDay(day),
|
|
7798
|
+
value: null,
|
|
7799
|
+
placeholder: true
|
|
7800
|
+
});
|
|
7801
|
+
else cells.push({
|
|
7802
|
+
label: formatDay(day),
|
|
7803
|
+
value: readValue(key)
|
|
7804
|
+
});
|
|
7805
|
+
}
|
|
7806
|
+
data.push({ data: cells });
|
|
7807
|
+
}
|
|
7808
|
+
columnGroups.push({
|
|
7809
|
+
label: formatGroup(monthStart),
|
|
7810
|
+
span: DAYS_PER_WEEK
|
|
7811
|
+
});
|
|
7812
|
+
}
|
|
7813
|
+
return {
|
|
7814
|
+
data,
|
|
7815
|
+
columnGroups
|
|
7816
|
+
};
|
|
7817
|
+
};
|
|
7818
|
+
//#endregion
|
|
7203
7819
|
//#region src/charts/heatmap-chart/use-calendar-heatmap-data.ts
|
|
7204
7820
|
/**
|
|
7205
7821
|
* `buildCalendarHeatmapData` with the locale and zone taken from
|
|
@@ -7236,6 +7852,36 @@ const useCalendarHeatmapData = (series, options = {}) => {
|
|
|
7236
7852
|
]);
|
|
7237
7853
|
};
|
|
7238
7854
|
//#endregion
|
|
7855
|
+
//#region src/charts/heatmap-chart/use-month-calendar-heatmap-data.ts
|
|
7856
|
+
/**
|
|
7857
|
+
* `buildMonthCalendarHeatmapData` with the locale taken from `GlobalChartsProvider`
|
|
7858
|
+
* where the caller names none.
|
|
7859
|
+
*
|
|
7860
|
+
* @param valueByDay - Value per `yyyy-MM-dd`. Held by reference, so a caller that rebuilds it each render defeats the memo.
|
|
7861
|
+
* @param range - As for `buildMonthCalendarHeatmapData`.
|
|
7862
|
+
* @param options - As for `buildMonthCalendarHeatmapData`; `locale` wins over the provider.
|
|
7863
|
+
* @return Columns and groups for `HeatmapChart`.
|
|
7864
|
+
*/
|
|
7865
|
+
const useMonthCalendarHeatmapData = (valueByDay, range, options = {}) => {
|
|
7866
|
+
const formatting = useChartFormatting();
|
|
7867
|
+
const locale = options.locale ?? formatting.locale;
|
|
7868
|
+
const { weekStartsOn } = options;
|
|
7869
|
+
const { start, end } = range;
|
|
7870
|
+
return (0, react.useMemo)(() => buildMonthCalendarHeatmapData(valueByDay, {
|
|
7871
|
+
start,
|
|
7872
|
+
end
|
|
7873
|
+
}, {
|
|
7874
|
+
locale,
|
|
7875
|
+
weekStartsOn
|
|
7876
|
+
}), [
|
|
7877
|
+
valueByDay,
|
|
7878
|
+
start,
|
|
7879
|
+
end,
|
|
7880
|
+
locale,
|
|
7881
|
+
weekStartsOn
|
|
7882
|
+
]);
|
|
7883
|
+
};
|
|
7884
|
+
//#endregion
|
|
7239
7885
|
//#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
|
|
7240
7886
|
/*!
|
|
7241
7887
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
@@ -7599,7 +8245,24 @@ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7599
8245
|
tslib_1.__exportStar(require_dist$1(), exports);
|
|
7600
8246
|
}));
|
|
7601
8247
|
//#endregion
|
|
7602
|
-
//#region ../../../node_modules/.pnpm/@wordpress+
|
|
8248
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.55.0/node_modules/@wordpress/warning/build-module/utils.mjs
|
|
8249
|
+
var logged = /* @__PURE__ */ new Set();
|
|
8250
|
+
//#endregion
|
|
8251
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.55.0/node_modules/@wordpress/warning/build-module/index.mjs
|
|
8252
|
+
function isDev() {
|
|
8253
|
+
return globalThis.SCRIPT_DEBUG === true;
|
|
8254
|
+
}
|
|
8255
|
+
function warning(message) {
|
|
8256
|
+
if (!isDev()) return;
|
|
8257
|
+
if (logged.has(message)) return;
|
|
8258
|
+
console.warn(message);
|
|
8259
|
+
try {
|
|
8260
|
+
throw Error(message);
|
|
8261
|
+
} catch {}
|
|
8262
|
+
logged.add(message);
|
|
8263
|
+
}
|
|
8264
|
+
//#endregion
|
|
8265
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
|
|
7603
8266
|
function useUpdateEffect(effect, deps) {
|
|
7604
8267
|
const mountedRef = (0, react.useRef)(false);
|
|
7605
8268
|
(0, react.useEffect)(() => {
|
|
@@ -9237,7 +9900,7 @@ _createEmotion.css;
|
|
|
9237
9900
|
_createEmotion.sheet;
|
|
9238
9901
|
_createEmotion.cache;
|
|
9239
9902
|
//#endregion
|
|
9240
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
9903
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
|
|
9241
9904
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
9242
9905
|
var useCx = () => {
|
|
9243
9906
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -9344,7 +10007,7 @@ function memize(fn, options) {
|
|
|
9344
10007
|
return memoized;
|
|
9345
10008
|
}
|
|
9346
10009
|
//#endregion
|
|
9347
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10010
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/colors-values.mjs
|
|
9348
10011
|
var white = "#fff";
|
|
9349
10012
|
var GRAY = {
|
|
9350
10013
|
900: "#1e1e1e",
|
|
@@ -9394,8 +10057,8 @@ var UI = {
|
|
|
9394
10057
|
border: THEME.gray[600],
|
|
9395
10058
|
borderHover: THEME.gray[700],
|
|
9396
10059
|
borderFocus: THEME.accent,
|
|
9397
|
-
borderDisabled:
|
|
9398
|
-
textDisabled:
|
|
10060
|
+
borderDisabled: `var(--wpds-color-stroke-interactive-neutral-disabled, #dbdbdb)`,
|
|
10061
|
+
textDisabled: `var(--wpds-color-foreground-interactive-neutral-disabled, #8d8d8d)`,
|
|
9399
10062
|
darkGrayPlaceholder: `color-mix(in srgb, ${THEME.foreground}, transparent 38%)`,
|
|
9400
10063
|
lightGrayPlaceholder: `color-mix(in srgb, ${THEME.background}, transparent 35%)`
|
|
9401
10064
|
};
|
|
@@ -9423,7 +10086,7 @@ var COLORS = Object.freeze({
|
|
|
9423
10086
|
ui: UI
|
|
9424
10087
|
});
|
|
9425
10088
|
//#endregion
|
|
9426
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10089
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/config-values.mjs
|
|
9427
10090
|
var CONTROL_HEIGHT = "36px";
|
|
9428
10091
|
var CONTROL_PROPS = {
|
|
9429
10092
|
controlPaddingX: 12,
|
|
@@ -9477,8 +10140,8 @@ var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
|
9477
10140
|
transitionTimingFunctionControl: "cubic-bezier(0.12, 0.8, 0.32, 1)"
|
|
9478
10141
|
});
|
|
9479
10142
|
//#endregion
|
|
9480
|
-
//#region ../../../node_modules/.pnpm
|
|
9481
|
-
var
|
|
10143
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
10144
|
+
var import_es6 = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
9482
10145
|
module.exports = function equal(a, b) {
|
|
9483
10146
|
if (a === b) return true;
|
|
9484
10147
|
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
@@ -9522,31 +10185,8 @@ var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
9522
10185
|
}
|
|
9523
10186
|
return a !== a && b !== b;
|
|
9524
10187
|
};
|
|
9525
|
-
}));
|
|
9526
|
-
|
|
9527
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/utils.mjs
|
|
9528
|
-
var logged = /* @__PURE__ */ new Set();
|
|
9529
|
-
//#endregion
|
|
9530
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/index.mjs
|
|
9531
|
-
function isDev() {
|
|
9532
|
-
return globalThis.SCRIPT_DEBUG === true;
|
|
9533
|
-
}
|
|
9534
|
-
function warning(message) {
|
|
9535
|
-
if (!isDev()) return;
|
|
9536
|
-
if (logged.has(message)) return;
|
|
9537
|
-
console.warn(message);
|
|
9538
|
-
try {
|
|
9539
|
-
throw Error(message);
|
|
9540
|
-
} catch {}
|
|
9541
|
-
logged.add(message);
|
|
9542
|
-
}
|
|
9543
|
-
//#endregion
|
|
9544
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
9545
|
-
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
9546
|
-
var ComponentsContext = (0, react.createContext)(
|
|
9547
|
-
/** @type {Record<string, any>} */
|
|
9548
|
-
{}
|
|
9549
|
-
);
|
|
10188
|
+
})))(), 1);
|
|
10189
|
+
var ComponentsContext = (0, react.createContext)({});
|
|
9550
10190
|
ComponentsContext.displayName = "ComponentsContext";
|
|
9551
10191
|
var useComponentsContext = () => (0, react.useContext)(ComponentsContext);
|
|
9552
10192
|
function useContextSystemBridge({ value }) {
|
|
@@ -9568,19 +10208,19 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
9568
10208
|
};
|
|
9569
10209
|
(0, react.memo)(BaseContextSystemProvider);
|
|
9570
10210
|
//#endregion
|
|
9571
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10211
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/constants.mjs
|
|
9572
10212
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
9573
10213
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
9574
10214
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
9575
10215
|
//#endregion
|
|
9576
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10216
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
|
|
9577
10217
|
var import_dist = require_dist();
|
|
9578
10218
|
function getStyledClassName(namespace) {
|
|
9579
10219
|
return `components-${(0, import_dist.paramCase)(namespace)}`;
|
|
9580
10220
|
}
|
|
9581
10221
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
9582
10222
|
//#endregion
|
|
9583
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10223
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/context-connect.mjs
|
|
9584
10224
|
function contextConnect(Component, namespace) {
|
|
9585
10225
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
9586
10226
|
}
|
|
@@ -9597,7 +10237,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
9597
10237
|
});
|
|
9598
10238
|
}
|
|
9599
10239
|
//#endregion
|
|
9600
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10240
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/utils.mjs
|
|
9601
10241
|
function getNamespace(componentName) {
|
|
9602
10242
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
9603
10243
|
}
|
|
@@ -9605,7 +10245,7 @@ function getConnectedNamespace() {
|
|
|
9605
10245
|
return { [CONNECTED_NAMESPACE]: true };
|
|
9606
10246
|
}
|
|
9607
10247
|
//#endregion
|
|
9608
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10248
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
|
|
9609
10249
|
function useContextSystem(props, namespace) {
|
|
9610
10250
|
const contextSystemProps = useComponentsContext();
|
|
9611
10251
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -9614,10 +10254,12 @@ function useContextSystem(props, namespace) {
|
|
|
9614
10254
|
...getConnectedNamespace(),
|
|
9615
10255
|
...getNamespace(namespace)
|
|
9616
10256
|
};
|
|
9617
|
-
const { _overrides
|
|
10257
|
+
const { _overrides, ...otherContextProps } = contextProps;
|
|
10258
|
+
const overrideProps = _overrides;
|
|
9618
10259
|
const initialMergedProps = Object.entries(otherContextProps).length ? Object.assign({}, otherContextProps, props) : props;
|
|
10260
|
+
const propsWithChildren = initialMergedProps;
|
|
9619
10261
|
const classes = useCx()(getStyledClassNameFromKey(namespace), props.className);
|
|
9620
|
-
const rendered = typeof
|
|
10262
|
+
const rendered = typeof propsWithChildren.renderChildren === "function" ? propsWithChildren.renderChildren(initialMergedProps) : propsWithChildren.children;
|
|
9621
10263
|
for (const key in initialMergedProps) finalComponentProps[key] = initialMergedProps[key];
|
|
9622
10264
|
for (const key in overrideProps) finalComponentProps[key] = overrideProps[key];
|
|
9623
10265
|
if (rendered !== void 0) finalComponentProps.children = rendered;
|
|
@@ -9625,7 +10267,7 @@ function useContextSystem(props, namespace) {
|
|
|
9625
10267
|
return finalComponentProps;
|
|
9626
10268
|
}
|
|
9627
10269
|
//#endregion
|
|
9628
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10270
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
|
|
9629
10271
|
var visuallyHidden = {
|
|
9630
10272
|
border: 0,
|
|
9631
10273
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -9641,7 +10283,7 @@ var visuallyHidden = {
|
|
|
9641
10283
|
wordBreak: "normal"
|
|
9642
10284
|
};
|
|
9643
10285
|
//#endregion
|
|
9644
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10286
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
|
|
9645
10287
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
9646
10288
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
9647
10289
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -9731,7 +10373,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
|
9731
10373
|
}
|
|
9732
10374
|
var PolymorphicElement = (0, react.forwardRef)(UnforwardedPolymorphicElement);
|
|
9733
10375
|
//#endregion
|
|
9734
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10376
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/view/component.mjs
|
|
9735
10377
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
9736
10378
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PolymorphicElement, {
|
|
9737
10379
|
ref,
|
|
@@ -9740,7 +10382,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
9740
10382
|
}
|
|
9741
10383
|
var component_default$2 = Object.assign((0, react.forwardRef)(UnforwardedView), { selector: ".components-view" });
|
|
9742
10384
|
//#endregion
|
|
9743
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10385
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
|
|
9744
10386
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
9745
10387
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
9746
10388
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
@@ -9755,7 +10397,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
9755
10397
|
}
|
|
9756
10398
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
9757
10399
|
//#endregion
|
|
9758
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10400
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
|
|
9759
10401
|
var breakpoints = [
|
|
9760
10402
|
"40em",
|
|
9761
10403
|
"52em",
|
|
@@ -9789,7 +10431,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
9789
10431
|
return array[index >= array.length ? array.length - 1 : index];
|
|
9790
10432
|
}
|
|
9791
10433
|
//#endregion
|
|
9792
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10434
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/utils.mjs
|
|
9793
10435
|
var ALIGNMENTS = {
|
|
9794
10436
|
bottom: {
|
|
9795
10437
|
alignItems: "flex-end",
|
|
@@ -9837,7 +10479,7 @@ function getAlignmentProps(alignment) {
|
|
|
9837
10479
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
9838
10480
|
}
|
|
9839
10481
|
//#endregion
|
|
9840
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10482
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/hook.mjs
|
|
9841
10483
|
function useGrid(props) {
|
|
9842
10484
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
9843
10485
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -9879,7 +10521,7 @@ function useGrid(props) {
|
|
|
9879
10521
|
};
|
|
9880
10522
|
}
|
|
9881
10523
|
//#endregion
|
|
9882
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.
|
|
10524
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.1.0_@date-fns+tz@1.5.0_@types+react-dom@18.3.7_@types+react@18_c300d25e93ed6b8d3659e83df7c1508a/node_modules/@wordpress/components/build-module/grid/component.mjs
|
|
9883
10525
|
function UnconnectedGrid(props, forwardedRef) {
|
|
9884
10526
|
const gridProps = useGrid(props);
|
|
9885
10527
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
@@ -11165,6 +11807,7 @@ exports.SparklineUnresponsive = SparklineUnresponsive;
|
|
|
11165
11807
|
exports.ThemeProvider = GlobalChartsProvider;
|
|
11166
11808
|
exports.TrendIndicator = TrendIndicator;
|
|
11167
11809
|
exports.buildCalendarHeatmapData = buildCalendarHeatmapData;
|
|
11810
|
+
exports.buildMonthCalendarHeatmapData = buildMonthCalendarHeatmapData;
|
|
11168
11811
|
exports.defaultTheme = defaultTheme;
|
|
11169
11812
|
exports.formatMetricValue = formatMetricValue;
|
|
11170
11813
|
exports.formatPercentage = formatPercentage;
|
|
@@ -11189,6 +11832,7 @@ exports.useChartScopeElement = useChartScopeElement;
|
|
|
11189
11832
|
exports.useGlobalChartsContext = useGlobalChartsContext;
|
|
11190
11833
|
exports.useGlobalChartsTheme = useGlobalChartsTheme;
|
|
11191
11834
|
exports.useLeaderboardLegendItems = useLeaderboardLegendItems;
|
|
11835
|
+
exports.useMonthCalendarHeatmapData = useMonthCalendarHeatmapData;
|
|
11192
11836
|
exports.validateHexColor = validateHexColor;
|
|
11193
11837
|
|
|
11194
11838
|
//# sourceMappingURL=index.cjs.map
|