@automattic/charts 3.1.1 → 4.0.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 +41 -0
- package/TOKENS.md +80 -46
- package/dist/index.cjs +1224 -662
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +72 -23
- package/dist/index.d.cts +230 -162
- package/dist/index.d.ts +230 -162
- package/dist/index.js +1224 -663
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
- package/src/charts/area-chart/area-chart.tsx +39 -25
- package/src/charts/area-chart/test/area-chart.test.tsx +4 -33
- package/src/charts/area-chart/test/tick-placement.test.tsx +55 -0
- package/src/charts/area-chart/test/tooltip-resolution-branches.test.tsx +86 -0
- package/src/charts/area-chart/test/tooltip-resolution.test.tsx +69 -0
- package/src/charts/area-chart/types.ts +4 -7
- package/src/charts/bar-chart/bar-chart.tsx +38 -11
- package/src/charts/bar-chart/private/test/use-bar-chart-options-formatting.test.tsx +69 -0
- package/src/charts/bar-chart/private/use-bar-chart-options.ts +27 -15
- package/src/charts/bar-chart/test/bar-chart-pointer-events.test.tsx +67 -0
- package/src/charts/bar-chart/test/bar-chart.test.tsx +79 -0
- package/src/charts/bar-list-chart/bar-list-chart.tsx +45 -2
- package/src/charts/bar-list-chart/test/bar-list-chart.test.tsx +38 -0
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.module.scss +33 -23
- package/src/charts/conversion-funnel-chart/conversion-funnel-chart.tsx +138 -182
- package/src/charts/conversion-funnel-chart/test/conversion-funnel-chart.test.tsx +46 -0
- package/src/charts/geo-chart/geo-chart.module.scss +1 -0
- package/src/charts/geo-chart/geo-chart.tsx +5 -10
- package/src/charts/geo-chart/test/geo-chart.test.tsx +2 -2
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +21 -16
- package/src/charts/heatmap-chart/heatmap-chart.tsx +45 -28
- package/src/charts/heatmap-chart/private/build-calendar-data.ts +3 -0
- package/src/charts/heatmap-chart/private/heatmap-legend.tsx +11 -4
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +51 -12
- package/src/charts/heatmap-chart/types.ts +2 -2
- package/src/charts/leaderboard-chart/hooks/use-fitted-row-count.ts +2 -2
- package/src/charts/leaderboard-chart/hooks/use-leaderboard-legend-items.ts +3 -5
- package/src/charts/leaderboard-chart/leaderboard-chart.module.scss +31 -19
- package/src/charts/leaderboard-chart/leaderboard-chart.tsx +27 -17
- package/src/charts/leaderboard-chart/test/leaderboard-chart.test.tsx +14 -0
- package/src/charts/leaderboard-chart/test/use-leaderboard-legend-items.test.tsx +2 -9
- package/src/charts/line-chart/line-chart.module.scss +10 -18
- package/src/charts/line-chart/line-chart.tsx +109 -25
- package/src/charts/line-chart/private/line-chart-annotation.tsx +18 -19
- package/src/charts/line-chart/test/default-tooltip-formatting.test.tsx +74 -0
- package/src/charts/line-chart/test/line-chart.test.tsx +74 -3
- package/src/charts/line-chart/test/tick-placement.test.tsx +84 -0
- package/src/charts/line-chart/test/tooltip-resolution.test.tsx +140 -0
- package/src/charts/line-chart/types.ts +4 -1
- package/src/charts/pie-chart/pie-chart.module.scss +13 -1
- package/src/charts/pie-chart/pie-chart.tsx +30 -40
- package/src/charts/pie-chart/test/pie-chart.test.tsx +56 -0
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.module.scss +8 -3
- package/src/charts/pie-semi-circle-chart/pie-semi-circle-chart.tsx +23 -37
- package/src/charts/pie-semi-circle-chart/test/pie-semi-circle-chart.test.tsx +50 -0
- package/src/charts/private/chart-layout/chart-layout.module.scss +3 -2
- package/src/charts/private/svg-empty-state/svg-empty-state.module.scss +1 -1
- package/src/charts/private/test/axis-formatting.test.tsx +85 -0
- package/src/charts/private/test/time-axis-formatting.test.ts +109 -0
- package/src/charts/private/test/time-axis-options.test.ts +267 -0
- package/src/charts/private/test/time-axis-tick-invariants.test.ts +153 -0
- package/src/charts/private/test/time-axis-tick-values.test.ts +280 -0
- package/src/charts/private/test/time-axis.test.ts +9 -69
- package/src/charts/private/time-axis-options.ts +106 -0
- package/src/charts/private/time-axis.ts +318 -136
- package/src/charts/private/x-zoom/x-zoom.module.scss +3 -3
- package/src/charts/private/xy-plot/xy-plot.module.scss +8 -0
- package/src/charts/sparkline/sparkline.tsx +9 -3
- package/src/charts/sparkline/test/sparkline.test.tsx +29 -56
- package/src/charts/sparkline/types.ts +2 -2
- package/src/components/legend/private/base-legend.module.scss +9 -5
- package/src/components/tooltip/accessible-tooltip.tsx +38 -10
- package/src/components/tooltip/base-tooltip.module.scss +3 -3
- package/src/components/tooltip/private/bounded-tooltip.tsx +172 -0
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +67 -0
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +129 -0
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +279 -0
- package/src/components/tooltip/xy-chart-tooltip.tsx +288 -0
- package/src/components/trend-indicator/trend-indicator.module.scss +2 -2
- package/src/hooks/test/use-xychart-theme-style-reads.test.tsx +17 -10
- package/src/hooks/test/use-xychart-theme.test.tsx +63 -5
- package/src/hooks/use-xychart-theme.ts +33 -23
- package/src/index.ts +4 -0
- package/src/providers/chart-context/global-charts-provider.tsx +64 -54
- package/src/providers/chart-context/hooks/use-chart-formatting.ts +22 -0
- package/src/providers/chart-context/index.ts +1 -0
- package/src/providers/chart-context/private/catalog-pointers.ts +42 -0
- package/src/providers/chart-context/private/series-palette.ts +35 -0
- package/src/providers/chart-context/test/catalog-pointers.test.ts +61 -0
- package/src/providers/chart-context/test/chart-context.test.tsx +177 -792
- package/src/providers/chart-context/test/use-global-charts-theme.test.tsx +7 -18
- package/src/providers/chart-context/themes.ts +7 -47
- package/src/providers/chart-context/types.ts +3 -0
- package/src/styles/chart-scope.scss +63 -58
- package/src/styles/test/chart-scope.test.ts +25 -40
- package/src/test-utils/series-fixtures.ts +31 -0
- package/src/types.ts +103 -73
- package/src/utils/bucket-info.ts +87 -0
- package/src/utils/color-utils.ts +0 -27
- package/src/utils/date-formatting.ts +174 -0
- package/src/utils/get-styles.ts +7 -1
- package/src/utils/index.ts +3 -0
- package/src/utils/test/bucket-info.test.ts +185 -0
- package/src/utils/test/color-utils.test.ts +1 -48
- package/src/utils/test/date-formatting.test.ts +89 -0
- package/src/utils/test/get-styles.test.ts +10 -7
- package/src/utils/test/merge-themes.test.ts +18 -46
- package/src/visx/types.ts +29 -2
- package/src/hooks/test/use-xychart-theme-provider-override.test.tsx +0 -28
- package/src/providers/chart-context/private/theme-override-vars.ts +0 -87
- package/src/providers/chart-context/private/with-catalog-pointers.ts +0 -50
- package/src/providers/chart-context/test/sparse-theme.test.ts +0 -35
- package/src/providers/chart-context/test/theme-override-vars-guard.test.tsx +0 -29
- package/src/providers/chart-context/test/theme-override-vars.test.ts +0 -118
- package/src/providers/chart-context/test/with-catalog-pointers.test.ts +0 -47
- package/src/styles/test/wpds-fallbacks.test.ts +0 -131
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getStringWidth as getStringWidth$1 } from "./visx/text/index.js";
|
|
2
2
|
import { formatNumber, formatNumberCompact } from "@automattic/number-formatters";
|
|
3
|
-
import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid,
|
|
3
|
+
import { AnimatedAreaSeries, AnimatedAreaStack, AreaSeries, Axis, BarGroup, BarSeries, DataContext, Grid, TooltipContext, XYChart, buildChartTheme } from "@visx/xychart";
|
|
4
4
|
import { __, _x, sprintf } from "@wordpress/i18n";
|
|
5
5
|
import clsx from "clsx";
|
|
6
6
|
import * as React from "react";
|
|
@@ -10,11 +10,12 @@ import { addDays, differenceInCalendarWeeks, differenceInHours, differenceInYear
|
|
|
10
10
|
import { Text, getStringWidth } from "@visx/text";
|
|
11
11
|
import deepmerge from "deepmerge";
|
|
12
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
-
import {
|
|
13
|
+
import { Tooltip, defaultStyles, useTooltip } from "@visx/tooltip";
|
|
14
14
|
import { createScale, getTicks, scaleBand, scaleOrdinal, scaleTime } from "@visx/scale";
|
|
15
15
|
import { Group } from "@visx/group";
|
|
16
16
|
import { LegendItem, LegendLabel, LegendOrdinal, LegendShape } from "@visx/legend";
|
|
17
17
|
import { IconButton, Stack, Text as Text$1 } from "@wordpress/ui";
|
|
18
|
+
import { createPortal } from "react-dom";
|
|
18
19
|
import { LinearGradient } from "@visx/gradient";
|
|
19
20
|
import { curveCatmullRom, curveLinear, curveMonotoneX } from "@visx/curve";
|
|
20
21
|
import { useParentSize } from "@visx/responsive";
|
|
@@ -45,7 +46,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
45
46
|
}
|
|
46
47
|
return to;
|
|
47
48
|
};
|
|
48
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
49
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
49
50
|
value: mod,
|
|
50
51
|
enumerable: true
|
|
51
52
|
}) : target, mod));
|
|
@@ -172,6 +173,39 @@ const parseAsLocalDate = (dateString) => {
|
|
|
172
173
|
return /* @__PURE__ */ new Date(NaN);
|
|
173
174
|
};
|
|
174
175
|
//#endregion
|
|
176
|
+
//#region src/utils/bucket-info.ts
|
|
177
|
+
const getInstant = (point) => {
|
|
178
|
+
if (!point) return;
|
|
179
|
+
if ("date" in point && point.date) return point.date.getTime();
|
|
180
|
+
if ("dateString" in point && point.dateString) return parseAsLocalDate(point.dateString).getTime();
|
|
181
|
+
};
|
|
182
|
+
const getPointSpacingInHours = (data) => {
|
|
183
|
+
return data.reduce((spacing, datom) => {
|
|
184
|
+
const instants = [...new Set(datom.data.map((point) => getInstant(point)))].filter((time) => time !== void 0 && Number.isFinite(time)).sort((a, b) => a - b);
|
|
185
|
+
return instants.reduce((seriesSpacing, time, index) => index === 0 ? seriesSpacing : Math.min(seriesSpacing, Math.abs(differenceInHours(time, instants[index - 1]))), spacing);
|
|
186
|
+
}, Number.POSITIVE_INFINITY);
|
|
187
|
+
};
|
|
188
|
+
const SUB_DAILY_SPACING_HOURS = 23;
|
|
189
|
+
const MONTHLY_SPACING_HOURS = 672;
|
|
190
|
+
const getBucketResolution = (data, tickResolution) => {
|
|
191
|
+
if (tickResolution) return tickResolution === "week" ? "day" : tickResolution;
|
|
192
|
+
const spacingInHours = getPointSpacingInHours(data);
|
|
193
|
+
if (spacingInHours < SUB_DAILY_SPACING_HOURS) return "hour";
|
|
194
|
+
if (!Number.isFinite(spacingInHours) || spacingInHours < MONTHLY_SPACING_HOURS) return "day";
|
|
195
|
+
return spacingInHours < 12 * MONTHLY_SPACING_HOURS ? "month" : "year";
|
|
196
|
+
};
|
|
197
|
+
/**
|
|
198
|
+
* How this data was classified, for consumers that render their own labels.
|
|
199
|
+
*
|
|
200
|
+
* @param data - The series the chart draws, in any order, dated by `date` or `dateString`.
|
|
201
|
+
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
202
|
+
* @return The declared or inferred bucket, and the resolution formats key on.
|
|
203
|
+
*/
|
|
204
|
+
const getBucketInfo = (data, tickResolution) => ({
|
|
205
|
+
bucket: tickResolution ?? getBucketResolution(data),
|
|
206
|
+
displayResolution: getBucketResolution(data, tickResolution)
|
|
207
|
+
});
|
|
208
|
+
//#endregion
|
|
175
209
|
//#region src/utils/format-metric-value.ts
|
|
176
210
|
/**
|
|
177
211
|
* Format a numeric metric value based on type, precision and scale.
|
|
@@ -250,7 +284,8 @@ const formatPercentage = (value) => {
|
|
|
250
284
|
*/
|
|
251
285
|
const getLongestTickWidth = (ticks, formatTick, labelStyle) => {
|
|
252
286
|
const formattedTicks = ticks.map((tick) => formatTick(tick, 0, []));
|
|
253
|
-
|
|
287
|
+
const longestTick = formattedTicks.reduce((longest, current) => longest.length >= current.length ? longest : current, formattedTicks[0]);
|
|
288
|
+
return getStringWidth(longestTick, labelStyle);
|
|
254
289
|
};
|
|
255
290
|
//#endregion
|
|
256
291
|
//#region src/utils/get-styles.ts
|
|
@@ -383,20 +418,6 @@ const parseHslString = (hslString) => {
|
|
|
383
418
|
];
|
|
384
419
|
};
|
|
385
420
|
/**
|
|
386
|
-
* Parse an RGB string like 'rgb(255, 0, 0)' into a hex color.
|
|
387
|
-
*
|
|
388
|
-
* @deprecated Use normalizeColorToHex() instead, which handles all color formats including rgb() and rgba().
|
|
389
|
-
* @param rgbString - RGB color string (not RGBA)
|
|
390
|
-
* @return hex color string or null if invalid
|
|
391
|
-
*/
|
|
392
|
-
const parseRgbString = (rgbString) => {
|
|
393
|
-
const lower = rgbString.toLowerCase().trim();
|
|
394
|
-
if (!lower.startsWith("rgb(") || lower.startsWith("rgba(")) return null;
|
|
395
|
-
const parsed = color(lower);
|
|
396
|
-
if (!parsed) return null;
|
|
397
|
-
return parsed.formatHex();
|
|
398
|
-
};
|
|
399
|
-
/**
|
|
400
421
|
* Normalize any CSS color value to a hex color string.
|
|
401
422
|
* Handles hex, HSL, HSLA, RGB, RGBA, named CSS colors, and CSS variables.
|
|
402
423
|
*
|
|
@@ -624,6 +645,112 @@ const resolveFontSize = (val) => {
|
|
|
624
645
|
}
|
|
625
646
|
};
|
|
626
647
|
//#endregion
|
|
648
|
+
//#region src/utils/date-formatting.ts
|
|
649
|
+
const formatters = /* @__PURE__ */ new Map();
|
|
650
|
+
const getFormatter$1 = (options, { locale, timeZone }) => {
|
|
651
|
+
const key = `${locale ?? ""}|${timeZone ?? ""}|${JSON.stringify(options)}`;
|
|
652
|
+
let formatter = formatters.get(key);
|
|
653
|
+
if (!formatter) {
|
|
654
|
+
formatter = new Intl.DateTimeFormat(locale, {
|
|
655
|
+
...options,
|
|
656
|
+
timeZone
|
|
657
|
+
});
|
|
658
|
+
formatters.set(key, formatter);
|
|
659
|
+
}
|
|
660
|
+
return formatter;
|
|
661
|
+
};
|
|
662
|
+
const warned = /* @__PURE__ */ new Set();
|
|
663
|
+
const warnOnce = (key, message) => {
|
|
664
|
+
if (warned.has(key) || process.env.NODE_ENV === "production") return;
|
|
665
|
+
warned.add(key);
|
|
666
|
+
console.warn(`[Charts] ${message}`);
|
|
667
|
+
};
|
|
668
|
+
const isUsable = (formatting) => {
|
|
669
|
+
try {
|
|
670
|
+
Intl.DateTimeFormat(formatting.locale, { timeZone: formatting.timeZone });
|
|
671
|
+
return true;
|
|
672
|
+
} catch {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
const toBcp47 = (locale) => locale?.replace(/_/g, "-");
|
|
677
|
+
/**
|
|
678
|
+
* Repairs a host locale for `Intl`, dropping either half it still cannot use.
|
|
679
|
+
*
|
|
680
|
+
* Every formatter below is built during render, so an unusable string would throw
|
|
681
|
+
* where React unmounts the whole host tree rather than one chart. WordPress hands
|
|
682
|
+
* out the likeliest one either way: `timezone_string` is `''` on a site set to a
|
|
683
|
+
* raw UTC offset, and has no repair.
|
|
684
|
+
*
|
|
685
|
+
* @param formatting - Locale and time zone as the host supplied them.
|
|
686
|
+
* @return The usable halves, each `undefined` where the host's value was not.
|
|
687
|
+
*/
|
|
688
|
+
const sanitizeFormatting = (formatting) => {
|
|
689
|
+
const repaired = {
|
|
690
|
+
...formatting,
|
|
691
|
+
locale: toBcp47(formatting.locale)
|
|
692
|
+
};
|
|
693
|
+
if (isUsable(repaired)) return repaired;
|
|
694
|
+
const locale = isUsable({ locale: repaired.locale }) ? repaired.locale : void 0;
|
|
695
|
+
const timeZone = isUsable({ timeZone: repaired.timeZone }) ? repaired.timeZone : void 0;
|
|
696
|
+
if (locale === void 0 && formatting.locale !== void 0) warnOnce(`locale:${formatting.locale}`, `locale ${JSON.stringify(formatting.locale)} is not a BCP-47 tag Intl accepts, so dates render in the browser's locale.`);
|
|
697
|
+
if (timeZone === void 0 && formatting.timeZone !== void 0) warnOnce(`timeZone:${formatting.timeZone}`, `timeZone ${JSON.stringify(formatting.timeZone)} is not a zone Intl accepts, so dates render in the browser's zone. Pass an IANA name or a UTC offset such as "+05:30".`);
|
|
698
|
+
return {
|
|
699
|
+
locale,
|
|
700
|
+
timeZone
|
|
701
|
+
};
|
|
702
|
+
};
|
|
703
|
+
/**
|
|
704
|
+
* A date formatter bound to the host's locale and time zone.
|
|
705
|
+
*
|
|
706
|
+
* @param options - Date-part options, as for `Intl.DateTimeFormat`.
|
|
707
|
+
* @param formatting - Host locale and time zone; either half absent leaves the runtime's own.
|
|
708
|
+
* @return Formatter taking a timestamp or a `Date`.
|
|
709
|
+
*/
|
|
710
|
+
const createDateFormatter = (options, formatting) => {
|
|
711
|
+
return (value) => {
|
|
712
|
+
if (!Number.isFinite(Number(value))) return new Date(Number(value)).toLocaleDateString();
|
|
713
|
+
return getFormatter$1(options, formatting).format(value);
|
|
714
|
+
};
|
|
715
|
+
};
|
|
716
|
+
const CLOCK_OPTIONS = {
|
|
717
|
+
month: "numeric",
|
|
718
|
+
hour: "numeric",
|
|
719
|
+
hourCycle: "h23"
|
|
720
|
+
};
|
|
721
|
+
const NO_FIELDS = {
|
|
722
|
+
month: NaN,
|
|
723
|
+
hour: NaN
|
|
724
|
+
};
|
|
725
|
+
/**
|
|
726
|
+
* A clock reading calendar fields in the host's time zone.
|
|
727
|
+
*
|
|
728
|
+
* `Date`'s own getters read the browser's zone, so a chart viewed from another
|
|
729
|
+
* country anchors its ticks to the wrong midnights and the wrong January
|
|
730
|
+
* without this.
|
|
731
|
+
*
|
|
732
|
+
* @param timeZone - IANA zone name; absent leaves the runtime's own.
|
|
733
|
+
* @return Reader taking a `Date`.
|
|
734
|
+
*/
|
|
735
|
+
const createZonedClock = (timeZone) => {
|
|
736
|
+
if (!timeZone) return (date) => ({
|
|
737
|
+
month: date.getMonth() + 1,
|
|
738
|
+
hour: date.getHours()
|
|
739
|
+
});
|
|
740
|
+
return (date) => {
|
|
741
|
+
if (!Number.isFinite(Number(date))) return NO_FIELDS;
|
|
742
|
+
const parts = getFormatter$1(CLOCK_OPTIONS, {
|
|
743
|
+
locale: "en-US",
|
|
744
|
+
timeZone
|
|
745
|
+
}).formatToParts(date);
|
|
746
|
+
const read = (type) => Number(parts.find((part) => part.type === type)?.value);
|
|
747
|
+
return {
|
|
748
|
+
month: read("month"),
|
|
749
|
+
hour: read("hour")
|
|
750
|
+
};
|
|
751
|
+
};
|
|
752
|
+
};
|
|
753
|
+
//#endregion
|
|
627
754
|
//#region src/providers/chart-scope/chart-scope-context.ts
|
|
628
755
|
/**
|
|
629
756
|
* The nearest chart element, published so JS token resolution reads the same CSS cascade that paints the chart's own colours.
|
|
@@ -760,140 +887,40 @@ const getChartColor = (index, colorCache) => {
|
|
|
760
887
|
const fallbackLightness = BASE_LIGHTNESS + index % LIGHTNESS_VARIATION_STEPS * LIGHTNESS_INCREMENT;
|
|
761
888
|
return hsl(Math.round(fallbackHue), fallbackSaturation / 100, fallbackLightness / 100).formatHex();
|
|
762
889
|
};
|
|
763
|
-
//#endregion
|
|
764
|
-
//#region src/providers/chart-context/private/theme-override-vars.ts
|
|
765
|
-
const ROLE_FOR_FIELD = [
|
|
766
|
-
["--a8c-charts-color-background", (theme) => theme.backgroundColor],
|
|
767
|
-
["--a8c-charts-color-grid", (theme) => theme.gridStyles?.stroke],
|
|
768
|
-
["--a8c-charts-color-axis", (theme) => theme.xAxisLineStyles?.stroke],
|
|
769
|
-
["--a8c-charts-color-tick", (theme) => theme.xTickLineStyles?.stroke],
|
|
770
|
-
["--a8c-charts-color-label-axis", (theme) => theme.svgLabelSmall?.fill]
|
|
771
|
-
];
|
|
772
890
|
/**
|
|
773
|
-
* The
|
|
891
|
+
* The catalog role holding one series-palette slot.
|
|
774
892
|
*
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
* @param role - The catalog role being overridden.
|
|
778
|
-
* @return The custom property carrying the consumer's value.
|
|
893
|
+
* @param slot - The one-based slot number.
|
|
894
|
+
* @return The role name.
|
|
779
895
|
*/
|
|
780
|
-
const
|
|
781
|
-
|
|
782
|
-
/**
|
|
783
|
-
|
|
784
|
-
*
|
|
785
|
-
* The dependency runs `<role>: var(<role>-theme, …)`, so a value naming `<role>` closes a cycle through the catalog entry. CSS marks every custom property in a cycle invalid at computed-value time — the role's own fallback is *not* used, so the token resolves to nothing and every chart loses that colour. Verified in Chrome: `--role-theme: var(--role, blue); --role: var(--role-theme, green)` leaves `--role` empty, not `green`.
|
|
786
|
-
*
|
|
787
|
-
* Three things this has to get right, none of which a plain substring test gets:
|
|
788
|
-
*
|
|
789
|
-
* `var()` permits whitespace after the opening paren, so testing for `var(<role>` misses `var( --a8c-charts-color-grid, … )`.
|
|
790
|
-
*
|
|
791
|
-
* Several roles are prefixes of others (`--a8c-charts-color-label` of `--a8c-charts-color-label-secondary`), and every role is a prefix of its own theme layer. A prefix match would read a legitimate cross-role pointer as a self-reference and silently drop the override, so the role must be followed by something that cannot continue an identifier — `-` included. A value naming `<role>-theme` is therefore not treated as a self-reference: that cycle is confined to the theme layer, which leaves the role free to fall back to the catalog default.
|
|
792
|
-
*
|
|
793
|
-
* `resolveCssVariable` also accepts a bare custom-property name with no `var()` wrapper (`--a8c-charts-color-grid`), so that is legal `theme` input too. It forms no cycle — custom properties accept arbitrary token streams — so it survives as a literal string and drops silently at the use site instead of falling back to the catalog default.
|
|
794
|
-
*
|
|
795
|
-
* @param value - The consumer's value for the field.
|
|
796
|
-
* @param role - The catalog role this value would override.
|
|
797
|
-
* @return True when the value reads `role`, so it must not be published.
|
|
798
|
-
*/
|
|
799
|
-
const readsOwnRole = (value, role) => value.trim() === role || new RegExp(`var\\(\\s*${role.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(value);
|
|
800
|
-
/**
|
|
801
|
-
* Maps a sparse consumer theme onto the theme-layer variables its overridden catalog roles read, so CSS-painted and JS-resolved colours read one source.
|
|
802
|
-
*
|
|
803
|
-
* A value that reads the role it would override is left unpublished — that is the default theme's own pointer surviving `mergeThemes`, and publishing it would invalidate the role. The role is still reported in `roles`: `withCatalogPointers` restores its theme field to the catalog pointer either way, so CSS and visx agree on the catalog default rather than visx painting a literal CSS never sees.
|
|
804
|
-
*
|
|
805
|
-
* @param theme - The consumer's `theme` prop, before merging with the default theme.
|
|
806
|
-
* @return The wrapper's custom properties, and the roles the consumer overrode.
|
|
807
|
-
*/
|
|
808
|
-
const themeOverrideVars = (theme) => {
|
|
809
|
-
if (!theme) return {
|
|
810
|
-
vars: {},
|
|
811
|
-
roles: []
|
|
812
|
-
};
|
|
813
|
-
const vars = {};
|
|
814
|
-
const roles = [];
|
|
815
|
-
for (const [role, read] of ROLE_FOR_FIELD) {
|
|
816
|
-
const value = read(theme);
|
|
817
|
-
if (typeof value !== "string" || value === "") continue;
|
|
818
|
-
roles.push(role);
|
|
819
|
-
if (!readsOwnRole(value, role)) vars[themeLayerVar(role)] = value;
|
|
820
|
-
}
|
|
821
|
-
return {
|
|
822
|
-
vars,
|
|
823
|
-
roles
|
|
824
|
-
};
|
|
825
|
-
};
|
|
896
|
+
const seriesRole = (slot) => `--a8c-charts-color-series-${slot}`;
|
|
897
|
+
const SERIES_SLOT_1_FALLBACK = "#3858e9";
|
|
898
|
+
/** The catalog pointer for every slot, in slot order. */
|
|
899
|
+
const SERIES_PALETTE_POINTERS = Array.from({ length: 5 }, (_, index) => index === 0 ? `var(${seriesRole(1)}, ${SERIES_SLOT_1_FALLBACK})` : `var(${seriesRole(index + 1)})`);
|
|
826
900
|
//#endregion
|
|
827
901
|
//#region src/providers/chart-context/themes.ts
|
|
828
902
|
/**
|
|
829
|
-
* Default theme configuration
|
|
903
|
+
* Default theme configuration: the shape and spacing a consumer can override.
|
|
904
|
+
*
|
|
905
|
+
* For a color, set the matching `--a8c-charts-color-*` role in CSS instead; the `var()`
|
|
906
|
+
* chains that deliver those live in `private/catalog-pointers.ts`.
|
|
830
907
|
*/
|
|
831
908
|
const defaultTheme = {
|
|
832
|
-
|
|
833
|
-
labelBackgroundColor: "transparent",
|
|
834
|
-
labelTextColor: "var(--a8c-charts-color-label-on-fill, #FFFFFF)",
|
|
835
|
-
colors: [
|
|
836
|
-
"#98C8DF",
|
|
837
|
-
"#006DAB",
|
|
838
|
-
"#A6DC80",
|
|
839
|
-
"#1F9828",
|
|
840
|
-
"#FF8C8F"
|
|
841
|
-
],
|
|
842
|
-
gridStyles: {
|
|
843
|
-
stroke: "var(--a8c-charts-color-grid, #dbdbdb)",
|
|
844
|
-
strokeWidth: 1
|
|
845
|
-
},
|
|
909
|
+
gridStyles: { strokeWidth: 1 },
|
|
846
910
|
tickLength: 4,
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
xTickLineStyles: {
|
|
850
|
-
stroke: "var(--a8c-charts-color-tick, #dbdbdb)",
|
|
851
|
-
strokeWidth: 1
|
|
852
|
-
},
|
|
853
|
-
xAxisLineStyles: {
|
|
854
|
-
stroke: "var(--a8c-charts-color-axis, #dbdbdb)",
|
|
855
|
-
strokeWidth: 1
|
|
856
|
-
},
|
|
911
|
+
xTickLineStyles: { strokeWidth: 1 },
|
|
912
|
+
xAxisLineStyles: { strokeWidth: 1 },
|
|
857
913
|
legend: {
|
|
858
|
-
labelStyles: {
|
|
914
|
+
labelStyles: {},
|
|
859
915
|
containerStyles: {},
|
|
860
916
|
shapeStyles: []
|
|
861
917
|
},
|
|
862
918
|
seriesLineStyles: [],
|
|
863
919
|
glyphs: [],
|
|
864
|
-
svgLabelSmall: {
|
|
865
|
-
fill: "var(--a8c-charts-color-label-axis, #1e1e1e)",
|
|
866
|
-
fontFamily: "inherit"
|
|
867
|
-
},
|
|
920
|
+
svgLabelSmall: { fontFamily: "inherit" },
|
|
868
921
|
svgLabelBig: { fontFamily: "inherit" },
|
|
869
|
-
annotationStyles: {
|
|
870
|
-
|
|
871
|
-
anchorLineStroke: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
872
|
-
backgroundFill: "var(--a8c-charts-color-surface, #fff)"
|
|
873
|
-
},
|
|
874
|
-
connector: { stroke: "var(--a8c-charts-color-annotation, #1e1e1e)" },
|
|
875
|
-
circleSubject: {
|
|
876
|
-
stroke: "transparent",
|
|
877
|
-
fill: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
878
|
-
radius: 5
|
|
879
|
-
}
|
|
880
|
-
},
|
|
881
|
-
geoChart: { featureFillColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)" },
|
|
882
|
-
leaderboardChart: {
|
|
883
|
-
rowGap: 12,
|
|
884
|
-
columnGap: 4,
|
|
885
|
-
labelSpacing: "xs",
|
|
886
|
-
deltaColors: [
|
|
887
|
-
"var(--a8c-charts-color-trend-down, #cc1818)",
|
|
888
|
-
"var(--a8c-charts-color-trend-neutral, #707070)",
|
|
889
|
-
"var(--a8c-charts-color-trend-up, #008030)"
|
|
890
|
-
]
|
|
891
|
-
},
|
|
892
|
-
conversionFunnelChart: {
|
|
893
|
-
backgroundColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
894
|
-
positiveChangeColor: "var(--a8c-charts-color-trend-up, #008030)",
|
|
895
|
-
negativeChangeColor: "var(--a8c-charts-color-trend-down, #cc1818)"
|
|
896
|
-
},
|
|
922
|
+
annotationStyles: {},
|
|
923
|
+
leaderboardChart: { labelSpacing: "xs" },
|
|
897
924
|
lineChart: { lineStyles: { comparison: {
|
|
898
925
|
strokeDasharray: "4 4",
|
|
899
926
|
strokeLinecap: "square"
|
|
@@ -917,52 +944,9 @@ const defaultTheme = {
|
|
|
917
944
|
}
|
|
918
945
|
};
|
|
919
946
|
//#endregion
|
|
920
|
-
//#region src/providers/chart-context/private/with-catalog-pointers.ts
|
|
921
|
-
const CATALOG_RESTORE_FOR_ROLE = {
|
|
922
|
-
"--a8c-charts-color-background": () => ({ backgroundColor: defaultTheme.backgroundColor }),
|
|
923
|
-
"--a8c-charts-color-grid": (theme) => ({ gridStyles: {
|
|
924
|
-
...theme.gridStyles,
|
|
925
|
-
stroke: defaultTheme.gridStyles.stroke
|
|
926
|
-
} }),
|
|
927
|
-
"--a8c-charts-color-axis": (theme) => ({ xAxisLineStyles: {
|
|
928
|
-
...theme.xAxisLineStyles,
|
|
929
|
-
stroke: defaultTheme.xAxisLineStyles.stroke
|
|
930
|
-
} }),
|
|
931
|
-
"--a8c-charts-color-tick": (theme) => ({ xTickLineStyles: {
|
|
932
|
-
...theme.xTickLineStyles,
|
|
933
|
-
stroke: defaultTheme.xTickLineStyles.stroke
|
|
934
|
-
} }),
|
|
935
|
-
"--a8c-charts-color-label-axis": (theme) => ({ svgLabelSmall: {
|
|
936
|
-
...theme.svgLabelSmall,
|
|
937
|
-
fill: defaultTheme.svgLabelSmall.fill
|
|
938
|
-
} })
|
|
939
|
-
};
|
|
940
|
-
/**
|
|
941
|
-
* Restores the mapped theme fields of `overriddenRoles` to their catalog pointer, so the theme-layer variable `themeOverrideVars` writes on the provider wrapper is the only carrier for an overridden role — CSS and the JS bridge (`useXYChartTheme`) then resolve it through the same cascade instead of visx reading a baked literal that can disagree with a closer CSS override.
|
|
942
|
-
*
|
|
943
|
-
* This covers roles `themeOverrideVars` deliberately left unpublished as well as the ones it published. A value that reads its own role is not publishable, but leaving visx the consumer's literal is what the whole mechanism exists to prevent: `theme={ { gridStyles: { stroke: 'var(--brand, var(--a8c-charts-color-grid, red))' } } }` would have CSS paint the catalog default while visx painted `--brand`.
|
|
944
|
-
*
|
|
945
|
-
* Every field outside the five mapped roles is left exactly as `merged` provided it: those aren't published as theme-layer vars, so rewriting them would erase a consumer's override with no replacement carrier.
|
|
946
|
-
*
|
|
947
|
-
* @param merged - The consumer theme merged onto `defaultTheme` (`mergeThemes` output).
|
|
948
|
-
* @param overriddenRoles - The catalog roles the consumer overrode, from `themeOverrideVars`.
|
|
949
|
-
* @return A new theme object; `merged` is not mutated.
|
|
950
|
-
*/
|
|
951
|
-
const withCatalogPointers = (merged, overriddenRoles) => {
|
|
952
|
-
let result = merged;
|
|
953
|
-
for (const role of overriddenRoles) {
|
|
954
|
-
const restore = CATALOG_RESTORE_FOR_ROLE[role];
|
|
955
|
-
if (restore) result = {
|
|
956
|
-
...result,
|
|
957
|
-
...restore(result)
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
|
-
return result;
|
|
961
|
-
};
|
|
962
|
-
//#endregion
|
|
963
947
|
//#region src/providers/chart-context/global-charts-provider.tsx
|
|
964
948
|
const GlobalChartsContext = createContext(null);
|
|
965
|
-
const GlobalChartsProvider = ({ children, theme }) => {
|
|
949
|
+
const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
966
950
|
const [charts, setCharts] = useState(() => /* @__PURE__ */ new Map());
|
|
967
951
|
const [hiddenSeries, setHiddenSeries] = useState(() => /* @__PURE__ */ new Map());
|
|
968
952
|
const seededCharts = useRef(/* @__PURE__ */ new Set());
|
|
@@ -972,11 +956,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
972
956
|
wrapperRef.current = node;
|
|
973
957
|
setScopeNode(node);
|
|
974
958
|
}, []);
|
|
975
|
-
const
|
|
976
|
-
const providerTheme = useMemo(() => {
|
|
977
|
-
if (!theme) return defaultTheme;
|
|
978
|
-
return withCatalogPointers(mergeThemes(defaultTheme, theme), overriddenRoles);
|
|
979
|
-
}, [theme, overriddenRoles]);
|
|
959
|
+
const providerTheme = useMemo(() => theme ? mergeThemes(defaultTheme, theme) : defaultTheme, [theme]);
|
|
980
960
|
const [colorCache, setColorCache] = useState(() => ({
|
|
981
961
|
colors: [],
|
|
982
962
|
hues: [],
|
|
@@ -987,29 +967,26 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
987
967
|
const [isColorPaletteResolved, setIsColorPaletteResolved] = useState(false);
|
|
988
968
|
useLayoutEffect(() => {
|
|
989
969
|
setIsColorPaletteResolved(false);
|
|
990
|
-
const { colors } = providerTheme;
|
|
991
970
|
const resolvedColors = [];
|
|
992
971
|
const hues = [];
|
|
993
972
|
const existingHslColors = [];
|
|
994
973
|
let minHue = 360;
|
|
995
974
|
let maxHue = 0;
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
maxHue = Math.max(maxHue, hslTuple[0]);
|
|
1012
|
-
}
|
|
975
|
+
for (const color of SERIES_PALETTE_POINTERS) {
|
|
976
|
+
const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
|
|
977
|
+
if (normalizedColor.startsWith("#")) {
|
|
978
|
+
resolvedColors.push(normalizedColor);
|
|
979
|
+
const hslColor = hsl(normalizedColor);
|
|
980
|
+
if (!isNaN(hslColor.h)) {
|
|
981
|
+
const hslTuple = [
|
|
982
|
+
hslColor.h,
|
|
983
|
+
hslColor.s * 100,
|
|
984
|
+
hslColor.l * 100
|
|
985
|
+
];
|
|
986
|
+
hues.push(hslTuple[0]);
|
|
987
|
+
existingHslColors.push(hslTuple);
|
|
988
|
+
minHue = Math.min(minHue, hslTuple[0]);
|
|
989
|
+
maxHue = Math.max(maxHue, hslTuple[0]);
|
|
1013
990
|
}
|
|
1014
991
|
}
|
|
1015
992
|
}
|
|
@@ -1020,14 +997,15 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1020
997
|
minHue,
|
|
1021
998
|
maxHue
|
|
1022
999
|
});
|
|
1023
|
-
}, [
|
|
1000
|
+
}, []);
|
|
1024
1001
|
useEffect(() => {
|
|
1025
1002
|
if (colorCache.colors.length > 0) setIsColorPaletteResolved(true);
|
|
1026
1003
|
}, [colorCache]);
|
|
1027
1004
|
const [groupToColorMap, setGroupToColorMap] = useState(() => /* @__PURE__ */ new Map());
|
|
1005
|
+
const paletteKey = colorCache.colors.join(",");
|
|
1028
1006
|
useEffect(() => {
|
|
1029
1007
|
setGroupToColorMap(/* @__PURE__ */ new Map());
|
|
1030
|
-
}, [
|
|
1008
|
+
}, [paletteKey]);
|
|
1031
1009
|
const registerChart = useCallback((id, data) => {
|
|
1032
1010
|
setCharts((prev) => new Map(prev).set(id, data));
|
|
1033
1011
|
}, []);
|
|
@@ -1111,12 +1089,17 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1111
1089
|
const set = hiddenSeries.get(chartId);
|
|
1112
1090
|
return set ? new Set(set) : /* @__PURE__ */ new Set();
|
|
1113
1091
|
}, [hiddenSeries]);
|
|
1092
|
+
const formatting = useMemo(() => sanitizeFormatting({
|
|
1093
|
+
locale,
|
|
1094
|
+
timeZone
|
|
1095
|
+
}), [locale, timeZone]);
|
|
1114
1096
|
const value = useMemo(() => ({
|
|
1115
1097
|
charts,
|
|
1116
1098
|
registerChart,
|
|
1117
1099
|
unregisterChart,
|
|
1118
1100
|
getChartData,
|
|
1119
1101
|
theme: providerTheme,
|
|
1102
|
+
formatting,
|
|
1120
1103
|
getElementStyles,
|
|
1121
1104
|
toggleSeriesVisibility,
|
|
1122
1105
|
setSeriesVisibility,
|
|
@@ -1132,6 +1115,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1132
1115
|
unregisterChart,
|
|
1133
1116
|
getChartData,
|
|
1134
1117
|
providerTheme,
|
|
1118
|
+
formatting,
|
|
1135
1119
|
getElementStyles,
|
|
1136
1120
|
toggleSeriesVisibility,
|
|
1137
1121
|
setSeriesVisibility,
|
|
@@ -1147,10 +1131,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1147
1131
|
children: /* @__PURE__ */ jsx("div", {
|
|
1148
1132
|
ref: setWrapperNode,
|
|
1149
1133
|
className: CHART_SCOPE_CLASS,
|
|
1150
|
-
style: {
|
|
1151
|
-
display: "contents",
|
|
1152
|
-
...overrideVars
|
|
1153
|
-
},
|
|
1134
|
+
style: { display: "contents" },
|
|
1154
1135
|
children: /* @__PURE__ */ jsx(ChartScopeContext.Provider, {
|
|
1155
1136
|
value: scopeNode,
|
|
1156
1137
|
children
|
|
@@ -1214,6 +1195,39 @@ const useDeepMemo = (value) => {
|
|
|
1214
1195
|
return ref.current;
|
|
1215
1196
|
};
|
|
1216
1197
|
//#endregion
|
|
1198
|
+
//#region src/providers/chart-context/private/catalog-pointers.ts
|
|
1199
|
+
const CATALOG_POINTERS = {
|
|
1200
|
+
background: "var(--a8c-charts-color-background, #fff)",
|
|
1201
|
+
labelAxis: "var(--a8c-charts-color-label-axis, #1e1e1e)",
|
|
1202
|
+
grid: "var(--a8c-charts-color-grid, #dbdbdb)",
|
|
1203
|
+
axisX: "var(--a8c-charts-color-axis-x, #dbdbdb)",
|
|
1204
|
+
tickX: "var(--a8c-charts-color-tick-x, #dbdbdb)",
|
|
1205
|
+
axisY: "var(--a8c-charts-color-axis-y, none)",
|
|
1206
|
+
tickY: "var(--a8c-charts-color-tick-y, none)",
|
|
1207
|
+
annotation: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
1208
|
+
surface: "var(--a8c-charts-color-surface, #fff)",
|
|
1209
|
+
surfaceSecondary: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
1210
|
+
trendUp: "var(--a8c-charts-color-trend-up, #008030)",
|
|
1211
|
+
trendDown: "var(--a8c-charts-color-trend-down, #cc1818)",
|
|
1212
|
+
series: SERIES_PALETTE_POINTERS
|
|
1213
|
+
};
|
|
1214
|
+
/**
|
|
1215
|
+
* The annotation parts visx paints, in the shape `@visx/annotation` takes. `radius`
|
|
1216
|
+
* rides along as the base the theme and the per-datum styles merge onto.
|
|
1217
|
+
*/
|
|
1218
|
+
const ANNOTATION_POINTERS = {
|
|
1219
|
+
label: {
|
|
1220
|
+
anchorLineStroke: CATALOG_POINTERS.annotation,
|
|
1221
|
+
backgroundFill: CATALOG_POINTERS.surface
|
|
1222
|
+
},
|
|
1223
|
+
connector: { stroke: CATALOG_POINTERS.annotation },
|
|
1224
|
+
circleSubject: {
|
|
1225
|
+
stroke: "transparent",
|
|
1226
|
+
fill: CATALOG_POINTERS.annotation,
|
|
1227
|
+
radius: 5
|
|
1228
|
+
}
|
|
1229
|
+
};
|
|
1230
|
+
//#endregion
|
|
1217
1231
|
//#region src/providers/chart-scope/use-chart-scope-element.ts
|
|
1218
1232
|
/**
|
|
1219
1233
|
* Returns the nearest chart scope element, or `null` when rendered outside any scope (and during SSR, before the ref is attached).
|
|
@@ -1240,26 +1254,33 @@ const useXYChartTheme = (data) => {
|
|
|
1240
1254
|
return useMemo(() => {
|
|
1241
1255
|
const resolve = createCssVariableResolver(scopeElement);
|
|
1242
1256
|
const resolveColor = (value) => value ? resolve(value) ?? value : value;
|
|
1243
|
-
const
|
|
1257
|
+
const paletteColors = [...JSON.parse(seriesColorKey), ...CATALOG_POINTERS.series].map((color) => resolveColor(color)).filter((color) => Boolean(color) && !color.includes("var("));
|
|
1258
|
+
const resolvedLabelColor = resolveColor(CATALOG_POINTERS.labelAxis);
|
|
1259
|
+
const htmlLabelColor = resolvedLabelColor ? normalizeColorToHex(resolvedLabelColor) || resolvedLabelColor : resolvedLabelColor;
|
|
1244
1260
|
return buildChartTheme({
|
|
1245
1261
|
...theme,
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1262
|
+
gridColor: "",
|
|
1263
|
+
gridColorDark: "",
|
|
1264
|
+
colors: paletteColors,
|
|
1265
|
+
backgroundColor: resolveColor(CATALOG_POINTERS.background),
|
|
1266
|
+
htmlLabel: htmlLabelColor ? { color: htmlLabelColor } : void 0,
|
|
1267
|
+
gridStyles: {
|
|
1249
1268
|
...theme.gridStyles,
|
|
1250
|
-
stroke:
|
|
1269
|
+
stroke: CATALOG_POINTERS.grid
|
|
1251
1270
|
},
|
|
1252
|
-
xAxisLineStyles:
|
|
1271
|
+
xAxisLineStyles: {
|
|
1253
1272
|
...theme.xAxisLineStyles,
|
|
1254
|
-
stroke:
|
|
1273
|
+
stroke: CATALOG_POINTERS.axisX
|
|
1255
1274
|
},
|
|
1256
|
-
xTickLineStyles:
|
|
1275
|
+
xTickLineStyles: {
|
|
1257
1276
|
...theme.xTickLineStyles,
|
|
1258
|
-
stroke:
|
|
1277
|
+
stroke: CATALOG_POINTERS.tickX
|
|
1259
1278
|
},
|
|
1260
|
-
|
|
1279
|
+
yAxisLineStyles: { stroke: CATALOG_POINTERS.axisY },
|
|
1280
|
+
yTickLineStyles: { stroke: CATALOG_POINTERS.tickY },
|
|
1281
|
+
svgLabelSmall: {
|
|
1261
1282
|
...theme.svgLabelSmall,
|
|
1262
|
-
fill:
|
|
1283
|
+
fill: CATALOG_POINTERS.labelAxis
|
|
1263
1284
|
}
|
|
1264
1285
|
});
|
|
1265
1286
|
}, [
|
|
@@ -1357,11 +1378,12 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1357
1378
|
if (options.axis?.y?.tickValues?.length) return options.axis.y.tickValues;
|
|
1358
1379
|
const minY = Math.min(...allDataPoints.map((d) => d.value));
|
|
1359
1380
|
const maxY = Math.max(...allDataPoints.map((d) => d.value));
|
|
1360
|
-
|
|
1381
|
+
const yScale = createScale({
|
|
1361
1382
|
...options.yScale,
|
|
1362
1383
|
domain: [minY, maxY],
|
|
1363
1384
|
range: [height, 0]
|
|
1364
|
-
})
|
|
1385
|
+
});
|
|
1386
|
+
return getTicks(yScale, options.axis?.y?.numTicks);
|
|
1365
1387
|
}, [
|
|
1366
1388
|
options,
|
|
1367
1389
|
data,
|
|
@@ -1486,7 +1508,7 @@ const MIN_PIXEL_SIZE = 3;
|
|
|
1486
1508
|
/**
|
|
1487
1509
|
* Pixel size for zero-value bars (1px less than near-zero to be visually distinguishable).
|
|
1488
1510
|
*/
|
|
1489
|
-
const ZERO_PIXEL_SIZE =
|
|
1511
|
+
const ZERO_PIXEL_SIZE = 2;
|
|
1490
1512
|
const useZeroValueDisplay = (data, options = { enabled: false }) => {
|
|
1491
1513
|
const { enabled, valueAxisLength } = options;
|
|
1492
1514
|
return useMemo(() => {
|
|
@@ -1664,6 +1686,21 @@ const useGlobalChartsTheme = () => {
|
|
|
1664
1686
|
return useContext(GlobalChartsContext)?.theme ?? defaultTheme;
|
|
1665
1687
|
};
|
|
1666
1688
|
//#endregion
|
|
1689
|
+
//#region src/providers/chart-context/hooks/use-chart-formatting.ts
|
|
1690
|
+
const RUNTIME_FORMATTING = {};
|
|
1691
|
+
/**
|
|
1692
|
+
* The locale and time zone dates are rendered in, as set on `GlobalChartsProvider`.
|
|
1693
|
+
*
|
|
1694
|
+
* Falls back to the runtime's own rather than throwing: charts render outside a
|
|
1695
|
+
* provider, and a host that sets neither gets exactly the browser-default
|
|
1696
|
+
* behavior this package had before the context existed.
|
|
1697
|
+
*
|
|
1698
|
+
* @return The host's formatting context.
|
|
1699
|
+
*/
|
|
1700
|
+
const useChartFormatting = () => {
|
|
1701
|
+
return useContext(GlobalChartsContext)?.formatting ?? RUNTIME_FORMATTING;
|
|
1702
|
+
};
|
|
1703
|
+
//#endregion
|
|
1667
1704
|
//#region src/components/legend/utils/value-or-identity.ts
|
|
1668
1705
|
/**
|
|
1669
1706
|
* Returns an object's value if defined, or the object.
|
|
@@ -2101,9 +2138,311 @@ const BaseTooltip = ({ data, top, left, component: Component = DefaultTooltipCon
|
|
|
2101
2138
|
});
|
|
2102
2139
|
};
|
|
2103
2140
|
//#endregion
|
|
2141
|
+
//#region src/components/tooltip/private/bounded-tooltip.tsx
|
|
2142
|
+
const DEFAULT_OFFSET = 10;
|
|
2143
|
+
const isClipping = (element) => {
|
|
2144
|
+
const { overflow, overflowX, overflowY } = getComputedStyle(element);
|
|
2145
|
+
return [
|
|
2146
|
+
overflow,
|
|
2147
|
+
overflowX,
|
|
2148
|
+
overflowY
|
|
2149
|
+
].some((value) => value && value !== "visible");
|
|
2150
|
+
};
|
|
2151
|
+
const findClippingAncestor = (wrapper) => {
|
|
2152
|
+
let element = wrapper.parentElement;
|
|
2153
|
+
while (element && element !== document.body) {
|
|
2154
|
+
if (isClipping(element)) return element;
|
|
2155
|
+
element = element.parentElement;
|
|
2156
|
+
}
|
|
2157
|
+
return null;
|
|
2158
|
+
};
|
|
2159
|
+
/**
|
|
2160
|
+
* Where the box goes, in wrapper coordinates. Below and to the right of the
|
|
2161
|
+
* anchor; flipped to the other side when that side clips less, as visx's
|
|
2162
|
+
* `TooltipWithBounds` decides it; then clamped so the box stays inside
|
|
2163
|
+
* `bounds` whenever it fits at all.
|
|
2164
|
+
*
|
|
2165
|
+
* @param params - Anchor, offsets, the box size and the bounds to keep inside.
|
|
2166
|
+
* @param params.left - Anchor x, in wrapper coordinates.
|
|
2167
|
+
* @param params.top - Anchor y, in wrapper coordinates.
|
|
2168
|
+
* @param params.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2169
|
+
* @param params.offsetTop - Gap between the anchor and the box, vertically.
|
|
2170
|
+
* @param params.box - Rendered size of the box.
|
|
2171
|
+
* @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
|
|
2172
|
+
* @return The box's top-left corner, rounded to whole pixels.
|
|
2173
|
+
*/
|
|
2174
|
+
const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) => {
|
|
2175
|
+
const rightX = left + offsetLeft;
|
|
2176
|
+
const leftX = left - offsetLeft - box.width;
|
|
2177
|
+
const rightOverflow = rightX + box.width - bounds.right;
|
|
2178
|
+
const leftOverflow = bounds.left - leftX;
|
|
2179
|
+
let x = rightOverflow > 0 && rightOverflow > leftOverflow ? leftX : rightX;
|
|
2180
|
+
const downY = top + offsetTop;
|
|
2181
|
+
const upY = top - offsetTop - box.height;
|
|
2182
|
+
const downOverflow = downY + box.height - bounds.bottom;
|
|
2183
|
+
const upOverflow = bounds.top - upY;
|
|
2184
|
+
let y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
|
|
2185
|
+
x = Math.min(Math.max(x, bounds.left), Math.max(bounds.left, bounds.right - box.width));
|
|
2186
|
+
y = Math.min(Math.max(y, bounds.top), Math.max(bounds.top, bounds.bottom - box.height));
|
|
2187
|
+
return {
|
|
2188
|
+
x: Math.round(x),
|
|
2189
|
+
y: Math.round(y)
|
|
2190
|
+
};
|
|
2191
|
+
};
|
|
2192
|
+
/**
|
|
2193
|
+
* visx's `Tooltip`, positioned like its `TooltipWithBounds` but kept inside the
|
|
2194
|
+
* nearest clipping ancestor — or the viewport when there is none — rather than
|
|
2195
|
+
* inside its own parent. Rendered in-tree, a tooltip's parent is the chart
|
|
2196
|
+
* wrapper, which is often narrower than the box; measuring against the parent
|
|
2197
|
+
* alone would let the box spill into an `overflow: hidden` card and be cut off.
|
|
2198
|
+
*
|
|
2199
|
+
* Re-measures on every render, so a box whose content changes width between
|
|
2200
|
+
* two hovers is placed for its current size.
|
|
2201
|
+
*
|
|
2202
|
+
* @param props - visx `Tooltip` props.
|
|
2203
|
+
* @param props.left - Anchor x, in wrapper coordinates.
|
|
2204
|
+
* @param props.top - Anchor y, in wrapper coordinates.
|
|
2205
|
+
* @param props.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2206
|
+
* @param props.offsetTop - Gap between the anchor and the box, vertically.
|
|
2207
|
+
* @param props.style - Box styles; visx's defaults unless `unstyled`.
|
|
2208
|
+
* @param props.unstyled - Skip `style` and leave the box bare.
|
|
2209
|
+
* @param props.children - Box content.
|
|
2210
|
+
* @return The tooltip box.
|
|
2211
|
+
*/
|
|
2212
|
+
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = defaultStyles, unstyled = false, children, ...rest }) => {
|
|
2213
|
+
const nodeRef = useRef(null);
|
|
2214
|
+
const clipRef = useRef(null);
|
|
2215
|
+
const [position, setPosition] = useState(null);
|
|
2216
|
+
useLayoutEffect(() => {
|
|
2217
|
+
const node = nodeRef.current;
|
|
2218
|
+
const wrapper = node?.parentElement;
|
|
2219
|
+
if (!node || !wrapper) return;
|
|
2220
|
+
if (clipRef.current?.wrapper !== wrapper) clipRef.current = {
|
|
2221
|
+
wrapper,
|
|
2222
|
+
clip: findClippingAncestor(wrapper)
|
|
2223
|
+
};
|
|
2224
|
+
const own = node.getBoundingClientRect();
|
|
2225
|
+
const wrapperRect = wrapper.getBoundingClientRect();
|
|
2226
|
+
const clipRect = clipRef.current.clip?.getBoundingClientRect() ?? {
|
|
2227
|
+
left: 0,
|
|
2228
|
+
top: 0,
|
|
2229
|
+
right: window.innerWidth,
|
|
2230
|
+
bottom: window.innerHeight
|
|
2231
|
+
};
|
|
2232
|
+
const next = getBoundedPosition({
|
|
2233
|
+
left,
|
|
2234
|
+
top,
|
|
2235
|
+
offsetLeft,
|
|
2236
|
+
offsetTop,
|
|
2237
|
+
box: {
|
|
2238
|
+
width: own.width,
|
|
2239
|
+
height: own.height
|
|
2240
|
+
},
|
|
2241
|
+
bounds: {
|
|
2242
|
+
left: clipRect.left - wrapperRect.left,
|
|
2243
|
+
top: clipRect.top - wrapperRect.top,
|
|
2244
|
+
right: clipRect.right - wrapperRect.left,
|
|
2245
|
+
bottom: clipRect.bottom - wrapperRect.top
|
|
2246
|
+
}
|
|
2247
|
+
});
|
|
2248
|
+
setPosition((current) => current && current.x === next.x && current.y === next.y ? current : next);
|
|
2249
|
+
}, [
|
|
2250
|
+
left,
|
|
2251
|
+
top,
|
|
2252
|
+
offsetLeft,
|
|
2253
|
+
offsetTop,
|
|
2254
|
+
children
|
|
2255
|
+
]);
|
|
2256
|
+
const x = position?.x ?? left + offsetLeft;
|
|
2257
|
+
const y = position?.y ?? top + offsetTop;
|
|
2258
|
+
return /* @__PURE__ */ jsx(Tooltip, {
|
|
2259
|
+
ref: nodeRef,
|
|
2260
|
+
style: {
|
|
2261
|
+
position: "absolute",
|
|
2262
|
+
left: 0,
|
|
2263
|
+
top: 0,
|
|
2264
|
+
transform: `translate(${x}px, ${y}px)`,
|
|
2265
|
+
...!unstyled && style
|
|
2266
|
+
},
|
|
2267
|
+
...rest,
|
|
2268
|
+
children
|
|
2269
|
+
});
|
|
2270
|
+
};
|
|
2271
|
+
//#endregion
|
|
2272
|
+
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2273
|
+
const CROSSHAIR_STROKE_WIDTH = 1.5;
|
|
2274
|
+
const DEFAULT_GLYPH_RADIUS = 4;
|
|
2275
|
+
const FALLBACK_COLOR = "#222";
|
|
2276
|
+
const DEFAULT_TOOLTIP_Z_INDEX = 3;
|
|
2277
|
+
const PORTAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
2278
|
+
"scroll",
|
|
2279
|
+
"debounce",
|
|
2280
|
+
"resizeObserverPolyfill"
|
|
2281
|
+
]);
|
|
2282
|
+
const isValidNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2283
|
+
const scaleBandwidth = (scale) => {
|
|
2284
|
+
const bandwidth = scale?.bandwidth;
|
|
2285
|
+
return typeof bandwidth === "function" ? Number(bandwidth()) : 0;
|
|
2286
|
+
};
|
|
2287
|
+
const DefaultGlyph$1 = ({ x, y, size, color, glyphStyle, seriesKey }) => {
|
|
2288
|
+
const { theme } = useContext(DataContext) || {};
|
|
2289
|
+
return /* @__PURE__ */ jsx("circle", {
|
|
2290
|
+
cx: x,
|
|
2291
|
+
cy: y,
|
|
2292
|
+
r: size,
|
|
2293
|
+
fill: color,
|
|
2294
|
+
stroke: theme?.backgroundColor,
|
|
2295
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2296
|
+
paintOrder: "fill",
|
|
2297
|
+
...glyphStyle
|
|
2298
|
+
});
|
|
2299
|
+
};
|
|
2300
|
+
const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ jsx(DefaultGlyph$1, {
|
|
2301
|
+
seriesKey: key,
|
|
2302
|
+
...props
|
|
2303
|
+
}, key);
|
|
2304
|
+
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, zIndex = DEFAULT_TOOLTIP_Z_INDEX, ...rest }) => {
|
|
2305
|
+
const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
|
|
2306
|
+
const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = useContext(DataContext) || {};
|
|
2307
|
+
const tooltipContent = renderTooltip ? renderTooltip({
|
|
2308
|
+
...tooltipContext,
|
|
2309
|
+
colorScale
|
|
2310
|
+
}) : null;
|
|
2311
|
+
if (tooltipContent == null) return null;
|
|
2312
|
+
const scaleX = xScale;
|
|
2313
|
+
const scaleY = yScale;
|
|
2314
|
+
const getDatumLeftTop = (key, datum) => {
|
|
2315
|
+
const entry = dataRegistry?.get(key);
|
|
2316
|
+
return {
|
|
2317
|
+
left: scaleX && entry?.xAccessor ? Number(scaleX(entry.xAccessor(datum))) + scaleBandwidth(xScale) / 2 : void 0,
|
|
2318
|
+
top: scaleY && entry?.yAccessor ? Number(scaleY(entry.yAccessor(datum))) + scaleBandwidth(yScale) / 2 : void 0
|
|
2319
|
+
};
|
|
2320
|
+
};
|
|
2321
|
+
const nearestDatum = tooltipContext.tooltipData?.nearestDatum;
|
|
2322
|
+
let { tooltipLeft, tooltipTop } = tooltipContext;
|
|
2323
|
+
if (nearestDatum && (snapTooltipToDatumX || snapTooltipToDatumY)) {
|
|
2324
|
+
const { left, top } = getDatumLeftTop(nearestDatum.key, nearestDatum.datum);
|
|
2325
|
+
if (snapTooltipToDatumX && isValidNumber(left)) tooltipLeft = left;
|
|
2326
|
+
if (snapTooltipToDatumY && isValidNumber(top)) tooltipTop = top;
|
|
2327
|
+
}
|
|
2328
|
+
const glyphs = [];
|
|
2329
|
+
if (showDatumGlyph || showSeriesGlyphs) {
|
|
2330
|
+
const size = Number(glyphStyle?.radius ?? DEFAULT_GLYPH_RADIUS);
|
|
2331
|
+
const labelColor = theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2332
|
+
const fallbackColor = showSeriesGlyphs ? labelColor : theme?.gridStyles?.stroke ?? labelColor;
|
|
2333
|
+
let entries = [];
|
|
2334
|
+
if (showSeriesGlyphs) entries = Object.values(tooltipContext.tooltipData?.datumByKey ?? {});
|
|
2335
|
+
else if (nearestDatum) entries = [nearestDatum];
|
|
2336
|
+
for (const { key, datum, index } of entries) {
|
|
2337
|
+
const { left, top } = getDatumLeftTop(key, datum);
|
|
2338
|
+
if (!isValidNumber(left) || !isValidNumber(top)) continue;
|
|
2339
|
+
glyphs.push(/* @__PURE__ */ jsx("g", {
|
|
2340
|
+
className: "visx-tooltip-glyph",
|
|
2341
|
+
transform: `translate(${left}, ${top})`,
|
|
2342
|
+
children: renderGlyph({
|
|
2343
|
+
key,
|
|
2344
|
+
color: colorScale?.(key) ?? fallbackColor,
|
|
2345
|
+
datum,
|
|
2346
|
+
index,
|
|
2347
|
+
size,
|
|
2348
|
+
x: 0,
|
|
2349
|
+
y: 0,
|
|
2350
|
+
glyphStyle,
|
|
2351
|
+
isNearestDatum: nearestDatum?.key === key
|
|
2352
|
+
})
|
|
2353
|
+
}, key));
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2357
|
+
const marginTop = margin?.top ?? 0;
|
|
2358
|
+
const marginLeft = margin?.left ?? 0;
|
|
2359
|
+
const TooltipComponent = detectBounds ? BoundedTooltip : Tooltip;
|
|
2360
|
+
const boxStyle = {
|
|
2361
|
+
...defaultStyles,
|
|
2362
|
+
zIndex,
|
|
2363
|
+
background: theme?.backgroundColor ?? "white",
|
|
2364
|
+
boxShadow: `0 1px 2px ${theme?.htmlLabel?.color ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2365
|
+
...theme?.htmlLabel
|
|
2366
|
+
};
|
|
2367
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("g", {
|
|
2368
|
+
className: "visx-tooltip-overlay",
|
|
2369
|
+
pointerEvents: "none",
|
|
2370
|
+
children: [
|
|
2371
|
+
showVerticalCrosshair && isValidNumber(tooltipLeft) && /* @__PURE__ */ jsx("line", {
|
|
2372
|
+
className: "visx-crosshair visx-crosshair-vertical",
|
|
2373
|
+
x1: tooltipLeft,
|
|
2374
|
+
x2: tooltipLeft,
|
|
2375
|
+
y1: marginTop,
|
|
2376
|
+
y2: marginTop + innerHeight,
|
|
2377
|
+
stroke: crosshairStroke,
|
|
2378
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2379
|
+
...verticalCrosshairStyle
|
|
2380
|
+
}),
|
|
2381
|
+
showHorizontalCrosshair && isValidNumber(tooltipTop) && /* @__PURE__ */ jsx("line", {
|
|
2382
|
+
className: "visx-crosshair visx-crosshair-horizontal",
|
|
2383
|
+
x1: marginLeft,
|
|
2384
|
+
x2: marginLeft + innerWidth,
|
|
2385
|
+
y1: tooltipTop,
|
|
2386
|
+
y2: tooltipTop,
|
|
2387
|
+
stroke: crosshairStroke,
|
|
2388
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2389
|
+
...horizontalCrosshairStyle
|
|
2390
|
+
}),
|
|
2391
|
+
glyphs
|
|
2392
|
+
]
|
|
2393
|
+
}), container && createPortal(/* @__PURE__ */ jsx(TooltipComponent, {
|
|
2394
|
+
left: tooltipLeft,
|
|
2395
|
+
top: tooltipTop,
|
|
2396
|
+
style: boxStyle,
|
|
2397
|
+
applyPositionStyle: true,
|
|
2398
|
+
...tooltipProps,
|
|
2399
|
+
children: tooltipContent
|
|
2400
|
+
}), container)] });
|
|
2401
|
+
};
|
|
2402
|
+
/**
|
|
2403
|
+
* In-tree replacement for `@visx/xychart`'s `Tooltip`.
|
|
2404
|
+
*
|
|
2405
|
+
* visx renders its tooltip box, glyphs and crosshairs through portals appended
|
|
2406
|
+
* to `document.body`. That puts them in the page's root stacking context, where
|
|
2407
|
+
* they paint above every sticky or fixed element that lives inside a nested
|
|
2408
|
+
* stacking context, and no z-index on that element can change the order. This
|
|
2409
|
+
* component draws the glyphs and crosshairs straight into the chart SVG and
|
|
2410
|
+
* renders the tooltip box into the SVG's parent element, so all of them stack
|
|
2411
|
+
* as ordinary descendants of the chart.
|
|
2412
|
+
*
|
|
2413
|
+
* Render it as a child of `XYChart`. The element wrapping that `XYChart` must
|
|
2414
|
+
* be `position: relative` with the SVG at its origin, and `isolation: isolate`:
|
|
2415
|
+
* the box is placed with the SVG-local coordinates visx reports, and the
|
|
2416
|
+
* isolation keeps the box's `zIndex` from competing with page chrome. The box
|
|
2417
|
+
* flips and clamps to stay inside the nearest ancestor that clips its overflow
|
|
2418
|
+
* (or the viewport), so it may extend past the chart wrapper but is never cut
|
|
2419
|
+
* off unless that ancestor is smaller than the box itself.
|
|
2420
|
+
*
|
|
2421
|
+
* @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
|
|
2422
|
+
* @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
|
|
2423
|
+
*/
|
|
2424
|
+
const XyChartTooltip = (props) => {
|
|
2425
|
+
const tooltipContext = useContext(TooltipContext);
|
|
2426
|
+
const [container, setContainer] = useState(null);
|
|
2427
|
+
const anchorRef = useCallback((node) => {
|
|
2428
|
+
setContainer(node?.ownerSVGElement?.parentElement ?? null);
|
|
2429
|
+
}, []);
|
|
2430
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("g", { ref: anchorRef }), tooltipContext?.tooltipOpen && /* @__PURE__ */ jsx(XyChartTooltipContent, {
|
|
2431
|
+
...props,
|
|
2432
|
+
tooltipContext,
|
|
2433
|
+
container
|
|
2434
|
+
})] });
|
|
2435
|
+
};
|
|
2436
|
+
//#endregion
|
|
2104
2437
|
//#region src/components/tooltip/accessible-tooltip.tsx
|
|
2105
|
-
const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", ...props }) => {
|
|
2438
|
+
const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
|
|
2106
2439
|
const tooltipContext = useContext(TooltipContext);
|
|
2440
|
+
const scopeElement = useChartScopeElement();
|
|
2441
|
+
const crosshairStroke = useMemo(() => {
|
|
2442
|
+
const stroke = resolveCssVariable(CATALOG_POINTERS.grid, scopeElement);
|
|
2443
|
+
return stroke ? { stroke } : void 0;
|
|
2444
|
+
}, [scopeElement]);
|
|
2445
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
2107
2446
|
const tooltipData = useMemo(() => {
|
|
2108
2447
|
if (mode !== "individual") return [];
|
|
2109
2448
|
if (series.length === 0) return [];
|
|
@@ -2164,11 +2503,11 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2164
2503
|
tabIndex: -1,
|
|
2165
2504
|
role: "tooltip",
|
|
2166
2505
|
"aria-atomic": "true",
|
|
2167
|
-
className: clsx(
|
|
2506
|
+
className: clsx(standaloneScopeClass, keyboardFocusedClassName),
|
|
2168
2507
|
children: tooltipContent
|
|
2169
2508
|
}, `chart-tooltip-${selectedIndex}`);
|
|
2170
2509
|
return /* @__PURE__ */ jsx("div", {
|
|
2171
|
-
className:
|
|
2510
|
+
className: standaloneScopeClass,
|
|
2172
2511
|
role: "tooltip",
|
|
2173
2512
|
"aria-live": "polite",
|
|
2174
2513
|
children: tooltipContent
|
|
@@ -2178,14 +2517,23 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2178
2517
|
renderTooltip,
|
|
2179
2518
|
selectedIndex,
|
|
2180
2519
|
tooltipRef,
|
|
2181
|
-
keyboardFocusedClassName
|
|
2520
|
+
keyboardFocusedClassName,
|
|
2521
|
+
standaloneScopeClass
|
|
2182
2522
|
]);
|
|
2183
|
-
return /* @__PURE__ */ jsx(
|
|
2523
|
+
return /* @__PURE__ */ jsx(XyChartTooltip, {
|
|
2184
2524
|
...props,
|
|
2525
|
+
verticalCrosshairStyle: {
|
|
2526
|
+
...crosshairStroke,
|
|
2527
|
+
...verticalCrosshairStyle
|
|
2528
|
+
},
|
|
2529
|
+
horizontalCrosshairStyle: {
|
|
2530
|
+
...crosshairStroke,
|
|
2531
|
+
...horizontalCrosshairStyle
|
|
2532
|
+
},
|
|
2185
2533
|
renderTooltip: focusableRenderTooltip
|
|
2186
2534
|
});
|
|
2187
2535
|
};
|
|
2188
|
-
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints }) => {
|
|
2536
|
+
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate }) => {
|
|
2189
2537
|
return {
|
|
2190
2538
|
tooltipRef: useCallback((element) => {
|
|
2191
2539
|
if (element && selectedIndex !== void 0) element.focus();
|
|
@@ -2226,13 +2574,14 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
|
|
|
2226
2574
|
setSelectedIndex(void 0);
|
|
2227
2575
|
setIsNavigating(false);
|
|
2228
2576
|
chartRef.current?.focus();
|
|
2229
|
-
}
|
|
2577
|
+
} else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) onActivate?.(selectedIndex);
|
|
2230
2578
|
}, [
|
|
2231
2579
|
totalPoints,
|
|
2232
2580
|
selectedIndex,
|
|
2233
2581
|
setSelectedIndex,
|
|
2234
2582
|
setIsNavigating,
|
|
2235
|
-
chartRef
|
|
2583
|
+
chartRef,
|
|
2584
|
+
onActivate
|
|
2236
2585
|
])
|
|
2237
2586
|
};
|
|
2238
2587
|
};
|
|
@@ -2519,72 +2868,90 @@ const getCurveType = (type, smoothing) => {
|
|
|
2519
2868
|
default: return curveLinear;
|
|
2520
2869
|
}
|
|
2521
2870
|
};
|
|
2522
|
-
const
|
|
2523
|
-
|
|
2524
|
-
return (timestamp) => {
|
|
2525
|
-
if (!Number.isFinite(Number(timestamp))) return new Date(timestamp).toLocaleDateString();
|
|
2526
|
-
formatter = formatter ?? new Intl.DateTimeFormat(void 0, options);
|
|
2527
|
-
return formatter.format(timestamp);
|
|
2528
|
-
};
|
|
2529
|
-
};
|
|
2530
|
-
const formatYearTick = dateTimeFormat({ year: "numeric" });
|
|
2531
|
-
const formatDateTick = dateTimeFormat({
|
|
2871
|
+
const YEAR_TICK = { year: "numeric" };
|
|
2872
|
+
const DATE_TICK = {
|
|
2532
2873
|
month: "short",
|
|
2533
2874
|
day: "numeric"
|
|
2534
|
-
}
|
|
2535
|
-
const
|
|
2536
|
-
|
|
2537
|
-
hour12: true
|
|
2538
|
-
});
|
|
2539
|
-
const formatMonthTick = dateTimeFormat({ month: "short" });
|
|
2875
|
+
};
|
|
2876
|
+
const HOUR_TICK = { hour: "numeric" };
|
|
2877
|
+
const MONTH_TICK = { month: "short" };
|
|
2540
2878
|
const boundaryFormat = (isAnchor, atBoundary, between) => {
|
|
2541
2879
|
const format = (timestamp) => isAnchor(new Date(timestamp)) ? atBoundary(timestamp) : between(timestamp);
|
|
2542
2880
|
format.isAnchor = isAnchor;
|
|
2543
2881
|
return format;
|
|
2544
2882
|
};
|
|
2545
|
-
const
|
|
2546
|
-
const
|
|
2883
|
+
const tickFormats = (formatting) => {
|
|
2884
|
+
const clock = createZonedClock(formatting.timeZone);
|
|
2885
|
+
const year = createDateFormatter(YEAR_TICK, formatting);
|
|
2886
|
+
const date = createDateFormatter(DATE_TICK, formatting);
|
|
2887
|
+
const hour = createDateFormatter(HOUR_TICK, formatting);
|
|
2888
|
+
const month = createDateFormatter(MONTH_TICK, formatting);
|
|
2889
|
+
const datedTick = (timestamp) => date(timestamp);
|
|
2890
|
+
datedTick.anchorsAtLabelChange = true;
|
|
2891
|
+
return {
|
|
2892
|
+
year,
|
|
2893
|
+
date: datedTick,
|
|
2894
|
+
dateOrHour: boundaryFormat((value) => clock(value).hour === 0, date, hour),
|
|
2895
|
+
hour,
|
|
2896
|
+
monthOrYear: boundaryFormat((value) => clock(value).month === 1, year, month)
|
|
2897
|
+
};
|
|
2898
|
+
};
|
|
2547
2899
|
const getSpan = (sortedData) => {
|
|
2548
|
-
const bounds = sortedData.map((datom) => [datom.data.at(0)?.date, datom.data.at(-1)?.date]).filter(([first, last]) => first
|
|
2900
|
+
const bounds = sortedData.map((datom) => [datom.data.at(0)?.date, datom.data.at(-1)?.date]).filter(([first, last]) => Number.isFinite(Number(first)) && Number.isFinite(Number(last)));
|
|
2549
2901
|
if (!bounds.length) return null;
|
|
2550
2902
|
return {
|
|
2551
2903
|
minX: Math.min(...bounds.map(([first]) => Number(first))),
|
|
2552
2904
|
maxX: Math.max(...bounds.map(([, last]) => Number(last)))
|
|
2553
2905
|
};
|
|
2554
2906
|
};
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
const
|
|
2565
|
-
|
|
2566
|
-
const spacingInHours = getPointSpacingInHours(sortedData);
|
|
2567
|
-
if (spacingInHours < SUB_DAILY_SPACING_HOURS) return "hour";
|
|
2568
|
-
if (!Number.isFinite(spacingInHours) || spacingInHours < MONTHLY_SPACING_HOURS) return "day";
|
|
2569
|
-
return spacingInHours < 12 * MONTHLY_SPACING_HOURS ? "month" : "year";
|
|
2570
|
-
};
|
|
2571
|
-
const getFormatter = (sortedData, tickResolution) => {
|
|
2907
|
+
/**
|
|
2908
|
+
* The most informative tick format for a bucket resolution and the span on screen.
|
|
2909
|
+
*
|
|
2910
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
2911
|
+
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
2912
|
+
* @param formatting - Host locale and time zone.
|
|
2913
|
+
* @param domain - The effective scale domain, or undefined for the data's own extent.
|
|
2914
|
+
* @return The formatter the axis labels its ticks with.
|
|
2915
|
+
*/
|
|
2916
|
+
const getFormatter = (sortedData, tickResolution, formatting = {}, domain) => {
|
|
2917
|
+
const format = tickFormats(formatting);
|
|
2572
2918
|
const resolution = getBucketResolution(sortedData, tickResolution);
|
|
2573
|
-
if (resolution === "year") return
|
|
2574
|
-
if (resolution === "month") return
|
|
2575
|
-
const span =
|
|
2576
|
-
|
|
2919
|
+
if (resolution === "year") return format.year;
|
|
2920
|
+
if (resolution === "month") return format.monthOrYear;
|
|
2921
|
+
const span = domain ? {
|
|
2922
|
+
minX: domain[0].getTime(),
|
|
2923
|
+
maxX: domain[1].getTime()
|
|
2924
|
+
} : getSpan(sortedData);
|
|
2925
|
+
if (!span) return format.date;
|
|
2577
2926
|
const diffInHours = Math.abs(differenceInHours(span.maxX, span.minX));
|
|
2578
2927
|
if (resolution === "hour") {
|
|
2579
|
-
if (diffInHours
|
|
2580
|
-
if (diffInHours <= 168) return
|
|
2928
|
+
if (diffInHours < 24) return format.hour;
|
|
2929
|
+
if (diffInHours <= 168) return format.dateOrHour;
|
|
2581
2930
|
}
|
|
2582
|
-
return Math.abs(differenceInYears(span.maxX, span.minX)) <= 1 ?
|
|
2931
|
+
return Math.abs(differenceInYears(span.maxX, span.minX)) <= 1 ? format.date : format.year;
|
|
2932
|
+
};
|
|
2933
|
+
/**
|
|
2934
|
+
* The instants a set of series spans, as a scale domain.
|
|
2935
|
+
*
|
|
2936
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
2937
|
+
* @return Earliest and latest dated point, or undefined when nothing is dated.
|
|
2938
|
+
*/
|
|
2939
|
+
const getSeriesExtent = (sortedData) => {
|
|
2940
|
+
const span = getSpan(sortedData);
|
|
2941
|
+
return span ? [new Date(span.minX), new Date(span.maxX)] : void 0;
|
|
2942
|
+
};
|
|
2943
|
+
const getAnchorIndices = (domain, tickFormatter, labels) => {
|
|
2944
|
+
if (tickFormatter.anchorsAtLabelChange) return labels.reduce((indices, label, index) => {
|
|
2945
|
+
if (index === 0 || label !== labels[index - 1]) indices.push(index);
|
|
2946
|
+
return indices;
|
|
2947
|
+
}, []);
|
|
2948
|
+
const { isAnchor } = tickFormatter;
|
|
2949
|
+
if (!isAnchor) return [];
|
|
2950
|
+
return domain.reduce((indices, date, index) => {
|
|
2951
|
+
if (isAnchor(date)) indices.push(index);
|
|
2952
|
+
return indices;
|
|
2953
|
+
}, []);
|
|
2583
2954
|
};
|
|
2584
|
-
const getAnchorIndices = (domain, isAnchor) => domain.reduce((indices, date, index) => {
|
|
2585
|
-
if (isAnchor(date)) indices.push(index);
|
|
2586
|
-
return indices;
|
|
2587
|
-
}, []);
|
|
2588
2955
|
const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
2589
2956
|
const steps = /* @__PURE__ */ new Set();
|
|
2590
2957
|
for (let count = maxTicks; count > 1; count--) {
|
|
@@ -2599,26 +2966,25 @@ const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
|
2599
2966
|
return steps;
|
|
2600
2967
|
};
|
|
2601
2968
|
/**
|
|
2602
|
-
* Tick values for
|
|
2969
|
+
* Tick values sampled by index, for the bar chart's band axis and for evenly
|
|
2970
|
+
* spaced points on a continuous one.
|
|
2603
2971
|
*
|
|
2604
|
-
* visx samples
|
|
2605
|
-
*
|
|
2606
|
-
*
|
|
2607
|
-
*
|
|
2608
|
-
*
|
|
2609
|
-
*
|
|
2610
|
-
* identical labels side by side.
|
|
2972
|
+
* visx samples by index from offset zero, blind to which labels carry a boundary
|
|
2973
|
+
* and without collapsing repeats — so the tick that prints the year or the date
|
|
2974
|
+
* often isn't sampled at all, and a long series can show the same label twice.
|
|
2975
|
+
* Choose the values instead: sweep the evenly spaced candidates, including those
|
|
2976
|
+
* that step from anchor to anchor, and keep the one that reaches the most anchors
|
|
2977
|
+
* without thinning the axis or putting two identical labels side by side.
|
|
2611
2978
|
*
|
|
2612
|
-
* @param domain -
|
|
2979
|
+
* @param domain - Buckets in axis order.
|
|
2613
2980
|
* @param tickFormatter - Formatter the axis will render these values with.
|
|
2614
2981
|
* @param maxTicks - Most ticks the axis should carry.
|
|
2615
2982
|
* @return Values to hand the axis as `tickValues`.
|
|
2616
2983
|
*/
|
|
2617
2984
|
const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
2618
2985
|
if (!domain.length) return [];
|
|
2619
|
-
const { isAnchor } = tickFormatter;
|
|
2620
|
-
const anchorIndices = isAnchor ? getAnchorIndices(domain, isAnchor) : [];
|
|
2621
2986
|
const domainLabels = domain.map((date) => tickFormatter(date.getTime()));
|
|
2987
|
+
const anchorIndices = getAnchorIndices(domain, tickFormatter, domainLabels);
|
|
2622
2988
|
const candidates = [];
|
|
2623
2989
|
const consider = (indices) => {
|
|
2624
2990
|
if (!indices.length || indices.length > maxTicks) return;
|
|
@@ -2630,15 +2996,108 @@ const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
|
2630
2996
|
for (let index = offset; index < domain.length; index += step) indices.push(index);
|
|
2631
2997
|
consider(indices);
|
|
2632
2998
|
}
|
|
2633
|
-
|
|
2999
|
+
const minStride = Math.max(1, Math.ceil(anchorIndices.length / maxTicks));
|
|
3000
|
+
for (let stride = minStride; stride <= anchorIndices.length; stride++) {
|
|
3001
|
+
const stepped = [];
|
|
3002
|
+
for (let position = 0; position < anchorIndices.length; position += stride) stepped.push(anchorIndices[position]);
|
|
3003
|
+
consider(stepped);
|
|
3004
|
+
}
|
|
2634
3005
|
if (!candidates.length) return [domain[0]];
|
|
2635
3006
|
const densest = candidates.reduce((most, indices) => Math.max(most, indices.length), 0);
|
|
2636
|
-
const
|
|
3007
|
+
const anchorIndexSet = new Set(anchorIndices);
|
|
3008
|
+
const anchorsIn = (indices) => indices.filter((index) => anchorIndexSet.has(index)).length;
|
|
2637
3009
|
return candidates.filter((indices) => indices.length >= densest - 1).reduce((chosen, indices) => {
|
|
2638
3010
|
const gain = anchorsIn(indices) - anchorsIn(chosen);
|
|
2639
3011
|
return gain > 0 || gain === 0 && indices.length > chosen.length ? indices : chosen;
|
|
2640
3012
|
}).map((index) => domain[index]);
|
|
2641
3013
|
};
|
|
3014
|
+
/**
|
|
3015
|
+
* The most x-axis ticks a chart of this width has room for.
|
|
3016
|
+
*
|
|
3017
|
+
* @param chartWidth - Chart width in pixels.
|
|
3018
|
+
* @return A tick budget of at least one.
|
|
3019
|
+
*/
|
|
3020
|
+
const getMaxTicksForWidth = (chartWidth) => Math.max(1, Math.floor(chartWidth / X_TICK_WIDTH));
|
|
3021
|
+
const MIN_GAP_IN_LABELS = .9;
|
|
3022
|
+
const nearestValue = (sorted, target) => {
|
|
3023
|
+
let low = 0;
|
|
3024
|
+
let high = sorted.length - 1;
|
|
3025
|
+
while (low < high) {
|
|
3026
|
+
const middle = Math.floor((low + high) / 2);
|
|
3027
|
+
if (sorted[middle] < target) low = middle + 1;
|
|
3028
|
+
else high = middle;
|
|
3029
|
+
}
|
|
3030
|
+
const above = sorted[low];
|
|
3031
|
+
const below = low > 0 ? sorted[low - 1] : above;
|
|
3032
|
+
return Math.abs(above - target) <= Math.abs(below - target) ? above : below;
|
|
3033
|
+
};
|
|
3034
|
+
const getPositionTickValues = (points, tickFormatter, maxTicks, axis) => {
|
|
3035
|
+
const times = points.map((point) => point.getTime());
|
|
3036
|
+
const { first, last } = axis;
|
|
3037
|
+
if (maxTicks <= 1 || times.length === 1 || first === last) return [points[0]];
|
|
3038
|
+
const step = (last - first) / (maxTicks - 1);
|
|
3039
|
+
const labels = points.map((point) => tickFormatter(point.getTime()));
|
|
3040
|
+
const minGap = (last - first) / maxTicks * MIN_GAP_IN_LABELS;
|
|
3041
|
+
const anchors = getAnchorIndices(points, tickFormatter, labels).map((index) => times[index]);
|
|
3042
|
+
const chosen = [];
|
|
3043
|
+
let lastLabel = null;
|
|
3044
|
+
for (let index = 0; index < maxTicks; index++) {
|
|
3045
|
+
const target = first + index * step;
|
|
3046
|
+
const anchor = anchors.length ? nearestValue(anchors, target) : null;
|
|
3047
|
+
let tick = anchor !== null && Math.abs(anchor - target) <= step / 2 ? anchor : null;
|
|
3048
|
+
if (tick === null) {
|
|
3049
|
+
const point = nearestValue(times, target);
|
|
3050
|
+
tick = Math.abs(point - target) <= step / 2 ? point : target;
|
|
3051
|
+
}
|
|
3052
|
+
const previous = chosen[chosen.length - 1];
|
|
3053
|
+
if (previous !== void 0 && (tick <= previous || tick - previous < minGap)) continue;
|
|
3054
|
+
const label = tickFormatter(tick);
|
|
3055
|
+
if (label === lastLabel) continue;
|
|
3056
|
+
chosen.push(tick);
|
|
3057
|
+
lastLabel = label;
|
|
3058
|
+
}
|
|
3059
|
+
return chosen.map((timestamp) => new Date(timestamp));
|
|
3060
|
+
};
|
|
3061
|
+
const isIndexSamplingUnusable = (ticks, points, maxTicks, axis) => {
|
|
3062
|
+
if (ticks.length < 2 || points.length < 2) return false;
|
|
3063
|
+
const span = axis.last - axis.first;
|
|
3064
|
+
if (!span) return false;
|
|
3065
|
+
return ticks.slice(1).reduce((nearest, tick, index) => Math.min(nearest, tick.getTime() - ticks[index].getTime()), Infinity) < span / maxTicks * MIN_GAP_IN_LABELS || ticks.length < Math.min(maxTicks, points.length) / 3;
|
|
3066
|
+
};
|
|
3067
|
+
/**
|
|
3068
|
+
* Tick values for a continuous time axis, chosen from the points it draws.
|
|
3069
|
+
*
|
|
3070
|
+
* Sampled by index while the points are evenly spaced, which keeps the axis on
|
|
3071
|
+
* the calendar boundaries `getBandTickValues` steers towards, and by position
|
|
3072
|
+
* once they are not, where an index stride crowds one end of the scale.
|
|
3073
|
+
*
|
|
3074
|
+
* Values are taken from the data wherever there is one to take, so a local time
|
|
3075
|
+
* that does not exist cannot become a tick and DST needs no special case. Only a
|
|
3076
|
+
* target stranded in a gap is constructed, as a plain instant.
|
|
3077
|
+
*
|
|
3078
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
3079
|
+
* @param domain - The effective scale domain, or undefined for all data.
|
|
3080
|
+
* @param tickFormatter - The formatter the ticks will be labeled with.
|
|
3081
|
+
* @param maxTicks - The most ticks the axis has room for.
|
|
3082
|
+
* @return Tick dates, or null when no series carries a usable date.
|
|
3083
|
+
*/
|
|
3084
|
+
const getTimeAxisTickValues = (sortedData, domain, tickFormatter, maxTicks) => {
|
|
3085
|
+
const byTimestamp = /* @__PURE__ */ new Map();
|
|
3086
|
+
for (const series of sortedData) for (const point of series.data) {
|
|
3087
|
+
const date = point.date;
|
|
3088
|
+
if (date instanceof Date && Number.isFinite(date.getTime())) byTimestamp.set(date.getTime(), date);
|
|
3089
|
+
}
|
|
3090
|
+
if (!byTimestamp.size) return null;
|
|
3091
|
+
const min = domain?.[0]?.getTime();
|
|
3092
|
+
const max = domain?.[1]?.getTime();
|
|
3093
|
+
const visible = [...byTimestamp.keys()].sort((a, b) => a - b).filter((timestamp) => (min === void 0 || timestamp >= min) && (max === void 0 || timestamp <= max)).map((timestamp) => byTimestamp.get(timestamp));
|
|
3094
|
+
const axis = {
|
|
3095
|
+
first: min ?? visible[0].getTime(),
|
|
3096
|
+
last: max ?? visible[visible.length - 1].getTime()
|
|
3097
|
+
};
|
|
3098
|
+
const ticks = getBandTickValues(visible, tickFormatter, maxTicks);
|
|
3099
|
+
return isIndexSamplingUnusable(ticks, visible, maxTicks, axis) ? getPositionTickValues(visible, tickFormatter, maxTicks, axis) : ticks;
|
|
3100
|
+
};
|
|
2642
3101
|
const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
2643
3102
|
const span = getSpan(data);
|
|
2644
3103
|
if (!span) return 1;
|
|
@@ -2653,7 +3112,43 @@ const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
|
2653
3112
|
if (ticks.some((tick, idx) => idx > 0 && tick === ticks[idx - 1])) continue;
|
|
2654
3113
|
return ticks.length;
|
|
2655
3114
|
}
|
|
2656
|
-
return secondBestGuess;
|
|
3115
|
+
return Math.max(1, secondBestGuess);
|
|
3116
|
+
};
|
|
3117
|
+
//#endregion
|
|
3118
|
+
//#region src/charts/private/time-axis-options.ts
|
|
3119
|
+
const toDateDomain = (domain) => domain ? [new Date(domain[0]), new Date(domain[1])] : void 0;
|
|
3120
|
+
/**
|
|
3121
|
+
* The x-axis options for a continuous time chart, shared by LineChart and AreaChart.
|
|
3122
|
+
*
|
|
3123
|
+
* Kept in one place so the tick-selection logic isn't duplicated between them.
|
|
3124
|
+
*
|
|
3125
|
+
* @param args - Named arguments.
|
|
3126
|
+
* @param args.dataSorted - Series as returned by `useChartDataTransform`.
|
|
3127
|
+
* @param args.width - Chart width in pixels, which bounds how many ticks fit.
|
|
3128
|
+
* @param args.axisOptions - The caller's `options.axis.x`.
|
|
3129
|
+
* @param args.scaleDomain - The caller's `options.xScale.domain`.
|
|
3130
|
+
* @param args.zoomDomain - The chart's current zoom window, when zoomed.
|
|
3131
|
+
* @param args.formatting - Host locale and time zone.
|
|
3132
|
+
* @param args.isSeriesRendered - Whether visx mounts a series, i.e. the legend shows it. Defaults to all of them.
|
|
3133
|
+
* @return Options ready to spread into the chart's `axis.x`; `orientation` is always set.
|
|
3134
|
+
*/
|
|
3135
|
+
const buildTimeAxisOptions = ({ dataSorted, width, axisOptions, scaleDomain, zoomDomain, formatting, isSeriesRendered }) => {
|
|
3136
|
+
const { tickResolution, tickFormat, tickValues: callerTickValues, numTicks: callerNumTicks, orientation: callerOrientation, display: callerDisplay, ...rest } = axisOptions ?? {};
|
|
3137
|
+
const rendered = isSeriesRendered ? dataSorted.filter(isSeriesRendered) : dataSorted;
|
|
3138
|
+
const effectiveDomain = zoomDomain ?? toDateDomain(scaleDomain) ?? getSeriesExtent(rendered);
|
|
3139
|
+
const ownFormatter = getFormatter(rendered, tickResolution, formatting, effectiveDomain);
|
|
3140
|
+
const formatter = tickFormat || ownFormatter;
|
|
3141
|
+
const ownTickValues = tickFormat || callerTickValues ? null : getTimeAxisTickValues(rendered, effectiveDomain, ownFormatter, callerNumTicks ?? getMaxTicksForWidth(width));
|
|
3142
|
+
const tickValues = callerTickValues ?? (ownTickValues?.length ? ownTickValues : void 0);
|
|
3143
|
+
const numTicks = callerNumTicks ?? (tickValues ? void 0 : guessOptimalNumTicks(rendered, width, formatter));
|
|
3144
|
+
return {
|
|
3145
|
+
orientation: callerOrientation ?? "bottom",
|
|
3146
|
+
tickFormat: formatter,
|
|
3147
|
+
display: callerDisplay ?? true,
|
|
3148
|
+
...rest,
|
|
3149
|
+
...tickValues ? { tickValues } : {},
|
|
3150
|
+
...numTicks === void 0 ? {} : { numTicks }
|
|
3151
|
+
};
|
|
2657
3152
|
};
|
|
2658
3153
|
//#endregion
|
|
2659
3154
|
//#region src/charts/private/with-responsive/with-responsive.module.scss
|
|
@@ -2934,6 +3429,9 @@ function ZoomResetButton({ onClick }) {
|
|
|
2934
3429
|
});
|
|
2935
3430
|
}
|
|
2936
3431
|
//#endregion
|
|
3432
|
+
//#region src/charts/private/xy-plot/xy-plot.module.scss
|
|
3433
|
+
var xy_plot_module_default = { "xy-plot": "a8ccharts-bIyhgG-xy-plot" };
|
|
3434
|
+
//#endregion
|
|
2937
3435
|
//#region src/charts/line-chart/line-chart.module.scss
|
|
2938
3436
|
var line_chart_module_default = {
|
|
2939
3437
|
"line-chart": "a8ccharts-inuQka-line-chart",
|
|
@@ -2999,7 +3497,7 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
|
|
|
2999
3497
|
style: {
|
|
3000
3498
|
width: `44px`,
|
|
3001
3499
|
height: `44px`,
|
|
3002
|
-
transform: `translate(
|
|
3500
|
+
transform: `translate(22px, 0)`
|
|
3003
3501
|
},
|
|
3004
3502
|
"aria-label": title || __("View details", "jetpack-charts"),
|
|
3005
3503
|
children: renderLabel({
|
|
@@ -3174,12 +3672,14 @@ const getVerticalAnchor = (subjectType, isFlippedVertically, y, yMax, height) =>
|
|
|
3174
3672
|
};
|
|
3175
3673
|
const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", styles: datumStyles, testId, renderLabel, renderLabelPopover }) => {
|
|
3176
3674
|
const providerTheme = useGlobalChartsTheme();
|
|
3177
|
-
const scopeElement = useChartScopeElement();
|
|
3178
3675
|
const { xScale, yScale } = useContext(DataContext) || {};
|
|
3179
3676
|
const labelRef = useRef(null);
|
|
3180
3677
|
const [height, setHeight] = useState(null);
|
|
3181
|
-
const styles =
|
|
3182
|
-
|
|
3678
|
+
const styles = useMemo(() => deepmerge.all([
|
|
3679
|
+
ANNOTATION_POINTERS,
|
|
3680
|
+
providerTheme.annotationStyles ?? {},
|
|
3681
|
+
datumStyles ?? {}
|
|
3682
|
+
]), [providerTheme.annotationStyles, datumStyles]);
|
|
3183
3683
|
useEffect(() => {
|
|
3184
3684
|
if (labelRef.current?.getBBox) {
|
|
3185
3685
|
const bbox = labelRef.current.getBBox();
|
|
@@ -3265,15 +3765,8 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3265
3765
|
dx,
|
|
3266
3766
|
dy,
|
|
3267
3767
|
children: [
|
|
3268
|
-
/* @__PURE__ */ jsx(Connector, {
|
|
3269
|
-
|
|
3270
|
-
stroke: resolveColor(styles?.connector?.stroke)
|
|
3271
|
-
}),
|
|
3272
|
-
subjectType === "circle" && /* @__PURE__ */ jsx(CircleSubject, {
|
|
3273
|
-
...styles?.circleSubject,
|
|
3274
|
-
fill: resolveColor(styles?.circleSubject?.fill),
|
|
3275
|
-
stroke: resolveColor(styles?.circleSubject?.stroke)
|
|
3276
|
-
}),
|
|
3768
|
+
/* @__PURE__ */ jsx(Connector, { ...styles?.connector }),
|
|
3769
|
+
subjectType === "circle" && /* @__PURE__ */ jsx(CircleSubject, { ...styles?.circleSubject }),
|
|
3277
3770
|
subjectType === "line-vertical" && /* @__PURE__ */ jsx(LineSubject, {
|
|
3278
3771
|
min: yMax,
|
|
3279
3772
|
max: yMin,
|
|
@@ -3307,8 +3800,6 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3307
3800
|
title,
|
|
3308
3801
|
subtitle,
|
|
3309
3802
|
...styles?.label,
|
|
3310
|
-
anchorLineStroke: resolveColor(styles?.label?.anchorLineStroke),
|
|
3311
|
-
backgroundFill: resolveColor(styles?.label?.backgroundFill),
|
|
3312
3803
|
...labelPosition,
|
|
3313
3804
|
horizontalAnchor: getHorizontalAnchor(subjectType, isFlippedHorizontally),
|
|
3314
3805
|
verticalAnchor: getVerticalAnchor(subjectType, isFlippedVertically, y, yMax, height ?? ANNOTATION_INIT_HEIGHT)
|
|
@@ -3356,16 +3847,33 @@ const toNumber = (val) => {
|
|
|
3356
3847
|
const num = typeof val === "number" ? val : parseFloat(val);
|
|
3357
3848
|
return isNaN(num) ? void 0 : num;
|
|
3358
3849
|
};
|
|
3850
|
+
const TOOLTIP_DATE = {};
|
|
3851
|
+
const TOOLTIP_FORMAT_BY_RESOLUTION$1 = {
|
|
3852
|
+
hour: {
|
|
3853
|
+
year: "numeric",
|
|
3854
|
+
month: "numeric",
|
|
3855
|
+
day: "numeric",
|
|
3856
|
+
hour: "numeric"
|
|
3857
|
+
},
|
|
3858
|
+
day: TOOLTIP_DATE,
|
|
3859
|
+
month: TOOLTIP_DATE,
|
|
3860
|
+
year: TOOLTIP_DATE
|
|
3861
|
+
};
|
|
3862
|
+
const TooltipDate = ({ date, displayResolution }) => {
|
|
3863
|
+
const formatting = useChartFormatting();
|
|
3864
|
+
const format = useMemo(() => createDateFormatter(TOOLTIP_FORMAT_BY_RESOLUTION$1[displayResolution], formatting), [displayResolution, formatting]);
|
|
3865
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: date ? format(date) : null });
|
|
3866
|
+
};
|
|
3359
3867
|
/**
|
|
3360
3868
|
* Default visx-tooltip render that prints the hovered date as a heading and
|
|
3361
3869
|
* one row per visible series (label + formatted value), sorted descending by
|
|
3362
3870
|
* value. Reused by AreaChart, which has the same multi-series shape.
|
|
3363
3871
|
*
|
|
3364
|
-
* @param params - visx `RenderTooltipParams< DataPointDate
|
|
3872
|
+
* @param params - visx `RenderTooltipParams< DataPointDate >`, plus the chart's optional `bucketInfo`.
|
|
3365
3873
|
* @return Tooltip JSX, or `null` when no datum is hovered.
|
|
3366
3874
|
*/
|
|
3367
3875
|
const renderDefaultTooltip = (params) => {
|
|
3368
|
-
const { tooltipData } = params;
|
|
3876
|
+
const { tooltipData, bucketInfo } = params;
|
|
3369
3877
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
3370
3878
|
if (!nearestDatum) return null;
|
|
3371
3879
|
const tooltipPoints = Object.entries(tooltipData?.datumByKey || {}).map(([key, { datum }]) => ({
|
|
@@ -3376,7 +3884,10 @@ const renderDefaultTooltip = (params) => {
|
|
|
3376
3884
|
className: line_chart_module_default["line-chart__tooltip"],
|
|
3377
3885
|
children: [/* @__PURE__ */ jsx("div", {
|
|
3378
3886
|
className: line_chart_module_default["line-chart__tooltip-date"],
|
|
3379
|
-
children:
|
|
3887
|
+
children: /* @__PURE__ */ jsx(TooltipDate, {
|
|
3888
|
+
date: nearestDatum.date,
|
|
3889
|
+
displayResolution: bucketInfo?.displayResolution ?? "day"
|
|
3890
|
+
})
|
|
3380
3891
|
}), tooltipPoints.map((point) => /* @__PURE__ */ jsxs(Stack, {
|
|
3381
3892
|
direction: "row",
|
|
3382
3893
|
align: "center",
|
|
@@ -3420,14 +3931,14 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
3420
3931
|
]);
|
|
3421
3932
|
return null;
|
|
3422
3933
|
};
|
|
3423
|
-
const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
3934
|
+
const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, onDatumActivate = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
3424
3935
|
const legendInteractive = legend.interactive ?? false;
|
|
3425
3936
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
3426
3937
|
const legendShape = legend.shape ?? "line";
|
|
3427
3938
|
const legendPosition = legend.position ?? "bottom";
|
|
3428
|
-
const
|
|
3939
|
+
const formatting = useChartFormatting();
|
|
3429
3940
|
const theme = useXYChartTheme(data);
|
|
3430
|
-
const resolvedBackgroundColor = theme.backgroundColor
|
|
3941
|
+
const resolvedBackgroundColor = theme.backgroundColor;
|
|
3431
3942
|
const chartId = useChartId(providedChartId);
|
|
3432
3943
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
3433
3944
|
const isSeriesVisible = useCallback((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
|
|
@@ -3482,26 +3993,36 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3482
3993
|
}
|
|
3483
3994
|
return min < max ? [min, max] : void 0;
|
|
3484
3995
|
}, [rescaleYOnVisibilityChange, dataSorted]);
|
|
3996
|
+
const activateSelectedPoint = useCallback((index) => {
|
|
3997
|
+
const series = dataSorted[0];
|
|
3998
|
+
const datum = series?.data[index];
|
|
3999
|
+
if (series && datum) onDatumActivate?.({
|
|
4000
|
+
datum,
|
|
4001
|
+
index,
|
|
4002
|
+
key: series.label
|
|
4003
|
+
});
|
|
4004
|
+
}, [dataSorted, onDatumActivate]);
|
|
3485
4005
|
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
3486
4006
|
selectedIndex,
|
|
3487
4007
|
setSelectedIndex,
|
|
3488
4008
|
isNavigating,
|
|
3489
4009
|
setIsNavigating,
|
|
3490
4010
|
chartRef,
|
|
3491
|
-
totalPoints: dataSorted[0]?.data.length || 0
|
|
4011
|
+
totalPoints: dataSorted[0]?.data.length || 0,
|
|
4012
|
+
onActivate: activateSelectedPoint
|
|
3492
4013
|
});
|
|
3493
4014
|
const chartOptions = useMemo(() => {
|
|
3494
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
3495
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
3496
4015
|
return {
|
|
3497
4016
|
axis: {
|
|
3498
|
-
x: {
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
4017
|
+
x: buildTimeAxisOptions({
|
|
4018
|
+
dataSorted,
|
|
4019
|
+
width,
|
|
4020
|
+
axisOptions: options?.axis?.x,
|
|
4021
|
+
scaleDomain: options?.xScale?.domain,
|
|
4022
|
+
zoomDomain: zoom.domain,
|
|
4023
|
+
formatting,
|
|
4024
|
+
isSeriesRendered: (series) => isSeriesVisible(series.label)
|
|
4025
|
+
}),
|
|
3505
4026
|
y: {
|
|
3506
4027
|
orientation: "left",
|
|
3507
4028
|
numTicks: 4,
|
|
@@ -3528,7 +4049,14 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3528
4049
|
dataSorted,
|
|
3529
4050
|
width,
|
|
3530
4051
|
zoom.domain,
|
|
3531
|
-
stableYDomain
|
|
4052
|
+
stableYDomain,
|
|
4053
|
+
formatting,
|
|
4054
|
+
isSeriesVisible
|
|
4055
|
+
]);
|
|
4056
|
+
const bucketInfo = useMemo(() => getBucketInfo(dataSorted.filter((series) => isSeriesVisible(series.label)), options?.axis?.x?.tickResolution), [
|
|
4057
|
+
dataSorted,
|
|
4058
|
+
isSeriesVisible,
|
|
4059
|
+
options?.axis?.x?.tickResolution
|
|
3532
4060
|
]);
|
|
3533
4061
|
const tooltipRenderGlyph = useMemo(() => {
|
|
3534
4062
|
return (props) => {
|
|
@@ -3552,42 +4080,48 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3552
4080
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme);
|
|
3553
4081
|
const error = validateData$4(dataSorted);
|
|
3554
4082
|
const isDataValid = !error;
|
|
4083
|
+
const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({
|
|
4084
|
+
withGlyph: withLegendGlyph,
|
|
4085
|
+
glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
|
|
4086
|
+
collapseGroups: legendCollapseGroups,
|
|
4087
|
+
renderGlyph
|
|
4088
|
+
}), [
|
|
4089
|
+
withLegendGlyph,
|
|
4090
|
+
glyphStyle?.radius,
|
|
4091
|
+
legendCollapseGroups,
|
|
4092
|
+
renderGlyph
|
|
4093
|
+
]), legendShape);
|
|
4094
|
+
const chartMetadata = useMemo(() => ({
|
|
4095
|
+
withGradientFill,
|
|
4096
|
+
smoothing,
|
|
4097
|
+
curveType,
|
|
4098
|
+
withStartGlyphs,
|
|
4099
|
+
withEndGlyphs,
|
|
4100
|
+
withLegendGlyph
|
|
4101
|
+
}), [
|
|
4102
|
+
withGradientFill,
|
|
4103
|
+
smoothing,
|
|
4104
|
+
curveType,
|
|
4105
|
+
withStartGlyphs,
|
|
4106
|
+
withEndGlyphs,
|
|
4107
|
+
withLegendGlyph
|
|
4108
|
+
]);
|
|
3555
4109
|
useChartRegistration({
|
|
3556
4110
|
chartId,
|
|
3557
|
-
legendItems
|
|
3558
|
-
withGlyph: withLegendGlyph,
|
|
3559
|
-
glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
|
|
3560
|
-
collapseGroups: legendCollapseGroups,
|
|
3561
|
-
renderGlyph
|
|
3562
|
-
}), [
|
|
3563
|
-
withLegendGlyph,
|
|
3564
|
-
glyphStyle?.radius,
|
|
3565
|
-
legendCollapseGroups,
|
|
3566
|
-
renderGlyph
|
|
3567
|
-
]), legendShape),
|
|
4111
|
+
legendItems,
|
|
3568
4112
|
chartType: "line",
|
|
3569
4113
|
isDataValid,
|
|
3570
|
-
metadata:
|
|
3571
|
-
withGradientFill,
|
|
3572
|
-
smoothing,
|
|
3573
|
-
curveType,
|
|
3574
|
-
withStartGlyphs,
|
|
3575
|
-
withEndGlyphs,
|
|
3576
|
-
withLegendGlyph
|
|
3577
|
-
}), [
|
|
3578
|
-
withGradientFill,
|
|
3579
|
-
smoothing,
|
|
3580
|
-
curveType,
|
|
3581
|
-
withStartGlyphs,
|
|
3582
|
-
withEndGlyphs,
|
|
3583
|
-
withLegendGlyph
|
|
3584
|
-
])
|
|
4114
|
+
metadata: chartMetadata
|
|
3585
4115
|
});
|
|
3586
4116
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3587
4117
|
const accessors = {
|
|
3588
4118
|
xAccessor: (d) => d?.date,
|
|
3589
4119
|
yAccessor: (d) => d?.value
|
|
3590
4120
|
};
|
|
4121
|
+
const tooltipRenderer = useMemo(() => (params) => renderTooltip({
|
|
4122
|
+
...params,
|
|
4123
|
+
bucketInfo
|
|
4124
|
+
}), [renderTooltip, bucketInfo]);
|
|
3591
4125
|
if (error) return /* @__PURE__ */ jsx("div", {
|
|
3592
4126
|
className: clsx("line-chart", line_chart_module_default["line-chart"]),
|
|
3593
4127
|
children: error
|
|
@@ -3636,7 +4170,7 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3636
4170
|
onBlur: onChartBlur,
|
|
3637
4171
|
children: chartHeight > 0 && /* @__PURE__ */ jsxs("div", {
|
|
3638
4172
|
ref: chartRef,
|
|
3639
|
-
|
|
4173
|
+
className: xy_plot_module_default["xy-plot"],
|
|
3640
4174
|
children: [zoomable && zoom.domain && /* @__PURE__ */ jsx(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ jsxs(XYChart, {
|
|
3641
4175
|
theme,
|
|
3642
4176
|
width,
|
|
@@ -3728,7 +4262,7 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3728
4262
|
snapTooltipToDatumX: true,
|
|
3729
4263
|
snapTooltipToDatumY: true,
|
|
3730
4264
|
showSeriesGlyphs: true,
|
|
3731
|
-
renderTooltip,
|
|
4265
|
+
renderTooltip: tooltipRenderer,
|
|
3732
4266
|
renderGlyph: tooltipRenderGlyph,
|
|
3733
4267
|
glyphStyle,
|
|
3734
4268
|
showVerticalCrosshair: withTooltipCrosshairs?.showVertical,
|
|
@@ -3866,12 +4400,11 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
|
|
|
3866
4400
|
};
|
|
3867
4401
|
//#endregion
|
|
3868
4402
|
//#region src/charts/area-chart/area-chart.tsx
|
|
3869
|
-
const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange
|
|
4403
|
+
const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
3870
4404
|
const legendInteractive = legend.interactive ?? false;
|
|
3871
4405
|
const legendShape = legend.shape ?? "rect";
|
|
3872
4406
|
const legendPosition = legend.position ?? "bottom";
|
|
3873
|
-
const
|
|
3874
|
-
const providerTheme = useGlobalChartsTheme();
|
|
4407
|
+
const formatting = useChartFormatting();
|
|
3875
4408
|
const theme = useXYChartTheme(data);
|
|
3876
4409
|
const chartId = useChartId(providedChartId);
|
|
3877
4410
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
@@ -3921,7 +4454,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3921
4454
|
totalPoints: dataSorted[0]?.data.length || 0
|
|
3922
4455
|
});
|
|
3923
4456
|
const fixedYDomain = useMemo(() => {
|
|
3924
|
-
if (
|
|
4457
|
+
if (rescaleYOnVisibilityChange || !dataSorted.length || !dataSorted[0].data.length || stacked && stackOffset !== "none") return;
|
|
3925
4458
|
if (stacked) {
|
|
3926
4459
|
const numPoints = Math.max(...dataSorted.map((s) => s.data.length));
|
|
3927
4460
|
let posMax = 0;
|
|
@@ -3955,20 +4488,19 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3955
4488
|
dataSorted,
|
|
3956
4489
|
stacked,
|
|
3957
4490
|
stackOffset,
|
|
3958
|
-
|
|
4491
|
+
rescaleYOnVisibilityChange
|
|
3959
4492
|
]);
|
|
3960
4493
|
const chartOptions = useMemo(() => {
|
|
3961
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
3962
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
3963
4494
|
return {
|
|
3964
4495
|
axis: {
|
|
3965
|
-
x: {
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
4496
|
+
x: buildTimeAxisOptions({
|
|
4497
|
+
dataSorted,
|
|
4498
|
+
width,
|
|
4499
|
+
axisOptions: options?.axis?.x,
|
|
4500
|
+
scaleDomain: options?.xScale?.domain,
|
|
4501
|
+
zoomDomain: zoom.domain,
|
|
4502
|
+
formatting
|
|
4503
|
+
}),
|
|
3972
4504
|
y: {
|
|
3973
4505
|
orientation: "left",
|
|
3974
4506
|
numTicks: 4,
|
|
@@ -3996,31 +4528,34 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
3996
4528
|
width,
|
|
3997
4529
|
stacked,
|
|
3998
4530
|
fixedYDomain,
|
|
3999
|
-
zoom.domain
|
|
4531
|
+
zoom.domain,
|
|
4532
|
+
formatting
|
|
4000
4533
|
]);
|
|
4001
4534
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme);
|
|
4002
4535
|
const error = validateData$3(dataSorted);
|
|
4003
4536
|
const isDataValid = !error;
|
|
4537
|
+
const legendItems = useChartLegendItems(dataSorted, useMemo(() => ({
|
|
4538
|
+
withGlyph: false,
|
|
4539
|
+
glyphSize: 0,
|
|
4540
|
+
collapseGroups: legend.collapseGroups ?? false
|
|
4541
|
+
}), [legend.collapseGroups]), legendShape);
|
|
4542
|
+
const chartMetadata = useMemo(() => ({
|
|
4543
|
+
stacked,
|
|
4544
|
+
stackOffset,
|
|
4545
|
+
smoothing,
|
|
4546
|
+
curveType
|
|
4547
|
+
}), [
|
|
4548
|
+
stacked,
|
|
4549
|
+
stackOffset,
|
|
4550
|
+
smoothing,
|
|
4551
|
+
curveType
|
|
4552
|
+
]);
|
|
4004
4553
|
useChartRegistration({
|
|
4005
4554
|
chartId,
|
|
4006
|
-
legendItems
|
|
4007
|
-
withGlyph: false,
|
|
4008
|
-
glyphSize: 0,
|
|
4009
|
-
collapseGroups: legend.collapseGroups ?? false
|
|
4010
|
-
}), [legend.collapseGroups]), legendShape),
|
|
4555
|
+
legendItems,
|
|
4011
4556
|
chartType: "area",
|
|
4012
4557
|
isDataValid,
|
|
4013
|
-
metadata:
|
|
4014
|
-
stacked,
|
|
4015
|
-
stackOffset,
|
|
4016
|
-
smoothing,
|
|
4017
|
-
curveType
|
|
4018
|
-
}), [
|
|
4019
|
-
stacked,
|
|
4020
|
-
stackOffset,
|
|
4021
|
-
smoothing,
|
|
4022
|
-
curveType
|
|
4023
|
-
])
|
|
4558
|
+
metadata: chartMetadata
|
|
4024
4559
|
});
|
|
4025
4560
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
4026
4561
|
const animationEnabled = !!animation && !prefersReducedMotion;
|
|
@@ -4030,9 +4565,17 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4030
4565
|
};
|
|
4031
4566
|
const zeroYAccessor = useCallback(() => 0, []);
|
|
4032
4567
|
const visibleLabels = useMemo(() => new Set(seriesWithVisibility.filter((s) => s.isVisible).map((s) => s.series.label)), [seriesWithVisibility]);
|
|
4568
|
+
const bucketInfo = useMemo(() => getBucketInfo(dataSorted.filter((series) => visibleLabels.has(series.label)), options?.axis?.x?.tickResolution), [
|
|
4569
|
+
dataSorted,
|
|
4570
|
+
visibleLabels,
|
|
4571
|
+
options?.axis?.x?.tickResolution
|
|
4572
|
+
]);
|
|
4033
4573
|
const filteredRenderTooltip = useCallback((params) => {
|
|
4034
4574
|
const datumByKey = params?.tooltipData?.datumByKey;
|
|
4035
|
-
if (!datumByKey) return renderTooltip(
|
|
4575
|
+
if (!datumByKey) return renderTooltip({
|
|
4576
|
+
...params,
|
|
4577
|
+
bucketInfo
|
|
4578
|
+
});
|
|
4036
4579
|
const filtered = Object.fromEntries(Object.entries(datumByKey).filter(([key]) => visibleLabels.has(key)));
|
|
4037
4580
|
if (Object.keys(filtered).length === 0) return null;
|
|
4038
4581
|
const nearestDatum = params?.tooltipData?.nearestDatum;
|
|
@@ -4042,13 +4585,18 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4042
4585
|
};
|
|
4043
4586
|
return renderTooltip({
|
|
4044
4587
|
...params,
|
|
4588
|
+
bucketInfo,
|
|
4045
4589
|
tooltipData: {
|
|
4046
4590
|
...params.tooltipData,
|
|
4047
4591
|
datumByKey: filtered,
|
|
4048
4592
|
nearestDatum: nextNearest
|
|
4049
4593
|
}
|
|
4050
4594
|
});
|
|
4051
|
-
}, [
|
|
4595
|
+
}, [
|
|
4596
|
+
renderTooltip,
|
|
4597
|
+
visibleLabels,
|
|
4598
|
+
bucketInfo
|
|
4599
|
+
]);
|
|
4052
4600
|
const resolvedFillOpacity = fillOpacity ?? (stacked ? .85 : .4);
|
|
4053
4601
|
const resolvedWithStroke = withStroke ?? !stacked;
|
|
4054
4602
|
if (error) return /* @__PURE__ */ jsx("div", {
|
|
@@ -4123,7 +4671,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4123
4671
|
onBlur: onChartBlur,
|
|
4124
4672
|
children: chartHeight > 0 && /* @__PURE__ */ jsxs("div", {
|
|
4125
4673
|
ref: chartRef,
|
|
4126
|
-
|
|
4674
|
+
className: xy_plot_module_default["xy-plot"],
|
|
4127
4675
|
children: [zoomable && zoom.domain && /* @__PURE__ */ jsx(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ jsxs(XYChart, {
|
|
4128
4676
|
theme,
|
|
4129
4677
|
width,
|
|
@@ -4179,7 +4727,7 @@ const AreaChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4179
4727
|
stacked,
|
|
4180
4728
|
stackOffset,
|
|
4181
4729
|
getElementStyles,
|
|
4182
|
-
strokeColor: theme.backgroundColor
|
|
4730
|
+
strokeColor: theme.backgroundColor
|
|
4183
4731
|
})] }),
|
|
4184
4732
|
/* @__PURE__ */ jsx(AreaChartScalesRef, {
|
|
4185
4733
|
chartRef: internalChartRef,
|
|
@@ -4347,8 +4895,7 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4347
4895
|
year: "numeric",
|
|
4348
4896
|
month: "long",
|
|
4349
4897
|
day: "numeric",
|
|
4350
|
-
hour: "numeric"
|
|
4351
|
-
hour12: true
|
|
4898
|
+
hour: "numeric"
|
|
4352
4899
|
},
|
|
4353
4900
|
day: {
|
|
4354
4901
|
year: "numeric",
|
|
@@ -4367,16 +4914,16 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4367
4914
|
*
|
|
4368
4915
|
* @param data - Date-based series, already parsed and sorted by `useChartDataTransform`.
|
|
4369
4916
|
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
4917
|
+
* @param formatting - Host locale and time zone.
|
|
4370
4918
|
* @return Tooltip label formatter.
|
|
4371
4919
|
*/
|
|
4372
|
-
const getTooltipFormatter = (data, tickResolution) => {
|
|
4373
|
-
if (tickResolution === "week")
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
}));
|
|
4920
|
+
const getTooltipFormatter = (data, tickResolution, formatting) => {
|
|
4921
|
+
if (tickResolution === "week") {
|
|
4922
|
+
const formatDay = createDateFormatter(TOOLTIP_FORMAT_BY_RESOLUTION.day, formatting);
|
|
4923
|
+
return (timestamp) => sprintf(__("Week of %s", "jetpack-charts"), formatDay(timestamp));
|
|
4924
|
+
}
|
|
4378
4925
|
const format = TOOLTIP_FORMAT_BY_RESOLUTION[getBucketResolution(data, tickResolution)] ?? TOOLTIP_FORMAT_BY_RESOLUTION.day;
|
|
4379
|
-
return (
|
|
4926
|
+
return createDateFormatter(format, formatting);
|
|
4380
4927
|
};
|
|
4381
4928
|
const identity = (label) => label;
|
|
4382
4929
|
const byBucket = (format) => (bucket) => typeof bucket === "string" ? bucket : format(Number(bucket));
|
|
@@ -4427,6 +4974,7 @@ const getGroupPadding = (scale) => {
|
|
|
4427
4974
|
*/
|
|
4428
4975
|
function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = ALL_RENDERED) {
|
|
4429
4976
|
const stableOptions = useDeepMemo(options);
|
|
4977
|
+
const formatting = useChartFormatting();
|
|
4430
4978
|
const axisConfig = useMemo(() => {
|
|
4431
4979
|
const { labelOverflow: xLabelOverflow, tickResolution: xTickResolution, tickFormat: xTickFormat, ...xAxisOptions } = stableOptions.axis?.x || {};
|
|
4432
4980
|
const { labelOverflow: yLabelOverflow, tickResolution: yTickResolution, tickFormat: yTickFormat, ...yAxisOptions } = stableOptions.axis?.y || {};
|
|
@@ -4453,9 +5001,9 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4453
5001
|
zero: false
|
|
4454
5002
|
};
|
|
4455
5003
|
const hasLabels = Boolean(data?.[0]?.data?.[0]?.label);
|
|
4456
|
-
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution);
|
|
5004
|
+
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution, formatting);
|
|
4457
5005
|
const labelFormatter = timeTickFormatter ? byBucket(timeTickFormatter) : identity;
|
|
4458
|
-
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution));
|
|
5006
|
+
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution, formatting));
|
|
4459
5007
|
const valueFormatter = formatNumberCompact;
|
|
4460
5008
|
const bandDomain = timeTickFormatter ? getBandDomain(data, isSeriesRendered) : null;
|
|
4461
5009
|
const valueAccessor = (d) => {
|
|
@@ -4491,7 +5039,8 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4491
5039
|
}, [
|
|
4492
5040
|
data,
|
|
4493
5041
|
tickResolution,
|
|
4494
|
-
isSeriesRendered
|
|
5042
|
+
isSeriesRendered,
|
|
5043
|
+
formatting
|
|
4495
5044
|
]);
|
|
4496
5045
|
return useMemo(() => {
|
|
4497
5046
|
const { xTickFormat: defaultXTickFormat, yTickFormat: defaultYTickFormat, tooltipLabelFormatter: defaultTooltipLabelFormatter, xAccessor, yAccessor, gridVisibility, xScale: baseXScale, yScale: baseYScale } = defaultOptions[horizontal ? "horizontal" : "vertical"];
|
|
@@ -4615,11 +5164,6 @@ function computeComparisonRect(params) {
|
|
|
4615
5164
|
};
|
|
4616
5165
|
}
|
|
4617
5166
|
/**
|
|
4618
|
-
* Fraction of each per-series step left as a gap between bars within a single tick.
|
|
4619
|
-
* Larger = more space between adjacent series; the shadow spans `1 - COMPARISON_INNER_GAP` of the step.
|
|
4620
|
-
*/
|
|
4621
|
-
const COMPARISON_INNER_GAP = .1;
|
|
4622
|
-
/**
|
|
4623
5167
|
* Upper clamp on the computed group padding, so bars can never collapse to zero width
|
|
4624
5168
|
* even at very large `widthFactor` values.
|
|
4625
5169
|
*/
|
|
@@ -4707,7 +5251,7 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ jsx("div", {
|
|
|
4707
5251
|
className: bar_chart_module_default["bar-chart__tooltip-row"],
|
|
4708
5252
|
children: sprintf(__("%1$s: %2$s", "jetpack-charts"), label, value)
|
|
4709
5253
|
});
|
|
4710
|
-
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" }) => {
|
|
5254
|
+
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 }) => {
|
|
4711
5255
|
const legendInteractive = legend.interactive ?? false;
|
|
4712
5256
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
4713
5257
|
const horizontal = orientation === "horizontal";
|
|
@@ -4734,14 +5278,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4734
5278
|
const [selectedIndex, setSelectedIndex] = useState(void 0);
|
|
4735
5279
|
const [isNavigating, setIsNavigating] = useState(false);
|
|
4736
5280
|
const primarySeriesForNav = dataWithVisibleZeros.filter((s) => s.options?.type !== "comparison");
|
|
4737
|
-
const
|
|
4738
|
-
selectedIndex,
|
|
4739
|
-
setSelectedIndex,
|
|
4740
|
-
isNavigating,
|
|
4741
|
-
setIsNavigating,
|
|
4742
|
-
chartRef,
|
|
4743
|
-
totalPoints: Math.max(0, ...primarySeriesForNav.map((s) => s.data?.length || 0)) * primarySeriesForNav.length
|
|
4744
|
-
});
|
|
5281
|
+
const totalPoints = Math.max(0, ...primarySeriesForNav.map((s) => s.data?.length || 0)) * primarySeriesForNav.length;
|
|
4745
5282
|
const seriesWithVisibility = useMemo(() => dataWithVisibleZeros.map((series, index) => ({
|
|
4746
5283
|
series,
|
|
4747
5284
|
index,
|
|
@@ -4753,6 +5290,27 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4753
5290
|
const primaryEntries = useMemo(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
|
|
4754
5291
|
const primaryKeys = useMemo(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
|
|
4755
5292
|
const primarySeries = useMemo(() => primaryEntries.map(({ series }) => series), [primaryEntries]);
|
|
5293
|
+
const activateSelectedBar = useCallback((index) => {
|
|
5294
|
+
const primaryCount = primaryEntries.length;
|
|
5295
|
+
if (!primaryCount) return;
|
|
5296
|
+
const dataPointIndex = Math.floor(index / primaryCount);
|
|
5297
|
+
const series = primaryEntries[index % primaryCount]?.series;
|
|
5298
|
+
const datum = series?.data[dataPointIndex];
|
|
5299
|
+
if (series && datum) onDatumActivate?.({
|
|
5300
|
+
datum,
|
|
5301
|
+
index: dataPointIndex,
|
|
5302
|
+
key: series.label
|
|
5303
|
+
});
|
|
5304
|
+
}, [primaryEntries, onDatumActivate]);
|
|
5305
|
+
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
5306
|
+
selectedIndex,
|
|
5307
|
+
setSelectedIndex,
|
|
5308
|
+
isNavigating,
|
|
5309
|
+
setIsNavigating,
|
|
5310
|
+
chartRef,
|
|
5311
|
+
totalPoints,
|
|
5312
|
+
onActivate: activateSelectedBar
|
|
5313
|
+
});
|
|
4756
5314
|
const comparisonEntries = useMemo(() => {
|
|
4757
5315
|
const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
|
|
4758
5316
|
label: series.label,
|
|
@@ -4789,7 +5347,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4789
5347
|
const groupPadding = useMemo(() => {
|
|
4790
5348
|
const basePadding = chartOptions.barGroup.padding;
|
|
4791
5349
|
if (!comparisonWidthFactor || comparisonWidthFactor <= 1) return basePadding;
|
|
4792
|
-
const p = 1 -
|
|
5350
|
+
const p = 1 - .9 / comparisonWidthFactor;
|
|
4793
5351
|
return Math.min(Math.max(p, basePadding), MAX_GROUP_PADDING);
|
|
4794
5352
|
}, [chartOptions.barGroup.padding, comparisonWidthFactor]);
|
|
4795
5353
|
const { xScale, yScale } = useMemo(() => {
|
|
@@ -4927,15 +5485,17 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4927
5485
|
chartId
|
|
4928
5486
|
]);
|
|
4929
5487
|
const error = validateData$2(dataSorted);
|
|
5488
|
+
const isDataValid = !error;
|
|
5489
|
+
const chartMetadata = useMemo(() => ({
|
|
5490
|
+
orientation,
|
|
5491
|
+
withPatterns
|
|
5492
|
+
}), [orientation, withPatterns]);
|
|
4930
5493
|
useChartRegistration({
|
|
4931
5494
|
chartId,
|
|
4932
5495
|
legendItems,
|
|
4933
5496
|
chartType: "bar",
|
|
4934
|
-
isDataValid
|
|
4935
|
-
metadata:
|
|
4936
|
-
orientation,
|
|
4937
|
-
withPatterns
|
|
4938
|
-
}), [orientation, withPatterns])
|
|
5497
|
+
isDataValid,
|
|
5498
|
+
metadata: chartMetadata
|
|
4939
5499
|
});
|
|
4940
5500
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
4941
5501
|
if (error) return /* @__PURE__ */ jsx("div", {
|
|
@@ -4989,6 +5549,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4989
5549
|
onBlur: onChartBlur,
|
|
4990
5550
|
children: chartHeight > 0 && /* @__PURE__ */ jsx("div", {
|
|
4991
5551
|
ref: chartRef,
|
|
5552
|
+
className: xy_plot_module_default["xy-plot"],
|
|
4992
5553
|
children: /* @__PURE__ */ jsxs(XYChart, {
|
|
4993
5554
|
theme,
|
|
4994
5555
|
width,
|
|
@@ -5000,6 +5561,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5000
5561
|
xScale,
|
|
5001
5562
|
yScale,
|
|
5002
5563
|
horizontal,
|
|
5564
|
+
onPointerDown,
|
|
5565
|
+
onPointerUp,
|
|
5003
5566
|
pointerEventsDataKey: "nearest",
|
|
5004
5567
|
children: [
|
|
5005
5568
|
!allSeriesHidden && /* @__PURE__ */ jsx(Grid, {
|
|
@@ -5154,7 +5717,26 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5154
5717
|
right: 20,
|
|
5155
5718
|
bottom: 0,
|
|
5156
5719
|
top: 0
|
|
5157
|
-
}, ...rest }) => {
|
|
5720
|
+
}, className, ...rest }) => {
|
|
5721
|
+
const { getElementStyles } = useGlobalChartsContext();
|
|
5722
|
+
const tintedData = useMemo(() => {
|
|
5723
|
+
if (data.length > 1) return data;
|
|
5724
|
+
return data.map((series, index) => {
|
|
5725
|
+
if (series.options?.stroke) return series;
|
|
5726
|
+
const { color } = getElementStyles({
|
|
5727
|
+
data: series,
|
|
5728
|
+
index
|
|
5729
|
+
});
|
|
5730
|
+
if (!isValidHexColor(color)) return series;
|
|
5731
|
+
return {
|
|
5732
|
+
...series,
|
|
5733
|
+
options: {
|
|
5734
|
+
...series.options,
|
|
5735
|
+
stroke: lightenHexColor(color, .6)
|
|
5736
|
+
}
|
|
5737
|
+
};
|
|
5738
|
+
});
|
|
5739
|
+
}, [data, getElementStyles]);
|
|
5158
5740
|
const chartOptions = useMemo(() => {
|
|
5159
5741
|
const isMultiSeries = data.length > 1;
|
|
5160
5742
|
const defaultYScale = {
|
|
@@ -5187,7 +5769,8 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5187
5769
|
return /* @__PURE__ */ jsx(BarChart, {
|
|
5188
5770
|
orientation: "horizontal",
|
|
5189
5771
|
gridVisibility: "none",
|
|
5190
|
-
|
|
5772
|
+
className: clsx("bar-list-chart", className),
|
|
5773
|
+
data: tintedData,
|
|
5191
5774
|
width,
|
|
5192
5775
|
height,
|
|
5193
5776
|
margin,
|
|
@@ -5223,6 +5806,9 @@ const BarListChartResponsive = withResponsive(BarListChart);
|
|
|
5223
5806
|
var conversion_funnel_chart_module_default = {
|
|
5224
5807
|
"bar-container": "a8ccharts-mGEVca-bar-container",
|
|
5225
5808
|
"change-indicator": "a8ccharts-mGEVca-change-indicator",
|
|
5809
|
+
"change-indicator--negative": "a8ccharts-mGEVca-change-indicator--negative",
|
|
5810
|
+
"change-indicator--positive": "a8ccharts-mGEVca-change-indicator--positive",
|
|
5811
|
+
"conversion-funnel-chart": "a8ccharts-mGEVca-conversion-funnel-chart",
|
|
5226
5812
|
"conversion-funnel-chart--loading": "a8ccharts-mGEVca-conversion-funnel-chart--loading",
|
|
5227
5813
|
"empty-state": "a8ccharts-mGEVca-empty-state",
|
|
5228
5814
|
"funnel-bar": "a8ccharts-mGEVca-funnel-bar",
|
|
@@ -5303,23 +5889,14 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
5303
5889
|
*/
|
|
5304
5890
|
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip }) => {
|
|
5305
5891
|
const chartId = useChartId(providedChartId);
|
|
5306
|
-
const { conversionFunnelChart: conversionFunnelChartSettings } = useGlobalChartsTheme();
|
|
5307
5892
|
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
5308
5893
|
const chartRef = useRef(null);
|
|
5309
5894
|
const selectedBarRef = useRef(null);
|
|
5310
5895
|
const [scopeNode, setScopeNode] = useState(null);
|
|
5311
5896
|
const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = useTooltip();
|
|
5312
5897
|
const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
|
|
5313
|
-
const
|
|
5314
|
-
detectBounds: true,
|
|
5315
|
-
scroll: true
|
|
5316
|
-
});
|
|
5317
|
-
const portalContainerRefRef = useRef(portalContainerRef);
|
|
5318
|
-
useEffect(() => {
|
|
5319
|
-
portalContainerRefRef.current = portalContainerRef;
|
|
5320
|
-
}, [portalContainerRef]);
|
|
5898
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
5321
5899
|
const setChartRef = useCallback((node) => {
|
|
5322
|
-
portalContainerRefRef.current(node);
|
|
5323
5900
|
chartRef.current = node;
|
|
5324
5901
|
setScopeNode(node);
|
|
5325
5902
|
}, []);
|
|
@@ -5336,30 +5913,22 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5336
5913
|
});
|
|
5337
5914
|
}, [showTooltip]);
|
|
5338
5915
|
const getMouseTooltipCoords = useCallback((event) => {
|
|
5339
|
-
|
|
5916
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5917
|
+
if (!bounds) return null;
|
|
5340
5918
|
return {
|
|
5341
|
-
x: event.clientX -
|
|
5342
|
-
y: event.clientY -
|
|
5919
|
+
x: event.clientX - bounds.left,
|
|
5920
|
+
y: event.clientY - bounds.top
|
|
5343
5921
|
};
|
|
5344
|
-
}, [
|
|
5345
|
-
containerBounds.width,
|
|
5346
|
-
containerBounds.height,
|
|
5347
|
-
containerBounds.left,
|
|
5348
|
-
containerBounds.top
|
|
5349
|
-
]);
|
|
5922
|
+
}, []);
|
|
5350
5923
|
const getKeyboardTooltipCoords = useCallback((event) => {
|
|
5351
|
-
|
|
5924
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5925
|
+
if (!bounds) return null;
|
|
5352
5926
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
5353
5927
|
return {
|
|
5354
|
-
x: rect.left + rect.width / 2 -
|
|
5355
|
-
y: rect.top -
|
|
5928
|
+
x: rect.left + rect.width / 2 - bounds.left,
|
|
5929
|
+
y: rect.top - bounds.top
|
|
5356
5930
|
};
|
|
5357
|
-
}, [
|
|
5358
|
-
containerBounds.width,
|
|
5359
|
-
containerBounds.height,
|
|
5360
|
-
containerBounds.left,
|
|
5361
|
-
containerBounds.top
|
|
5362
|
-
]);
|
|
5931
|
+
}, []);
|
|
5363
5932
|
const handleStepInteraction = useCallback((step, event, interactionType) => {
|
|
5364
5933
|
selectedBarRef.current = event.currentTarget;
|
|
5365
5934
|
const { isClicked } = getStepState(step.id);
|
|
@@ -5420,19 +5989,14 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5420
5989
|
};
|
|
5421
5990
|
}, [clearSelectionAndRef]);
|
|
5422
5991
|
const resolvedHeight = height ?? style?.height ?? "100%";
|
|
5423
|
-
const {
|
|
5424
|
-
const
|
|
5425
|
-
|
|
5426
|
-
overrideColor: primaryColor
|
|
5427
|
-
}) : { color: primaryColor || "#000000" };
|
|
5428
|
-
const changeColor = changeIndicator?.startsWith("+") ? positiveChangeColor : negativeChangeColor;
|
|
5429
|
-
const barBackgroundColor = backgroundColor || hexToRgba(barColor, .08) || "rgba(0, 0, 0, 0.08)";
|
|
5992
|
+
const { color: barColor } = getElementStyles ? getElementStyles({ index: 0 }) : { color: "#000000" };
|
|
5993
|
+
const isPositiveChange = changeIndicator?.startsWith("+");
|
|
5994
|
+
const changeColor = isPositiveChange ? CATALOG_POINTERS.trendUp : CATALOG_POINTERS.trendDown;
|
|
5430
5995
|
const renderDefaultMainMetric = () => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
5431
5996
|
className: conversion_funnel_chart_module_default["main-rate"],
|
|
5432
5997
|
children: formatPercentage(mainRate)
|
|
5433
5998
|
}), changeIndicator && /* @__PURE__ */ jsx("span", {
|
|
5434
|
-
className: conversion_funnel_chart_module_default["change-indicator"],
|
|
5435
|
-
style: { color: changeColor },
|
|
5999
|
+
className: clsx(conversion_funnel_chart_module_default["change-indicator"], conversion_funnel_chart_module_default[isPositiveChange ? "change-indicator--positive" : "change-indicator--negative"]),
|
|
5436
6000
|
children: changeIndicator
|
|
5437
6001
|
})] });
|
|
5438
6002
|
const renderDefaultTooltip = (step) => /* @__PURE__ */ jsxs(Stack, {
|
|
@@ -5448,20 +6012,21 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5448
6012
|
})]
|
|
5449
6013
|
});
|
|
5450
6014
|
const isDataValid = Boolean(steps && steps.length > 0);
|
|
6015
|
+
const chartMetadata = useMemo(() => ({
|
|
6016
|
+
mainRate,
|
|
6017
|
+
changeIndicator,
|
|
6018
|
+
stepsCount: steps?.length || 0
|
|
6019
|
+
}), [
|
|
6020
|
+
mainRate,
|
|
6021
|
+
changeIndicator,
|
|
6022
|
+
steps?.length
|
|
6023
|
+
]);
|
|
5451
6024
|
useChartRegistration({
|
|
5452
6025
|
chartId,
|
|
5453
6026
|
legendItems: [],
|
|
5454
6027
|
chartType: "conversion-funnel",
|
|
5455
6028
|
isDataValid,
|
|
5456
|
-
metadata:
|
|
5457
|
-
mainRate,
|
|
5458
|
-
changeIndicator,
|
|
5459
|
-
stepsCount: steps?.length || 0
|
|
5460
|
-
}), [
|
|
5461
|
-
mainRate,
|
|
5462
|
-
changeIndicator,
|
|
5463
|
-
steps?.length
|
|
5464
|
-
])
|
|
6029
|
+
metadata: chartMetadata
|
|
5465
6030
|
});
|
|
5466
6031
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
5467
6032
|
if (!isDataValid) return /* @__PURE__ */ jsx(Stack, {
|
|
@@ -5469,7 +6034,7 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5469
6034
|
align: "center",
|
|
5470
6035
|
justify: "center",
|
|
5471
6036
|
ref: setScopeNode,
|
|
5472
|
-
className: clsx(conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
6037
|
+
className: clsx("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
5473
6038
|
style: {
|
|
5474
6039
|
...style,
|
|
5475
6040
|
height: resolvedHeight
|
|
@@ -5480,16 +6045,16 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5480
6045
|
})
|
|
5481
6046
|
});
|
|
5482
6047
|
const maxRate = Math.max(...steps.map((step) => step.rate));
|
|
5483
|
-
return /* @__PURE__ */ jsxs(
|
|
6048
|
+
return /* @__PURE__ */ jsxs(Stack, {
|
|
5484
6049
|
direction: "column",
|
|
5485
6050
|
gap: "xl",
|
|
5486
6051
|
ref: setChartRef,
|
|
5487
|
-
className: clsx(conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
6052
|
+
className: clsx("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
5488
6053
|
style: {
|
|
5489
6054
|
...style,
|
|
5490
6055
|
height: resolvedHeight
|
|
5491
6056
|
},
|
|
5492
|
-
children: /* @__PURE__ */ jsxs(ChartScopeContext.Provider, {
|
|
6057
|
+
children: [/* @__PURE__ */ jsxs(ChartScopeContext.Provider, {
|
|
5493
6058
|
value: scopeNode,
|
|
5494
6059
|
children: [renderMainMetric ? renderMainMetric({
|
|
5495
6060
|
mainRate,
|
|
@@ -5541,7 +6106,6 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5541
6106
|
role: "button",
|
|
5542
6107
|
tabIndex: isBlurred ? -1 : 0,
|
|
5543
6108
|
"aria-label": step.label,
|
|
5544
|
-
style: { backgroundColor: barBackgroundColor },
|
|
5545
6109
|
children: /* @__PURE__ */ jsx("div", {
|
|
5546
6110
|
className: clsx(conversion_funnel_chart_module_default["funnel-bar"], { [conversion_funnel_chart_module_default["funnel-bar--animated"]]: animation && !loading && !prefersReducedMotion }),
|
|
5547
6111
|
style: {
|
|
@@ -5553,23 +6117,23 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5553
6117
|
}, step.id);
|
|
5554
6118
|
})
|
|
5555
6119
|
})]
|
|
5556
|
-
})
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
}
|
|
5572
|
-
})
|
|
6120
|
+
}), tooltipOpen && tooltipData && (() => {
|
|
6121
|
+
const tooltipContent = renderTooltip ? renderTooltip({
|
|
6122
|
+
step: tooltipData,
|
|
6123
|
+
index: steps.findIndex((s) => s.id === tooltipData.id),
|
|
6124
|
+
top: tooltipTop,
|
|
6125
|
+
left: tooltipLeft,
|
|
6126
|
+
className: conversion_funnel_chart_module_default["tooltip-wrapper"]
|
|
6127
|
+
}) : renderDefaultTooltip(tooltipData);
|
|
6128
|
+
if (!tooltipContent) return null;
|
|
6129
|
+
return /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
6130
|
+
top: tooltipTop,
|
|
6131
|
+
left: tooltipLeft,
|
|
6132
|
+
className: clsx(standaloneScopeClass, conversion_funnel_chart_module_default["tooltip-wrapper"]),
|
|
6133
|
+
children: tooltipContent
|
|
6134
|
+
});
|
|
6135
|
+
})()]
|
|
6136
|
+
});
|
|
5573
6137
|
};
|
|
5574
6138
|
/**
|
|
5575
6139
|
* ConversionFunnelChart component with provider wrapper
|
|
@@ -5715,7 +6279,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
5715
6279
|
* @return A React component displaying an interactive map with data visualization
|
|
5716
6280
|
*/
|
|
5717
6281
|
const GeoChartInternal = ({ className, data, width, height, region = "world", resolution = "countries", onError, renderPlaceholder }) => {
|
|
5718
|
-
const { getElementStyles
|
|
6282
|
+
const { getElementStyles } = useGlobalChartsContext();
|
|
5719
6283
|
const scopeElement = useChartScopeElement();
|
|
5720
6284
|
const containerRef = useRef(null);
|
|
5721
6285
|
const reportedErrorIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
@@ -5749,8 +6313,8 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5749
6313
|
});
|
|
5750
6314
|
const fullColorHex = getElementStyles({ index: 0 }).color;
|
|
5751
6315
|
const lightColorHex = lightenHexColor(fullColorHex, .8);
|
|
5752
|
-
const backgroundColorHex = normalizeColorToHex(
|
|
5753
|
-
const defaultFillColorHex = normalizeColorToHex(
|
|
6316
|
+
const backgroundColorHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable) || DEFAULT_BACKGROUND_COLOR;
|
|
6317
|
+
const defaultFillColorHex = normalizeColorToHex(CATALOG_POINTERS.surfaceSecondary, scopeElement, resolveCssVariable) || DEFAULT_FEATURE_FILL_COLOR;
|
|
5754
6318
|
const sanitizedData = useMemo(() => {
|
|
5755
6319
|
if (data.length === 0) return {
|
|
5756
6320
|
data,
|
|
@@ -5811,8 +6375,7 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5811
6375
|
className: clsx("geo-chart", geo_chart_module_default.container, className),
|
|
5812
6376
|
style: {
|
|
5813
6377
|
width,
|
|
5814
|
-
height
|
|
5815
|
-
backgroundColor
|
|
6378
|
+
height
|
|
5816
6379
|
},
|
|
5817
6380
|
children: /* @__PURE__ */ jsx(Chart, {
|
|
5818
6381
|
chartType: "GeoChart",
|
|
@@ -5862,6 +6425,7 @@ var heatmap_chart_module_default = {
|
|
|
5862
6425
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
5863
6426
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
5864
6427
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
6428
|
+
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
5865
6429
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
5866
6430
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
5867
6431
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
@@ -6004,7 +6568,7 @@ const HeatmapContext = createContext(null);
|
|
|
6004
6568
|
//#region src/charts/heatmap-chart/private/heatmap-legend.tsx
|
|
6005
6569
|
const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
6006
6570
|
const context = useContext(HeatmapContext);
|
|
6007
|
-
const { legend
|
|
6571
|
+
const { legend } = useGlobalChartsTheme();
|
|
6008
6572
|
if (!context) return null;
|
|
6009
6573
|
const { primaryColorHex } = context;
|
|
6010
6574
|
const labelStyle = legend.labelStyles;
|
|
@@ -6015,6 +6579,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6015
6579
|
children: [
|
|
6016
6580
|
/* @__PURE__ */ jsx(Text$1, {
|
|
6017
6581
|
variant: "body-sm",
|
|
6582
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6018
6583
|
style: labelStyle,
|
|
6019
6584
|
children: lessLabel ?? __("Less", "jetpack-charts")
|
|
6020
6585
|
}),
|
|
@@ -6028,7 +6593,6 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6028
6593
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
6029
6594
|
style: {
|
|
6030
6595
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6031
|
-
"--a8c-charts-color-heatmap-background": backgroundColor,
|
|
6032
6596
|
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
6033
6597
|
}
|
|
6034
6598
|
}, index);
|
|
@@ -6036,6 +6600,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6036
6600
|
}),
|
|
6037
6601
|
/* @__PURE__ */ jsx(Text$1, {
|
|
6038
6602
|
variant: "body-sm",
|
|
6603
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6039
6604
|
style: labelStyle,
|
|
6040
6605
|
children: moreLabel ?? __("More", "jetpack-charts")
|
|
6041
6606
|
})
|
|
@@ -6053,19 +6618,16 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6053
6618
|
const { nonLegendChildren } = useChartChildren(children, "HeatmapChart");
|
|
6054
6619
|
const [selectedIndex, setSelectedIndex] = useState();
|
|
6055
6620
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = useTooltip();
|
|
6056
|
-
const
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
});
|
|
6060
|
-
const containerBoundsRef = useRef(containerBounds);
|
|
6061
|
-
containerBoundsRef.current = containerBounds;
|
|
6621
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
6622
|
+
const containerRef = useRef(null);
|
|
6623
|
+
const getTooltipOrigin = useCallback(() => containerRef.current?.closest(`[data-chart-id="heatmap-chart-${chartId}"]`)?.getBoundingClientRect() ?? null, [chartId]);
|
|
6062
6624
|
const { color: primaryColorHex } = getElementStyles({
|
|
6063
6625
|
index: 0,
|
|
6064
|
-
overrideColor: primaryColor
|
|
6626
|
+
overrideColor: primaryColor
|
|
6065
6627
|
});
|
|
6066
|
-
const chartBackgroundHex = normalizeColorToHex(
|
|
6628
|
+
const chartBackgroundHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable);
|
|
6067
6629
|
const primaryHex = normalizeColorToHex(primaryColorHex);
|
|
6068
|
-
const cellHasLightText = (intensity) => isValidHexColor(primaryHex) && isValidHexColor(chartBackgroundHex) && prefersLightText(mixHexColors(primaryHex, chartBackgroundHex, 1 - (CELL_MIX_FLOOR +
|
|
6630
|
+
const cellHasLightText = (intensity) => isValidHexColor(primaryHex) && isValidHexColor(chartBackgroundHex) && prefersLightText(mixHexColors(primaryHex, chartBackgroundHex, 1 - (CELL_MIX_FLOOR + .85 * intensity)));
|
|
6069
6631
|
const extent = useMemo(() => getValueExtent(data), [data]);
|
|
6070
6632
|
const heatmapContext = useMemo(() => ({
|
|
6071
6633
|
extent,
|
|
@@ -6139,19 +6701,21 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6139
6701
|
]);
|
|
6140
6702
|
const handleCellMouseMove = useCallback((event) => {
|
|
6141
6703
|
if (!withTooltips) return;
|
|
6704
|
+
const origin = getTooltipOrigin();
|
|
6705
|
+
if (!origin) return;
|
|
6142
6706
|
const target = event.currentTarget;
|
|
6143
6707
|
const columnIndex = Number(target.dataset.column);
|
|
6144
6708
|
const rowIndex = Number(target.dataset.row);
|
|
6145
|
-
const bounds = containerBoundsRef.current;
|
|
6146
6709
|
showTooltip({
|
|
6147
|
-
tooltipLeft: event.clientX -
|
|
6148
|
-
tooltipTop: event.clientY -
|
|
6710
|
+
tooltipLeft: event.clientX - origin.left,
|
|
6711
|
+
tooltipTop: event.clientY - origin.top,
|
|
6149
6712
|
tooltipData: buildTooltipData(columnIndex, rowIndex)
|
|
6150
6713
|
});
|
|
6151
6714
|
}, [
|
|
6152
6715
|
withTooltips,
|
|
6153
6716
|
showTooltip,
|
|
6154
|
-
buildTooltipData
|
|
6717
|
+
buildTooltipData,
|
|
6718
|
+
getTooltipOrigin
|
|
6155
6719
|
]);
|
|
6156
6720
|
const handleCellMouseLeave = useCallback(() => {
|
|
6157
6721
|
if (withTooltips && selectedIndex === void 0) hideTooltip();
|
|
@@ -6162,13 +6726,14 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6162
6726
|
]);
|
|
6163
6727
|
useEffect(() => {
|
|
6164
6728
|
if (!withTooltips || selectedIndex === void 0) return;
|
|
6729
|
+
const origin = getTooltipOrigin();
|
|
6730
|
+
if (!origin) return;
|
|
6165
6731
|
const col = Math.floor(selectedIndex / rows);
|
|
6166
6732
|
const row = selectedIndex % rows;
|
|
6167
6733
|
const rect = (typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null)?.getBoundingClientRect();
|
|
6168
|
-
const bounds = containerBoundsRef.current;
|
|
6169
6734
|
showTooltip({
|
|
6170
|
-
tooltipLeft: rect ? rect.left + rect.width / 2 -
|
|
6171
|
-
tooltipTop: rect ? rect.top + rect.height / 2 -
|
|
6735
|
+
tooltipLeft: rect ? rect.left + rect.width / 2 - origin.left : 0,
|
|
6736
|
+
tooltipTop: rect ? rect.top + rect.height / 2 - origin.top : 0,
|
|
6172
6737
|
tooltipData: buildTooltipData(col, row)
|
|
6173
6738
|
});
|
|
6174
6739
|
}, [
|
|
@@ -6177,7 +6742,8 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6177
6742
|
rows,
|
|
6178
6743
|
chartId,
|
|
6179
6744
|
buildTooltipData,
|
|
6180
|
-
showTooltip
|
|
6745
|
+
showTooltip,
|
|
6746
|
+
getTooltipOrigin
|
|
6181
6747
|
]);
|
|
6182
6748
|
const defaultRenderTooltip = useCallback((info) => /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("strong", { children: info.cellLabel || `${info.columnLabel ?? ""} ${info.rowLabel ?? ""}`.trim() }), /* @__PURE__ */ jsx("div", { children: info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value) })] }), []);
|
|
6183
6749
|
if (!columns || !rows) return /* @__PURE__ */ jsx(Center, {
|
|
@@ -6195,7 +6761,6 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6195
6761
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
6196
6762
|
const gridStyle = {
|
|
6197
6763
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6198
|
-
"--a8c-charts-color-heatmap-background": theme.backgroundColor,
|
|
6199
6764
|
gridTemplateColumns: `auto repeat(${columns}, ${columnTrack})`,
|
|
6200
6765
|
gridTemplateRows: `auto repeat(${rows}, ${rowTrack})`
|
|
6201
6766
|
};
|
|
@@ -6293,11 +6858,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6293
6858
|
})]
|
|
6294
6859
|
}, `row-${rowIndex}`);
|
|
6295
6860
|
})]
|
|
6296
|
-
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(
|
|
6861
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
6297
6862
|
top: tooltipTop,
|
|
6298
6863
|
left: tooltipLeft,
|
|
6299
6864
|
children: /* @__PURE__ */ jsx("div", {
|
|
6300
|
-
className:
|
|
6865
|
+
className: standaloneScopeClass,
|
|
6301
6866
|
role: "tooltip",
|
|
6302
6867
|
tabIndex: -1,
|
|
6303
6868
|
children: (renderTooltip ?? defaultRenderTooltip)(tooltipData)
|
|
@@ -6321,7 +6886,7 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ jsx(HeatmapChartW
|
|
|
6321
6886
|
HeatmapChartResponsiveInner.displayName = "HeatmapChart";
|
|
6322
6887
|
const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
|
|
6323
6888
|
//#endregion
|
|
6324
|
-
//#region ../../../node_modules/.pnpm/is-plain-object@5.
|
|
6889
|
+
//#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
|
|
6325
6890
|
/*!
|
|
6326
6891
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
6327
6892
|
*
|
|
@@ -6388,7 +6953,7 @@ function paramCase(input, options) {
|
|
|
6388
6953
|
return dotCase(input, __assign({ delimiter: "-" }, options));
|
|
6389
6954
|
}
|
|
6390
6955
|
//#endregion
|
|
6391
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
6956
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
|
|
6392
6957
|
function useUpdateEffect(effect, deps) {
|
|
6393
6958
|
const mountedRef = useRef$1(false);
|
|
6394
6959
|
useEffect$1(() => {
|
|
@@ -6420,10 +6985,11 @@ var StyleSheet = /*#__PURE__*/ function() {
|
|
|
6420
6985
|
var _this = this;
|
|
6421
6986
|
this._insertTag = function(tag) {
|
|
6422
6987
|
var before;
|
|
6423
|
-
if (_this.tags.length === 0)
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6988
|
+
if (_this.tags.length === 0) {
|
|
6989
|
+
if (_this.insertionPoint) before = _this.insertionPoint.nextSibling;
|
|
6990
|
+
else if (_this.prepend) before = _this.container.firstChild;
|
|
6991
|
+
else before = _this.before;
|
|
6992
|
+
} else before = _this.tags[_this.tags.length - 1].nextSibling;
|
|
6427
6993
|
_this.container.insertBefore(tag, before);
|
|
6428
6994
|
_this.tags.push(tag);
|
|
6429
6995
|
};
|
|
@@ -6742,9 +7308,7 @@ function delimiter(type) {
|
|
|
6742
7308
|
case 40:
|
|
6743
7309
|
if (type === 41) delimiter(type);
|
|
6744
7310
|
break;
|
|
6745
|
-
case 92:
|
|
6746
|
-
next();
|
|
6747
|
-
break;
|
|
7311
|
+
case 92: next();
|
|
6748
7312
|
}
|
|
6749
7313
|
return position;
|
|
6750
7314
|
}
|
|
@@ -7720,14 +8284,12 @@ function handleInterpolation(mergedProps, registered, interpolation) {
|
|
|
7720
8284
|
return serializedStyles.styles + ";";
|
|
7721
8285
|
}
|
|
7722
8286
|
return createStringFromObject(mergedProps, registered, interpolation);
|
|
7723
|
-
case "function":
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
}
|
|
7730
|
-
break;
|
|
8287
|
+
case "function": if (mergedProps !== void 0) {
|
|
8288
|
+
var previousCursor = cursor;
|
|
8289
|
+
var result = interpolation(mergedProps);
|
|
8290
|
+
cursor = previousCursor;
|
|
8291
|
+
return handleInterpolation(mergedProps, registered, result);
|
|
8292
|
+
}
|
|
7731
8293
|
}
|
|
7732
8294
|
var asString = interpolation;
|
|
7733
8295
|
if (registered == null) return asString;
|
|
@@ -7961,7 +8523,7 @@ _createEmotion.css;
|
|
|
7961
8523
|
_createEmotion.sheet;
|
|
7962
8524
|
_createEmotion.cache;
|
|
7963
8525
|
//#endregion
|
|
7964
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8526
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
|
|
7965
8527
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
7966
8528
|
var useCx = () => {
|
|
7967
8529
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -8068,7 +8630,7 @@ function memize(fn, options) {
|
|
|
8068
8630
|
return memoized;
|
|
8069
8631
|
}
|
|
8070
8632
|
//#endregion
|
|
8071
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8633
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/colors-values.mjs
|
|
8072
8634
|
var white = "#fff";
|
|
8073
8635
|
var GRAY = {
|
|
8074
8636
|
900: "#1e1e1e",
|
|
@@ -8147,7 +8709,7 @@ var COLORS = Object.freeze({
|
|
|
8147
8709
|
ui: UI
|
|
8148
8710
|
});
|
|
8149
8711
|
//#endregion
|
|
8150
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8712
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/config-values.mjs
|
|
8151
8713
|
var CONTROL_HEIGHT = "36px";
|
|
8152
8714
|
var CONTROL_PROPS = {
|
|
8153
8715
|
controlPaddingX: 12,
|
|
@@ -8162,9 +8724,6 @@ var CONTROL_PROPS = {
|
|
|
8162
8724
|
};
|
|
8163
8725
|
var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
8164
8726
|
colorDivider: "rgba(0, 0, 0, 0.1)",
|
|
8165
|
-
colorScrollbarThumb: "rgba(0, 0, 0, 0.2)",
|
|
8166
|
-
colorScrollbarThumbHover: "rgba(0, 0, 0, 0.5)",
|
|
8167
|
-
colorScrollbarTrack: "rgba(0, 0, 0, 0.04)",
|
|
8168
8727
|
elevationIntensity: 1,
|
|
8169
8728
|
radiusXSmall: "1px",
|
|
8170
8729
|
radiusSmall: "2px",
|
|
@@ -8175,7 +8734,6 @@ var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
|
8175
8734
|
borderWidth: "1px",
|
|
8176
8735
|
borderWidthFocus: "1.5px",
|
|
8177
8736
|
borderWidthTab: "4px",
|
|
8178
|
-
spinnerSize: 16,
|
|
8179
8737
|
fontSize: "13px",
|
|
8180
8738
|
fontSizeH1: "calc(2.44 * 13px)",
|
|
8181
8739
|
fontSizeH2: "calc(1.95 * 13px)",
|
|
@@ -8252,10 +8810,10 @@ var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
8252
8810
|
};
|
|
8253
8811
|
}));
|
|
8254
8812
|
//#endregion
|
|
8255
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.
|
|
8813
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/utils.mjs
|
|
8256
8814
|
var logged = /* @__PURE__ */ new Set();
|
|
8257
8815
|
//#endregion
|
|
8258
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.
|
|
8816
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/index.mjs
|
|
8259
8817
|
function isDev() {
|
|
8260
8818
|
return globalThis.SCRIPT_DEBUG === true;
|
|
8261
8819
|
}
|
|
@@ -8269,7 +8827,7 @@ function warning(message) {
|
|
|
8269
8827
|
logged.add(message);
|
|
8270
8828
|
}
|
|
8271
8829
|
//#endregion
|
|
8272
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8830
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
8273
8831
|
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
8274
8832
|
var ComponentsContext = createContext$1(
|
|
8275
8833
|
/** @type {Record<string, any>} */
|
|
@@ -8296,18 +8854,18 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
8296
8854
|
};
|
|
8297
8855
|
memo(BaseContextSystemProvider);
|
|
8298
8856
|
//#endregion
|
|
8299
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8857
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/constants.mjs
|
|
8300
8858
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
8301
8859
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
8302
8860
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
8303
8861
|
//#endregion
|
|
8304
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8862
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
|
|
8305
8863
|
function getStyledClassName(namespace) {
|
|
8306
8864
|
return `components-${paramCase(namespace)}`;
|
|
8307
8865
|
}
|
|
8308
8866
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
8309
8867
|
//#endregion
|
|
8310
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8868
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/context-connect.mjs
|
|
8311
8869
|
function contextConnect(Component, namespace) {
|
|
8312
8870
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
8313
8871
|
}
|
|
@@ -8324,7 +8882,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
8324
8882
|
});
|
|
8325
8883
|
}
|
|
8326
8884
|
//#endregion
|
|
8327
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8885
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/utils.mjs
|
|
8328
8886
|
function getNamespace(componentName) {
|
|
8329
8887
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
8330
8888
|
}
|
|
@@ -8332,7 +8890,7 @@ function getConnectedNamespace() {
|
|
|
8332
8890
|
return { [CONNECTED_NAMESPACE]: true };
|
|
8333
8891
|
}
|
|
8334
8892
|
//#endregion
|
|
8335
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8893
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
|
|
8336
8894
|
function useContextSystem(props, namespace) {
|
|
8337
8895
|
const contextSystemProps = useComponentsContext();
|
|
8338
8896
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -8352,7 +8910,7 @@ function useContextSystem(props, namespace) {
|
|
|
8352
8910
|
return finalComponentProps;
|
|
8353
8911
|
}
|
|
8354
8912
|
//#endregion
|
|
8355
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8913
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
|
|
8356
8914
|
var visuallyHidden = {
|
|
8357
8915
|
border: 0,
|
|
8358
8916
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -8368,7 +8926,7 @@ var visuallyHidden = {
|
|
|
8368
8926
|
wordBreak: "normal"
|
|
8369
8927
|
};
|
|
8370
8928
|
//#endregion
|
|
8371
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8929
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
|
|
8372
8930
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
8373
8931
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
8374
8932
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -8450,14 +9008,15 @@ function filterIntrinsicElementProps(props, element) {
|
|
|
8450
9008
|
}
|
|
8451
9009
|
function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
8452
9010
|
const Element = as || "div";
|
|
9011
|
+
const forwardedProps = typeof Element === "string" ? filterIntrinsicElementProps(props, Element) : props;
|
|
8453
9012
|
return /* @__PURE__ */ jsx(Element, {
|
|
8454
9013
|
ref,
|
|
8455
|
-
...
|
|
9014
|
+
...forwardedProps
|
|
8456
9015
|
});
|
|
8457
9016
|
}
|
|
8458
9017
|
var PolymorphicElement = forwardRef$1(UnforwardedPolymorphicElement);
|
|
8459
9018
|
//#endregion
|
|
8460
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9019
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/view/component.mjs
|
|
8461
9020
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
8462
9021
|
return /* @__PURE__ */ jsx(PolymorphicElement, {
|
|
8463
9022
|
ref,
|
|
@@ -8466,7 +9025,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
8466
9025
|
}
|
|
8467
9026
|
var component_default$2 = Object.assign(forwardRef$1(UnforwardedView), { selector: ".components-view" });
|
|
8468
9027
|
//#endregion
|
|
8469
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9028
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
|
|
8470
9029
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
8471
9030
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
8472
9031
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -8481,7 +9040,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
8481
9040
|
}
|
|
8482
9041
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
8483
9042
|
//#endregion
|
|
8484
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9043
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
|
|
8485
9044
|
var breakpoints = [
|
|
8486
9045
|
"40em",
|
|
8487
9046
|
"52em",
|
|
@@ -8515,7 +9074,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
8515
9074
|
return array[index >= array.length ? array.length - 1 : index];
|
|
8516
9075
|
}
|
|
8517
9076
|
//#endregion
|
|
8518
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9077
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/grid/utils.mjs
|
|
8519
9078
|
var ALIGNMENTS = {
|
|
8520
9079
|
bottom: {
|
|
8521
9080
|
alignItems: "flex-end",
|
|
@@ -8563,7 +9122,7 @@ function getAlignmentProps(alignment) {
|
|
|
8563
9122
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
8564
9123
|
}
|
|
8565
9124
|
//#endregion
|
|
8566
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9125
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/grid/hook.mjs
|
|
8567
9126
|
function useGrid(props) {
|
|
8568
9127
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
8569
9128
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -8584,7 +9143,7 @@ function useGrid(props) {
|
|
|
8584
9143
|
justifyContent: justify,
|
|
8585
9144
|
verticalAlign: isInline ? "middle" : void 0,
|
|
8586
9145
|
...alignmentProps
|
|
8587
|
-
}, process.env.NODE_ENV === "production" ? "" : ";label:gridClasses;", process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
9146
|
+
}, process.env.NODE_ENV === "production" ? "" : ";label:gridClasses;", process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImhvb2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBNENzQiIsImZpbGUiOiJob29rLnRzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3NzIH0gZnJvbSAnQGVtb3Rpb24vcmVhY3QnO1xuaW1wb3J0IHsgdXNlTWVtbyB9IGZyb20gJ0B3b3JkcHJlc3MvZWxlbWVudCc7XG5pbXBvcnQgdHlwZSB7IFdvcmRQcmVzc0NvbXBvbmVudFByb3BzIH0gZnJvbSAnLi4vY29udGV4dCc7XG5pbXBvcnQgeyB1c2VDb250ZXh0U3lzdGVtIH0gZnJvbSAnLi4vY29udGV4dCc7XG5pbXBvcnQgeyBnZXRBbGlnbm1lbnRQcm9wcyB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgdXNlUmVzcG9uc2l2ZVZhbHVlIH0gZnJvbSAnLi4vdXRpbHMvdXNlLXJlc3BvbnNpdmUtdmFsdWUnO1xuaW1wb3J0IENPTkZJRyBmcm9tICcuLi91dGlscy9jb25maWctdmFsdWVzJztcbmltcG9ydCB7IHVzZUN4IH0gZnJvbSAnLi4vdXRpbHMvaG9va3MvdXNlLWN4JztcbmltcG9ydCB0eXBlIHsgR3JpZFByb3BzIH0gZnJvbSAnLi90eXBlcyc7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVzZUdyaWQoXG5cdHByb3BzOiBXb3JkUHJlc3NDb21wb25lbnRQcm9wczwgR3JpZFByb3BzLCAnZGl2JyA+XG4pIHtcblx0Y29uc3Qge1xuXHRcdGFsaWduLFxuXHRcdGFsaWdubWVudCxcblx0XHRjbGFzc05hbWUsXG5cdFx0Y29sdW1uR2FwLFxuXHRcdGNvbHVtbnMgPSAyLFxuXHRcdGdhcCA9IDMsXG5cdFx0aXNJbmxpbmUgPSBmYWxzZSxcblx0XHRqdXN0aWZ5LFxuXHRcdHJvd0dhcCxcblx0XHRyb3dzLFxuXHRcdHRlbXBsYXRlQ29sdW1ucyxcblx0XHR0ZW1wbGF0ZVJvd3MsXG5cdFx0Li4ub3RoZXJQcm9wc1xuXHR9ID0gdXNlQ29udGV4dFN5c3RlbSggcHJvcHMsICdHcmlkJyApO1xuXG5cdGNvbnN0IGNvbHVtbnNBc0FycmF5ID0gQXJyYXkuaXNBcnJheSggY29sdW1ucyApID8gY29sdW1ucyA6IFsgY29sdW1ucyBdO1xuXHRjb25zdCBjb2x1bW4gPSB1c2VSZXNwb25zaXZlVmFsdWUoIGNvbHVtbnNBc0FycmF5ICk7XG5cdGNvbnN0IHJvd3NBc0FycmF5ID0gQXJyYXkuaXNBcnJheSggcm93cyApID8gcm93cyA6IFsgcm93cyBdO1xuXHRjb25zdCByb3cgPSB1c2VSZXNwb25zaXZlVmFsdWUoIHJvd3NBc0FycmF5ICk7XG5cblx0Y29uc3QgZ3JpZFRlbXBsYXRlQ29sdW1ucyA9XG5cdFx0dGVtcGxhdGVDb2x1bW5zIHx8ICggISEgY29sdW1ucyAmJiBgcmVwZWF0KCAkeyBjb2x1bW4gfSwgMWZyIClgICk7XG5cdGNvbnN0IGdyaWRUZW1wbGF0ZVJvd3MgPVxuXHRcdHRlbXBsYXRlUm93cyB8fCAoICEhIHJvd3MgJiYgYHJlcGVhdCggJHsgcm93IH0sIDFmciApYCApO1xuXG5cdGNvbnN0IGN4ID0gdXNlQ3goKTtcblxuXHRjb25zdCBjbGFzc2VzID0gdXNlTWVtbyggKCkgPT4ge1xuXHRcdGNvbnN0IGFsaWdubWVudFByb3BzID0gZ2V0QWxpZ25tZW50UHJvcHMoIGFsaWdubWVudCApO1xuXG5cdFx0Y29uc3QgZ3JpZENsYXNzZXMgPSBjc3MoIHtcblx0XHRcdGFsaWduSXRlbXM6IGFsaWduLFxuXHRcdFx0ZGlzcGxheTogaXNJbmxpbmUgPyAnaW5saW5lLWdyaWQnIDogJ2dyaWQnLFxuXHRcdFx0Z2FwOiBgY2FsYyggJHsgQ09ORklHLmdyaWRCYXNlIH0gKiAkeyBnYXAgfSApYCxcblx0XHRcdGdyaWRUZW1wbGF0ZUNvbHVtbnM6IGdyaWRUZW1wbGF0ZUNvbHVtbnMgfHwgdW5kZWZpbmVkLFxuXHRcdFx0Z3JpZFRlbXBsYXRlUm93czogZ3JpZFRlbXBsYXRlUm93cyB8fCB1bmRlZmluZWQsXG5cdFx0XHRncmlkUm93R2FwOiByb3dHYXAsXG5cdFx0XHRncmlkQ29sdW1uR2FwOiBjb2x1bW5HYXAsXG5cdFx0XHRqdXN0aWZ5Q29udGVudDoganVzdGlmeSxcblx0XHRcdHZlcnRpY2FsQWxpZ246IGlzSW5saW5lID8gJ21pZGRsZScgOiB1bmRlZmluZWQsXG5cdFx0XHQuLi5hbGlnbm1lbnRQcm9wcyxcblx0XHR9ICk7XG5cblx0XHRyZXR1cm4gY3goIGdyaWRDbGFzc2VzLCBjbGFzc05hbWUgKTtcblx0fSwgW1xuXHRcdGFsaWduLFxuXHRcdGFsaWdubWVudCxcblx0XHRjbGFzc05hbWUsXG5cdFx0Y29sdW1uR2FwLFxuXHRcdGN4LFxuXHRcdGdhcCxcblx0XHRncmlkVGVtcGxhdGVDb2x1bW5zLFxuXHRcdGdyaWRUZW1wbGF0ZVJvd3MsXG5cdFx0aXNJbmxpbmUsXG5cdFx0anVzdGlmeSxcblx0XHRyb3dHYXAsXG5cdF0gKTtcblxuXHRyZXR1cm4geyAuLi5vdGhlclByb3BzLCBjbGFzc05hbWU6IGNsYXNzZXMgfTtcbn1cbiJdfQ== */");
|
|
8588
9147
|
return cx(gridClasses, className);
|
|
8589
9148
|
}, [
|
|
8590
9149
|
align,
|
|
@@ -8605,10 +9164,11 @@ function useGrid(props) {
|
|
|
8605
9164
|
};
|
|
8606
9165
|
}
|
|
8607
9166
|
//#endregion
|
|
8608
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9167
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@18.3.31__@types+react_d122c1aea9dc8a45ffffc1d3c2f19116/node_modules/@wordpress/components/build-module/grid/component.mjs
|
|
8609
9168
|
function UnconnectedGrid(props, forwardedRef) {
|
|
9169
|
+
const gridProps = useGrid(props);
|
|
8610
9170
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
8611
|
-
...
|
|
9171
|
+
...gridProps,
|
|
8612
9172
|
ref: forwardedRef
|
|
8613
9173
|
});
|
|
8614
9174
|
}
|
|
@@ -8627,8 +9187,8 @@ const SUBPIXEL_TOLERANCE = .5;
|
|
|
8627
9187
|
* Counts how many leading rows fit inside the content container.
|
|
8628
9188
|
*
|
|
8629
9189
|
* Rows are read from the DOM rather than derived from constants: row height
|
|
8630
|
-
* depends on
|
|
8631
|
-
* as a label, so any restated number would drift.
|
|
9190
|
+
* depends on `--a8c-charts-dimension-leaderboard-row-gap`, label wrapping, and
|
|
9191
|
+
* whatever a caller renders as a label, so any restated number would drift.
|
|
8632
9192
|
*
|
|
8633
9193
|
* Every row is a direct grid child marked with `data-row-index`; interactive rows
|
|
8634
9194
|
* use a button wrapper and non-interactive rows use a div wrapper.
|
|
@@ -8713,14 +9273,13 @@ function useFittedRowCount(enabled, rowCount, data) {
|
|
|
8713
9273
|
* @return Array of legend items for the leaderboard chart
|
|
8714
9274
|
*/
|
|
8715
9275
|
function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withComparison = false, withOverlayLabel = false, legendLabels }) {
|
|
8716
|
-
const { leaderboardChart: leaderboardChartSettings } = useGlobalChartsTheme();
|
|
8717
9276
|
const { getElementStyles } = useGlobalChartsContext();
|
|
8718
9277
|
return useMemo(() => {
|
|
8719
9278
|
if (!data || data.length === 0) return [];
|
|
8720
9279
|
const items = [];
|
|
8721
9280
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
8722
9281
|
index: 0,
|
|
8723
|
-
overrideColor: primaryColor
|
|
9282
|
+
overrideColor: primaryColor
|
|
8724
9283
|
});
|
|
8725
9284
|
items.push({
|
|
8726
9285
|
label: legendLabels?.primary || __("Current period", "jetpack-charts"),
|
|
@@ -8729,7 +9288,7 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
8729
9288
|
if (withComparison && !withOverlayLabel) {
|
|
8730
9289
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
8731
9290
|
index: 1,
|
|
8732
|
-
overrideColor: secondaryColor
|
|
9291
|
+
overrideColor: secondaryColor
|
|
8733
9292
|
});
|
|
8734
9293
|
items.push({
|
|
8735
9294
|
label: legendLabels?.comparison || __("Previous period", "jetpack-charts"),
|
|
@@ -8743,7 +9302,6 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
8743
9302
|
secondaryColor,
|
|
8744
9303
|
withComparison,
|
|
8745
9304
|
legendLabels,
|
|
8746
|
-
leaderboardChartSettings,
|
|
8747
9305
|
getElementStyles,
|
|
8748
9306
|
withOverlayLabel
|
|
8749
9307
|
]);
|
|
@@ -8757,6 +9315,9 @@ var leaderboard_chart_module_default = {
|
|
|
8757
9315
|
"chevron": "a8ccharts-GovfoW-chevron",
|
|
8758
9316
|
"deltaPlaceholder": "a8ccharts-GovfoW-deltaPlaceholder",
|
|
8759
9317
|
"deltaValue": "a8ccharts-GovfoW-deltaValue",
|
|
9318
|
+
"deltaValue--down": "a8ccharts-GovfoW-deltaValue--down",
|
|
9319
|
+
"deltaValue--neutral": "a8ccharts-GovfoW-deltaValue--neutral",
|
|
9320
|
+
"deltaValue--up": "a8ccharts-GovfoW-deltaValue--up",
|
|
8760
9321
|
"emptyState": "a8ccharts-GovfoW-emptyState",
|
|
8761
9322
|
"fitEmptyState": "a8ccharts-GovfoW-fitEmptyState",
|
|
8762
9323
|
"interactiveRow": "a8ccharts-GovfoW-interactiveRow",
|
|
@@ -8775,6 +9336,14 @@ var leaderboard_chart_module_default = {
|
|
|
8775
9336
|
};
|
|
8776
9337
|
//#endregion
|
|
8777
9338
|
//#region src/charts/leaderboard-chart/leaderboard-chart.tsx
|
|
9339
|
+
const ROW_GAP = "var(--a8c-charts-dimension-leaderboard-row-gap, 12px)";
|
|
9340
|
+
const COLUMN_GAP = "var(--a8c-charts-dimension-leaderboard-column-gap, 4px)";
|
|
9341
|
+
/** Indexed by `Math.sign( delta ) + 1`, so [negative, neutral, positive]. */
|
|
9342
|
+
const DELTA_TREND_CLASS = [
|
|
9343
|
+
"deltaValue--down",
|
|
9344
|
+
"deltaValue--neutral",
|
|
9345
|
+
"deltaValue--up"
|
|
9346
|
+
];
|
|
8778
9347
|
/**
|
|
8779
9348
|
* Default value formatter using formatMetricValue
|
|
8780
9349
|
*
|
|
@@ -8877,15 +9446,15 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
8877
9446
|
...legend.shapeStyles
|
|
8878
9447
|
};
|
|
8879
9448
|
const { legendChildren, nonLegendChildren } = useChartChildren(children, "LeaderboardChart");
|
|
8880
|
-
const { labelSpacing
|
|
9449
|
+
const { labelSpacing } = leaderboardChartSettings;
|
|
8881
9450
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
8882
9451
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
8883
9452
|
index: 0,
|
|
8884
|
-
overrideColor: primaryColor
|
|
9453
|
+
overrideColor: primaryColor
|
|
8885
9454
|
});
|
|
8886
9455
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
8887
9456
|
index: 1,
|
|
8888
|
-
overrideColor: secondaryColor
|
|
9457
|
+
overrideColor: secondaryColor
|
|
8889
9458
|
});
|
|
8890
9459
|
const legendItems = useLeaderboardLegendItems({
|
|
8891
9460
|
data: data || [],
|
|
@@ -8920,15 +9489,17 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
8920
9489
|
withComparison,
|
|
8921
9490
|
withOverlayLabel
|
|
8922
9491
|
]);
|
|
9492
|
+
const isDataValid = Boolean(data && data.length > 0);
|
|
9493
|
+
const chartMetadata = useMemo(() => ({
|
|
9494
|
+
withComparison,
|
|
9495
|
+
withOverlayLabel
|
|
9496
|
+
}), [withComparison, withOverlayLabel]);
|
|
8923
9497
|
useChartRegistration({
|
|
8924
9498
|
chartId,
|
|
8925
9499
|
legendItems,
|
|
8926
9500
|
chartType: "leaderboard",
|
|
8927
|
-
isDataValid
|
|
8928
|
-
metadata:
|
|
8929
|
-
withComparison,
|
|
8930
|
-
withOverlayLabel
|
|
8931
|
-
}), [withComparison, withOverlayLabel])
|
|
9501
|
+
isDataValid,
|
|
9502
|
+
metadata: chartMetadata
|
|
8932
9503
|
});
|
|
8933
9504
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
8934
9505
|
const { contentRef, fittedCount, isMeasurable } = useFittedRowCount(fitRows && !allSeriesHidden, data?.length ?? 0, data);
|
|
@@ -8939,7 +9510,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
8939
9510
|
legendPosition,
|
|
8940
9511
|
legendElement: false,
|
|
8941
9512
|
legendChildren,
|
|
8942
|
-
className: clsx(leaderboard_chart_module_default.leaderboardChart, {
|
|
9513
|
+
className: clsx("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
8943
9514
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
8944
9515
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
8945
9516
|
}, className),
|
|
@@ -8974,7 +9545,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
8974
9545
|
legendPosition,
|
|
8975
9546
|
legendElement,
|
|
8976
9547
|
legendChildren,
|
|
8977
|
-
className: clsx(leaderboard_chart_module_default.leaderboardChart, {
|
|
9548
|
+
className: clsx("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
8978
9549
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
8979
9550
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
8980
9551
|
}, className),
|
|
@@ -8996,8 +9567,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
8996
9567
|
children: getAllHiddenMessage(legendInteractive, "series")
|
|
8997
9568
|
}) : /* @__PURE__ */ jsx(component_default, {
|
|
8998
9569
|
templateColumns: "minmax(0, 1fr) auto",
|
|
8999
|
-
rowGap,
|
|
9000
|
-
columnGap,
|
|
9570
|
+
rowGap: ROW_GAP,
|
|
9571
|
+
columnGap: COLUMN_GAP,
|
|
9001
9572
|
"data-leaderboard-grid": true,
|
|
9002
9573
|
children: data.map((entry, rowIndex) => {
|
|
9003
9574
|
const rowStyle = shouldFitRows && rowIndex >= fittedCount ? { visibility: "hidden" } : void 0;
|
|
@@ -9006,8 +9577,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9006
9577
|
const hasDelta = hasDeltaValue(entry);
|
|
9007
9578
|
const showComparisonValue = showComparisonColumn && hasDelta;
|
|
9008
9579
|
const showComparisonPlaceholder = showComparisonColumn && !hasDelta;
|
|
9009
|
-
const
|
|
9010
|
-
const deltaColor = deltaColors[colorIndex];
|
|
9580
|
+
const deltaTrendClass = leaderboard_chart_module_default[DELTA_TREND_CLASS[showComparisonValue ? Math.sign(entry.delta) + 1 : 1]];
|
|
9011
9581
|
const rowCells = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Stack, {
|
|
9012
9582
|
direction: "column",
|
|
9013
9583
|
gap: labelSpacing,
|
|
@@ -9028,13 +9598,11 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9028
9598
|
children: [
|
|
9029
9599
|
isPrimaryVisible && /* @__PURE__ */ jsx(Text$1, { children: valueFormatter(entry.currentValue) }),
|
|
9030
9600
|
showComparisonValue && /* @__PURE__ */ jsx(Text$1, {
|
|
9031
|
-
className: leaderboard_chart_module_default.deltaValue,
|
|
9032
|
-
style: { color: deltaColor },
|
|
9601
|
+
className: clsx(leaderboard_chart_module_default.deltaValue, deltaTrendClass),
|
|
9033
9602
|
children: deltaFormatter(entry.delta)
|
|
9034
9603
|
}),
|
|
9035
9604
|
showComparisonPlaceholder && /* @__PURE__ */ jsxs(Text$1, {
|
|
9036
|
-
className: clsx(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder),
|
|
9037
|
-
style: { color: deltaColor },
|
|
9605
|
+
className: clsx(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder, deltaTrendClass),
|
|
9038
9606
|
children: [/* @__PURE__ */ jsx("span", {
|
|
9039
9607
|
"aria-hidden": "true",
|
|
9040
9608
|
children: "—"
|
|
@@ -9118,7 +9686,9 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
|
|
|
9118
9686
|
//#endregion
|
|
9119
9687
|
//#region src/charts/pie-chart/pie-chart.module.scss
|
|
9120
9688
|
var pie_chart_module_default = {
|
|
9121
|
-
"pie-
|
|
9689
|
+
"pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
|
|
9690
|
+
"pie-chart__label-text": "a8ccharts-gnszbG-pie-chart__label-text",
|
|
9691
|
+
"pie-chart__plot": "a8ccharts-gnszbG-pie-chart__plot",
|
|
9122
9692
|
"pie-chart--responsive": "a8ccharts-gnszbG-pie-chart--responsive"
|
|
9123
9693
|
};
|
|
9124
9694
|
//#endregion
|
|
@@ -9173,18 +9743,16 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9173
9743
|
const providerTheme = useGlobalChartsTheme();
|
|
9174
9744
|
const chartId = useChartId(providedChartId);
|
|
9175
9745
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = useTooltip();
|
|
9176
|
-
const
|
|
9177
|
-
|
|
9178
|
-
scroll: true,
|
|
9179
|
-
debounce: 0
|
|
9180
|
-
});
|
|
9746
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
9747
|
+
const containerRef = useRef(null);
|
|
9181
9748
|
const onMouseLeave = useCallback(() => {
|
|
9182
9749
|
if (!withTooltips) return;
|
|
9183
9750
|
hideTooltip();
|
|
9184
9751
|
}, [withTooltips, hideTooltip]);
|
|
9185
9752
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
9753
|
+
const dataWithPercentages = useDataWithPercentages(data);
|
|
9186
9754
|
const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
|
|
9187
|
-
data:
|
|
9755
|
+
data: dataWithPercentages,
|
|
9188
9756
|
chartId,
|
|
9189
9757
|
isSeriesVisible
|
|
9190
9758
|
});
|
|
@@ -9194,20 +9762,21 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9194
9762
|
}), [legendValueDisplay]));
|
|
9195
9763
|
const { isValid, message } = validateData$1(data);
|
|
9196
9764
|
const { svgChildren, htmlChildren, legendChildren, otherChildren } = useChartChildren(children, "PieChart");
|
|
9765
|
+
const chartMetadata = useMemo(() => ({
|
|
9766
|
+
thickness,
|
|
9767
|
+
gapScale,
|
|
9768
|
+
cornerScale
|
|
9769
|
+
}), [
|
|
9770
|
+
thickness,
|
|
9771
|
+
gapScale,
|
|
9772
|
+
cornerScale
|
|
9773
|
+
]);
|
|
9197
9774
|
useChartRegistration({
|
|
9198
9775
|
chartId,
|
|
9199
9776
|
legendItems,
|
|
9200
9777
|
chartType: "pie",
|
|
9201
9778
|
isDataValid: isValid,
|
|
9202
|
-
metadata:
|
|
9203
|
-
thickness,
|
|
9204
|
-
gapScale,
|
|
9205
|
-
cornerScale
|
|
9206
|
-
}), [
|
|
9207
|
-
thickness,
|
|
9208
|
-
gapScale,
|
|
9209
|
-
cornerScale
|
|
9210
|
-
])
|
|
9779
|
+
metadata: chartMetadata
|
|
9211
9780
|
});
|
|
9212
9781
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
9213
9782
|
if (!isValid) return /* @__PURE__ */ jsx("div", {
|
|
@@ -9258,19 +9827,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9258
9827
|
width: propWidth || void 0,
|
|
9259
9828
|
height: propHeight || void 0
|
|
9260
9829
|
},
|
|
9261
|
-
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9262
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(TooltipInPortal, {
|
|
9263
|
-
top: tooltipTop || 0,
|
|
9264
|
-
left: tooltipLeft || 0,
|
|
9265
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
9266
|
-
className: "a8c-charts-scope",
|
|
9267
|
-
role: "tooltip",
|
|
9268
|
-
children: renderTooltip({ tooltipData })
|
|
9269
|
-
})
|
|
9270
|
-
}),
|
|
9271
|
-
htmlChildren,
|
|
9272
|
-
otherChildren
|
|
9273
|
-
] }),
|
|
9830
|
+
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [htmlChildren, otherChildren] }),
|
|
9274
9831
|
children: ({ contentWidth, contentHeight }) => {
|
|
9275
9832
|
const availableSize = Math.min(contentWidth > 0 ? contentWidth : 300, contentHeight > 0 ? contentHeight : 300);
|
|
9276
9833
|
const actualSize = size ? Math.min(size, availableSize) : availableSize;
|
|
@@ -9283,9 +9840,10 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9283
9840
|
const innerRadius = thickness === 0 ? 0 : outerRadius * (1 - thickness);
|
|
9284
9841
|
const maxCornerRadius = (outerRadius - innerRadius) / 2;
|
|
9285
9842
|
const cornerRadius = cornerScale ? Math.min(cornerScale * outerRadius, maxCornerRadius) : 0;
|
|
9286
|
-
return /* @__PURE__ */
|
|
9843
|
+
return /* @__PURE__ */ jsxs(Center, {
|
|
9287
9844
|
ref: containerRef,
|
|
9288
|
-
|
|
9845
|
+
className: pie_chart_module_default["pie-chart__plot"],
|
|
9846
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
9289
9847
|
viewBox: `0 0 ${width} ${height}`,
|
|
9290
9848
|
preserveAspectRatio: "xMidYMid meet",
|
|
9291
9849
|
width,
|
|
@@ -9317,11 +9875,12 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9317
9875
|
const hasSpaceForLabel = arc.endAngle - arc.startAngle >= .25;
|
|
9318
9876
|
const handleMouseMove = (event) => {
|
|
9319
9877
|
if (!withTooltips) return;
|
|
9320
|
-
|
|
9878
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
9879
|
+
if (!bounds) return;
|
|
9321
9880
|
showTooltip({
|
|
9322
9881
|
tooltipData: arc.data,
|
|
9323
|
-
tooltipLeft: event.clientX -
|
|
9324
|
-
tooltipTop: event.clientY -
|
|
9882
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
9883
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9325
9884
|
});
|
|
9326
9885
|
};
|
|
9327
9886
|
const pathProps = {
|
|
@@ -9336,30 +9895,28 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9336
9895
|
}
|
|
9337
9896
|
const svgLabelSmall = providerTheme.svgLabelSmall;
|
|
9338
9897
|
const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
|
|
9339
|
-
const
|
|
9898
|
+
const backgroundWidth = getStringWidth$1(arc.data.label, {
|
|
9340
9899
|
fontSize,
|
|
9341
9900
|
fontFamily: svgLabelSmall?.fontFamily,
|
|
9342
9901
|
fontWeight: svgLabelSmall?.fontWeight
|
|
9343
|
-
});
|
|
9344
|
-
const
|
|
9345
|
-
const backgroundWidth = estimatedTextWidth + labelPadding * 2;
|
|
9346
|
-
const backgroundHeight = fontSize + labelPadding * 2;
|
|
9902
|
+
}) + 12;
|
|
9903
|
+
const backgroundHeight = fontSize + 12;
|
|
9347
9904
|
return /* @__PURE__ */ jsxs("g", {
|
|
9348
9905
|
...groupProps,
|
|
9349
|
-
children: [/* @__PURE__ */ jsx("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ jsxs("g", { children: [
|
|
9906
|
+
children: [/* @__PURE__ */ jsx("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("rect", {
|
|
9907
|
+
className: pie_chart_module_default["pie-chart__label-plate"],
|
|
9350
9908
|
x: centroidX - backgroundWidth / 2,
|
|
9351
9909
|
y: centroidY - backgroundHeight / 2,
|
|
9352
9910
|
width: backgroundWidth,
|
|
9353
9911
|
height: backgroundHeight,
|
|
9354
|
-
fill: providerTheme.labelBackgroundColor,
|
|
9355
9912
|
rx: 4,
|
|
9356
9913
|
ry: 4,
|
|
9357
9914
|
pointerEvents: "none"
|
|
9358
9915
|
}), /* @__PURE__ */ jsx("text", {
|
|
9916
|
+
className: pie_chart_module_default["pie-chart__label-text"],
|
|
9359
9917
|
x: centroidX,
|
|
9360
9918
|
y: centroidY,
|
|
9361
9919
|
dy: ".33em",
|
|
9362
|
-
fill: providerTheme.labelTextColor || "#333",
|
|
9363
9920
|
fontSize,
|
|
9364
9921
|
textAnchor: "middle",
|
|
9365
9922
|
pointerEvents: "none",
|
|
@@ -9370,7 +9927,15 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9370
9927
|
}
|
|
9371
9928
|
}), !allSegmentsHidden && svgChildren]
|
|
9372
9929
|
})]
|
|
9373
|
-
})
|
|
9930
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
9931
|
+
top: tooltipTop || 0,
|
|
9932
|
+
left: tooltipLeft || 0,
|
|
9933
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
9934
|
+
className: standaloneScopeClass,
|
|
9935
|
+
role: "tooltip",
|
|
9936
|
+
children: renderTooltip({ tooltipData })
|
|
9937
|
+
})
|
|
9938
|
+
})]
|
|
9374
9939
|
});
|
|
9375
9940
|
}
|
|
9376
9941
|
})
|
|
@@ -9397,6 +9962,7 @@ var pie_semi_circle_chart_module_default = {
|
|
|
9397
9962
|
"label": "a8ccharts-YtTOxW-label",
|
|
9398
9963
|
"note": "a8ccharts-YtTOxW-note",
|
|
9399
9964
|
"pie-semi-circle-chart": "a8ccharts-YtTOxW-pie-semi-circle-chart",
|
|
9965
|
+
"pie-semi-circle-chart__plot": "a8ccharts-YtTOxW-pie-semi-circle-chart__plot",
|
|
9400
9966
|
"pie-semi-circle-chart--responsive": "a8ccharts-YtTOxW-pie-semi-circle-chart--responsive"
|
|
9401
9967
|
};
|
|
9402
9968
|
//#endregion
|
|
@@ -9446,23 +10012,17 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9446
10012
|
const legendPosition = legend.position ?? "bottom";
|
|
9447
10013
|
const chartId = useChartId(providedChartId);
|
|
9448
10014
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = useTooltip();
|
|
9449
|
-
const
|
|
9450
|
-
|
|
9451
|
-
scroll: true,
|
|
9452
|
-
debounce: 0
|
|
9453
|
-
});
|
|
10015
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
10016
|
+
const containerRef = useRef(null);
|
|
9454
10017
|
const handleMouseMove = useCallback((event, arc) => {
|
|
9455
|
-
|
|
10018
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
10019
|
+
if (!bounds) return;
|
|
9456
10020
|
showTooltip({
|
|
9457
10021
|
tooltipData: arc.data,
|
|
9458
|
-
tooltipLeft: event.clientX -
|
|
9459
|
-
tooltipTop: event.clientY -
|
|
10022
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
10023
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9460
10024
|
});
|
|
9461
10025
|
}, [
|
|
9462
|
-
containerBounds.width,
|
|
9463
|
-
containerBounds.height,
|
|
9464
|
-
containerBounds.left,
|
|
9465
|
-
containerBounds.top,
|
|
9466
10026
|
showTooltip,
|
|
9467
10027
|
tooltipOffsetX,
|
|
9468
10028
|
tooltipOffsetY
|
|
@@ -9475,8 +10035,9 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9475
10035
|
}, [handleMouseMove]);
|
|
9476
10036
|
const { isValid, message } = validateData(data);
|
|
9477
10037
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
10038
|
+
const dataWithPercentages = useDataWithPercentages(data);
|
|
9478
10039
|
const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
|
|
9479
|
-
data:
|
|
10040
|
+
data: dataWithPercentages,
|
|
9480
10041
|
chartId,
|
|
9481
10042
|
isSeriesVisible
|
|
9482
10043
|
});
|
|
@@ -9493,15 +10054,16 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9493
10054
|
legendValueDisplay
|
|
9494
10055
|
}), [legendValueDisplay]));
|
|
9495
10056
|
const { svgChildren, htmlChildren, legendChildren, otherChildren } = useChartChildren(children, "PieSemiCircleChart");
|
|
10057
|
+
const chartMetadata = useMemo(() => ({
|
|
10058
|
+
thickness,
|
|
10059
|
+
clockwise
|
|
10060
|
+
}), [thickness, clockwise]);
|
|
9496
10061
|
useChartRegistration({
|
|
9497
10062
|
chartId,
|
|
9498
10063
|
legendItems,
|
|
9499
10064
|
chartType: "pie-semi-circle",
|
|
9500
10065
|
isDataValid: isValid,
|
|
9501
|
-
metadata:
|
|
9502
|
-
thickness,
|
|
9503
|
-
clockwise
|
|
9504
|
-
}), [thickness, clockwise])
|
|
10066
|
+
metadata: chartMetadata
|
|
9505
10067
|
});
|
|
9506
10068
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
9507
10069
|
const effectiveWidth = propWidth || DEFAULT_WIDTH$1;
|
|
@@ -9509,7 +10071,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9509
10071
|
const errorWidth = propHeight ? Math.min(propWidth || propHeight * 2, propHeight * 2) : effectiveWidth;
|
|
9510
10072
|
const errorHeight = errorWidth / 2;
|
|
9511
10073
|
return /* @__PURE__ */ jsx("div", {
|
|
9512
|
-
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart"],
|
|
10074
|
+
className: clsx("pie-semi-circle-chart", pie_semi_circle_chart_module_default["pie-semi-circle-chart"], className),
|
|
9513
10075
|
children: /* @__PURE__ */ jsx("svg", {
|
|
9514
10076
|
width: errorWidth,
|
|
9515
10077
|
height: errorHeight,
|
|
@@ -9556,19 +10118,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9556
10118
|
width: propWidth || void 0,
|
|
9557
10119
|
height: propHeight || void 0
|
|
9558
10120
|
},
|
|
9559
|
-
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
9560
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(TooltipInPortal, {
|
|
9561
|
-
top: tooltipTop || 0,
|
|
9562
|
-
left: tooltipLeft || 0,
|
|
9563
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
9564
|
-
className: "a8c-charts-scope",
|
|
9565
|
-
role: "tooltip",
|
|
9566
|
-
children: renderTooltip({ tooltipData })
|
|
9567
|
-
})
|
|
9568
|
-
}),
|
|
9569
|
-
htmlChildren,
|
|
9570
|
-
otherChildren
|
|
9571
|
-
] }),
|
|
10121
|
+
trailingContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [htmlChildren, otherChildren] }),
|
|
9572
10122
|
children: ({ contentWidth, contentHeight }) => {
|
|
9573
10123
|
const availableWidth = contentWidth > 0 ? contentWidth : effectiveWidth;
|
|
9574
10124
|
const availableHeight = contentHeight > 0 ? contentHeight : propHeight || effectiveWidth / 2;
|
|
@@ -9576,9 +10126,10 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9576
10126
|
const height = width / 2;
|
|
9577
10127
|
const radius = height;
|
|
9578
10128
|
const innerRadius = radius * (1 - thickness);
|
|
9579
|
-
return /* @__PURE__ */
|
|
10129
|
+
return /* @__PURE__ */ jsxs(Center, {
|
|
9580
10130
|
ref: containerRef,
|
|
9581
|
-
|
|
10131
|
+
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart__plot"],
|
|
10132
|
+
children: [/* @__PURE__ */ jsxs("svg", {
|
|
9582
10133
|
width,
|
|
9583
10134
|
height,
|
|
9584
10135
|
viewBox: `0 0 ${width} ${height}`,
|
|
@@ -9636,7 +10187,15 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9636
10187
|
!allSegmentsHidden && svgChildren
|
|
9637
10188
|
] })
|
|
9638
10189
|
})]
|
|
9639
|
-
})
|
|
10190
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ jsx(BoundedTooltip, {
|
|
10191
|
+
top: tooltipTop || 0,
|
|
10192
|
+
left: tooltipLeft || 0,
|
|
10193
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
10194
|
+
className: standaloneScopeClass,
|
|
10195
|
+
role: "tooltip",
|
|
10196
|
+
children: renderTooltip({ tooltipData })
|
|
10197
|
+
})
|
|
10198
|
+
})]
|
|
9640
10199
|
});
|
|
9641
10200
|
}
|
|
9642
10201
|
})
|
|
@@ -9692,6 +10251,7 @@ const transformToSeriesData = (data, color, strokeWidth) => {
|
|
|
9692
10251
|
};
|
|
9693
10252
|
const SparklineComponent = forwardRef(({ data, width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, color, strokeWidth: strokeWidthProp, withGradientFill = true, gradient, className, chartId, margin: marginProp, animation }, ref) => {
|
|
9694
10253
|
const theme = useGlobalChartsTheme();
|
|
10254
|
+
const chartsContext = useContext(GlobalChartsContext);
|
|
9695
10255
|
const themeStrokeWidth = theme.sparkline?.strokeWidth ?? 1.5;
|
|
9696
10256
|
const strokeWidth = strokeWidthProp ?? themeStrokeWidth;
|
|
9697
10257
|
const seriesData = useMemo(() => {
|
|
@@ -9745,7 +10305,7 @@ const SparklineComponent = forwardRef(({ data, width = DEFAULT_WIDTH, height = D
|
|
|
9745
10305
|
if (data.length === 1) {
|
|
9746
10306
|
const cx = width / 2;
|
|
9747
10307
|
const cy = height / 2;
|
|
9748
|
-
const resolvedColor = color || "#000000";
|
|
10308
|
+
const resolvedColor = color || chartsContext?.getElementStyles({ index: 0 }).color || "#000000";
|
|
9749
10309
|
return /* @__PURE__ */ jsx("div", {
|
|
9750
10310
|
ref,
|
|
9751
10311
|
className: clsx("sparkline", sparkline_module_default.sparkline, sparkline_module_default["sparkline--single-point"], className),
|
|
@@ -9848,8 +10408,9 @@ const Icon$1 = ({ direction }) => {
|
|
|
9848
10408
|
*/
|
|
9849
10409
|
function TrendIndicator({ direction, value, className, style, showIcon = true }) {
|
|
9850
10410
|
const ariaLabel = `${DIRECTION_LABELS[direction]}: ${value}`;
|
|
10411
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
9851
10412
|
return /* @__PURE__ */ jsxs("span", {
|
|
9852
|
-
className: clsx(
|
|
10413
|
+
className: clsx(standaloneScopeClass, trend_indicator_module_default["trend-indicator"], trend_indicator_module_default[`trend-indicator--${direction}`], className),
|
|
9853
10414
|
style,
|
|
9854
10415
|
"aria-label": ariaLabel,
|
|
9855
10416
|
children: [showIcon && /* @__PURE__ */ jsx(Icon$1, { direction }), /* @__PURE__ */ jsx("span", {
|
|
@@ -9859,6 +10420,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
|
|
|
9859
10420
|
});
|
|
9860
10421
|
}
|
|
9861
10422
|
//#endregion
|
|
9862
|
-
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString,
|
|
10423
|
+
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
|
|
9863
10424
|
|
|
9864
10425
|
//# sourceMappingURL=index.js.map
|