@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.cjs
CHANGED
|
@@ -17,7 +17,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
}
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
21
21
|
value: mod,
|
|
22
22
|
enumerable: true
|
|
23
23
|
}) : target, mod));
|
|
@@ -28,7 +28,7 @@ let _wordpress_i18n = require("@wordpress/i18n");
|
|
|
28
28
|
let clsx = require("clsx");
|
|
29
29
|
clsx = __toESM(clsx, 1);
|
|
30
30
|
let react = require("react");
|
|
31
|
-
react = __toESM(react
|
|
31
|
+
react = __toESM(react);
|
|
32
32
|
let _visx_vendor_d3_color = require("@visx/vendor/d3-color");
|
|
33
33
|
let date_fns = require("date-fns");
|
|
34
34
|
let _visx_text = require("@visx/text");
|
|
@@ -40,6 +40,7 @@ let _visx_scale = require("@visx/scale");
|
|
|
40
40
|
let _visx_group = require("@visx/group");
|
|
41
41
|
let _visx_legend = require("@visx/legend");
|
|
42
42
|
let _wordpress_ui = require("@wordpress/ui");
|
|
43
|
+
let react_dom = require("react-dom");
|
|
43
44
|
let _visx_gradient = require("@visx/gradient");
|
|
44
45
|
let _visx_curve = require("@visx/curve");
|
|
45
46
|
let _visx_responsive = require("@visx/responsive");
|
|
@@ -174,6 +175,39 @@ const parseAsLocalDate = (dateString) => {
|
|
|
174
175
|
return /* @__PURE__ */ new Date(NaN);
|
|
175
176
|
};
|
|
176
177
|
//#endregion
|
|
178
|
+
//#region src/utils/bucket-info.ts
|
|
179
|
+
const getInstant = (point) => {
|
|
180
|
+
if (!point) return;
|
|
181
|
+
if ("date" in point && point.date) return point.date.getTime();
|
|
182
|
+
if ("dateString" in point && point.dateString) return parseAsLocalDate(point.dateString).getTime();
|
|
183
|
+
};
|
|
184
|
+
const getPointSpacingInHours = (data) => {
|
|
185
|
+
return data.reduce((spacing, datom) => {
|
|
186
|
+
const instants = [...new Set(datom.data.map((point) => getInstant(point)))].filter((time) => time !== void 0 && Number.isFinite(time)).sort((a, b) => a - b);
|
|
187
|
+
return instants.reduce((seriesSpacing, time, index) => index === 0 ? seriesSpacing : Math.min(seriesSpacing, Math.abs((0, date_fns.differenceInHours)(time, instants[index - 1]))), spacing);
|
|
188
|
+
}, Number.POSITIVE_INFINITY);
|
|
189
|
+
};
|
|
190
|
+
const SUB_DAILY_SPACING_HOURS = 23;
|
|
191
|
+
const MONTHLY_SPACING_HOURS = 672;
|
|
192
|
+
const getBucketResolution = (data, tickResolution) => {
|
|
193
|
+
if (tickResolution) return tickResolution === "week" ? "day" : tickResolution;
|
|
194
|
+
const spacingInHours = getPointSpacingInHours(data);
|
|
195
|
+
if (spacingInHours < SUB_DAILY_SPACING_HOURS) return "hour";
|
|
196
|
+
if (!Number.isFinite(spacingInHours) || spacingInHours < MONTHLY_SPACING_HOURS) return "day";
|
|
197
|
+
return spacingInHours < 12 * MONTHLY_SPACING_HOURS ? "month" : "year";
|
|
198
|
+
};
|
|
199
|
+
/**
|
|
200
|
+
* How this data was classified, for consumers that render their own labels.
|
|
201
|
+
*
|
|
202
|
+
* @param data - The series the chart draws, in any order, dated by `date` or `dateString`.
|
|
203
|
+
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
204
|
+
* @return The declared or inferred bucket, and the resolution formats key on.
|
|
205
|
+
*/
|
|
206
|
+
const getBucketInfo = (data, tickResolution) => ({
|
|
207
|
+
bucket: tickResolution ?? getBucketResolution(data),
|
|
208
|
+
displayResolution: getBucketResolution(data, tickResolution)
|
|
209
|
+
});
|
|
210
|
+
//#endregion
|
|
177
211
|
//#region src/utils/format-metric-value.ts
|
|
178
212
|
/**
|
|
179
213
|
* Format a numeric metric value based on type, precision and scale.
|
|
@@ -252,7 +286,8 @@ const formatPercentage = (value) => {
|
|
|
252
286
|
*/
|
|
253
287
|
const getLongestTickWidth = (ticks, formatTick, labelStyle) => {
|
|
254
288
|
const formattedTicks = ticks.map((tick) => formatTick(tick, 0, []));
|
|
255
|
-
|
|
289
|
+
const longestTick = formattedTicks.reduce((longest, current) => longest.length >= current.length ? longest : current, formattedTicks[0]);
|
|
290
|
+
return (0, _visx_text.getStringWidth)(longestTick, labelStyle);
|
|
256
291
|
};
|
|
257
292
|
//#endregion
|
|
258
293
|
//#region src/utils/get-styles.ts
|
|
@@ -385,20 +420,6 @@ const parseHslString = (hslString) => {
|
|
|
385
420
|
];
|
|
386
421
|
};
|
|
387
422
|
/**
|
|
388
|
-
* Parse an RGB string like 'rgb(255, 0, 0)' into a hex color.
|
|
389
|
-
*
|
|
390
|
-
* @deprecated Use normalizeColorToHex() instead, which handles all color formats including rgb() and rgba().
|
|
391
|
-
* @param rgbString - RGB color string (not RGBA)
|
|
392
|
-
* @return hex color string or null if invalid
|
|
393
|
-
*/
|
|
394
|
-
const parseRgbString = (rgbString) => {
|
|
395
|
-
const lower = rgbString.toLowerCase().trim();
|
|
396
|
-
if (!lower.startsWith("rgb(") || lower.startsWith("rgba(")) return null;
|
|
397
|
-
const parsed = (0, _visx_vendor_d3_color.color)(lower);
|
|
398
|
-
if (!parsed) return null;
|
|
399
|
-
return parsed.formatHex();
|
|
400
|
-
};
|
|
401
|
-
/**
|
|
402
423
|
* Normalize any CSS color value to a hex color string.
|
|
403
424
|
* Handles hex, HSL, HSLA, RGB, RGBA, named CSS colors, and CSS variables.
|
|
404
425
|
*
|
|
@@ -626,6 +647,112 @@ const resolveFontSize = (val) => {
|
|
|
626
647
|
}
|
|
627
648
|
};
|
|
628
649
|
//#endregion
|
|
650
|
+
//#region src/utils/date-formatting.ts
|
|
651
|
+
const formatters = /* @__PURE__ */ new Map();
|
|
652
|
+
const getFormatter$1 = (options, { locale, timeZone }) => {
|
|
653
|
+
const key = `${locale ?? ""}|${timeZone ?? ""}|${JSON.stringify(options)}`;
|
|
654
|
+
let formatter = formatters.get(key);
|
|
655
|
+
if (!formatter) {
|
|
656
|
+
formatter = new Intl.DateTimeFormat(locale, {
|
|
657
|
+
...options,
|
|
658
|
+
timeZone
|
|
659
|
+
});
|
|
660
|
+
formatters.set(key, formatter);
|
|
661
|
+
}
|
|
662
|
+
return formatter;
|
|
663
|
+
};
|
|
664
|
+
const warned = /* @__PURE__ */ new Set();
|
|
665
|
+
const warnOnce = (key, message) => {
|
|
666
|
+
if (warned.has(key) || process.env.NODE_ENV === "production") return;
|
|
667
|
+
warned.add(key);
|
|
668
|
+
console.warn(`[Charts] ${message}`);
|
|
669
|
+
};
|
|
670
|
+
const isUsable = (formatting) => {
|
|
671
|
+
try {
|
|
672
|
+
Intl.DateTimeFormat(formatting.locale, { timeZone: formatting.timeZone });
|
|
673
|
+
return true;
|
|
674
|
+
} catch {
|
|
675
|
+
return false;
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
const toBcp47 = (locale) => locale?.replace(/_/g, "-");
|
|
679
|
+
/**
|
|
680
|
+
* Repairs a host locale for `Intl`, dropping either half it still cannot use.
|
|
681
|
+
*
|
|
682
|
+
* Every formatter below is built during render, so an unusable string would throw
|
|
683
|
+
* where React unmounts the whole host tree rather than one chart. WordPress hands
|
|
684
|
+
* out the likeliest one either way: `timezone_string` is `''` on a site set to a
|
|
685
|
+
* raw UTC offset, and has no repair.
|
|
686
|
+
*
|
|
687
|
+
* @param formatting - Locale and time zone as the host supplied them.
|
|
688
|
+
* @return The usable halves, each `undefined` where the host's value was not.
|
|
689
|
+
*/
|
|
690
|
+
const sanitizeFormatting = (formatting) => {
|
|
691
|
+
const repaired = {
|
|
692
|
+
...formatting,
|
|
693
|
+
locale: toBcp47(formatting.locale)
|
|
694
|
+
};
|
|
695
|
+
if (isUsable(repaired)) return repaired;
|
|
696
|
+
const locale = isUsable({ locale: repaired.locale }) ? repaired.locale : void 0;
|
|
697
|
+
const timeZone = isUsable({ timeZone: repaired.timeZone }) ? repaired.timeZone : void 0;
|
|
698
|
+
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.`);
|
|
699
|
+
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".`);
|
|
700
|
+
return {
|
|
701
|
+
locale,
|
|
702
|
+
timeZone
|
|
703
|
+
};
|
|
704
|
+
};
|
|
705
|
+
/**
|
|
706
|
+
* A date formatter bound to the host's locale and time zone.
|
|
707
|
+
*
|
|
708
|
+
* @param options - Date-part options, as for `Intl.DateTimeFormat`.
|
|
709
|
+
* @param formatting - Host locale and time zone; either half absent leaves the runtime's own.
|
|
710
|
+
* @return Formatter taking a timestamp or a `Date`.
|
|
711
|
+
*/
|
|
712
|
+
const createDateFormatter = (options, formatting) => {
|
|
713
|
+
return (value) => {
|
|
714
|
+
if (!Number.isFinite(Number(value))) return new Date(Number(value)).toLocaleDateString();
|
|
715
|
+
return getFormatter$1(options, formatting).format(value);
|
|
716
|
+
};
|
|
717
|
+
};
|
|
718
|
+
const CLOCK_OPTIONS = {
|
|
719
|
+
month: "numeric",
|
|
720
|
+
hour: "numeric",
|
|
721
|
+
hourCycle: "h23"
|
|
722
|
+
};
|
|
723
|
+
const NO_FIELDS = {
|
|
724
|
+
month: NaN,
|
|
725
|
+
hour: NaN
|
|
726
|
+
};
|
|
727
|
+
/**
|
|
728
|
+
* A clock reading calendar fields in the host's time zone.
|
|
729
|
+
*
|
|
730
|
+
* `Date`'s own getters read the browser's zone, so a chart viewed from another
|
|
731
|
+
* country anchors its ticks to the wrong midnights and the wrong January
|
|
732
|
+
* without this.
|
|
733
|
+
*
|
|
734
|
+
* @param timeZone - IANA zone name; absent leaves the runtime's own.
|
|
735
|
+
* @return Reader taking a `Date`.
|
|
736
|
+
*/
|
|
737
|
+
const createZonedClock = (timeZone) => {
|
|
738
|
+
if (!timeZone) return (date) => ({
|
|
739
|
+
month: date.getMonth() + 1,
|
|
740
|
+
hour: date.getHours()
|
|
741
|
+
});
|
|
742
|
+
return (date) => {
|
|
743
|
+
if (!Number.isFinite(Number(date))) return NO_FIELDS;
|
|
744
|
+
const parts = getFormatter$1(CLOCK_OPTIONS, {
|
|
745
|
+
locale: "en-US",
|
|
746
|
+
timeZone
|
|
747
|
+
}).formatToParts(date);
|
|
748
|
+
const read = (type) => Number(parts.find((part) => part.type === type)?.value);
|
|
749
|
+
return {
|
|
750
|
+
month: read("month"),
|
|
751
|
+
hour: read("hour")
|
|
752
|
+
};
|
|
753
|
+
};
|
|
754
|
+
};
|
|
755
|
+
//#endregion
|
|
629
756
|
//#region src/providers/chart-scope/chart-scope-context.ts
|
|
630
757
|
/**
|
|
631
758
|
* The nearest chart element, published so JS token resolution reads the same CSS cascade that paints the chart's own colours.
|
|
@@ -762,140 +889,40 @@ const getChartColor = (index, colorCache) => {
|
|
|
762
889
|
const fallbackLightness = BASE_LIGHTNESS + index % LIGHTNESS_VARIATION_STEPS * LIGHTNESS_INCREMENT;
|
|
763
890
|
return (0, _visx_vendor_d3_color.hsl)(Math.round(fallbackHue), fallbackSaturation / 100, fallbackLightness / 100).formatHex();
|
|
764
891
|
};
|
|
765
|
-
//#endregion
|
|
766
|
-
//#region src/providers/chart-context/private/theme-override-vars.ts
|
|
767
|
-
const ROLE_FOR_FIELD = [
|
|
768
|
-
["--a8c-charts-color-background", (theme) => theme.backgroundColor],
|
|
769
|
-
["--a8c-charts-color-grid", (theme) => theme.gridStyles?.stroke],
|
|
770
|
-
["--a8c-charts-color-axis", (theme) => theme.xAxisLineStyles?.stroke],
|
|
771
|
-
["--a8c-charts-color-tick", (theme) => theme.xTickLineStyles?.stroke],
|
|
772
|
-
["--a8c-charts-color-label-axis", (theme) => theme.svgLabelSmall?.fill]
|
|
773
|
-
];
|
|
774
892
|
/**
|
|
775
|
-
* The
|
|
893
|
+
* The catalog role holding one series-palette slot.
|
|
776
894
|
*
|
|
777
|
-
*
|
|
778
|
-
*
|
|
779
|
-
* @param role - The catalog role being overridden.
|
|
780
|
-
* @return The custom property carrying the consumer's value.
|
|
895
|
+
* @param slot - The one-based slot number.
|
|
896
|
+
* @return The role name.
|
|
781
897
|
*/
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
/**
|
|
785
|
-
|
|
786
|
-
*
|
|
787
|
-
* 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`.
|
|
788
|
-
*
|
|
789
|
-
* Three things this has to get right, none of which a plain substring test gets:
|
|
790
|
-
*
|
|
791
|
-
* `var()` permits whitespace after the opening paren, so testing for `var(<role>` misses `var( --a8c-charts-color-grid, … )`.
|
|
792
|
-
*
|
|
793
|
-
* 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.
|
|
794
|
-
*
|
|
795
|
-
* `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.
|
|
796
|
-
*
|
|
797
|
-
* @param value - The consumer's value for the field.
|
|
798
|
-
* @param role - The catalog role this value would override.
|
|
799
|
-
* @return True when the value reads `role`, so it must not be published.
|
|
800
|
-
*/
|
|
801
|
-
const readsOwnRole = (value, role) => value.trim() === role || new RegExp(`var\\(\\s*${role.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(value);
|
|
802
|
-
/**
|
|
803
|
-
* 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.
|
|
804
|
-
*
|
|
805
|
-
* 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.
|
|
806
|
-
*
|
|
807
|
-
* @param theme - The consumer's `theme` prop, before merging with the default theme.
|
|
808
|
-
* @return The wrapper's custom properties, and the roles the consumer overrode.
|
|
809
|
-
*/
|
|
810
|
-
const themeOverrideVars = (theme) => {
|
|
811
|
-
if (!theme) return {
|
|
812
|
-
vars: {},
|
|
813
|
-
roles: []
|
|
814
|
-
};
|
|
815
|
-
const vars = {};
|
|
816
|
-
const roles = [];
|
|
817
|
-
for (const [role, read] of ROLE_FOR_FIELD) {
|
|
818
|
-
const value = read(theme);
|
|
819
|
-
if (typeof value !== "string" || value === "") continue;
|
|
820
|
-
roles.push(role);
|
|
821
|
-
if (!readsOwnRole(value, role)) vars[themeLayerVar(role)] = value;
|
|
822
|
-
}
|
|
823
|
-
return {
|
|
824
|
-
vars,
|
|
825
|
-
roles
|
|
826
|
-
};
|
|
827
|
-
};
|
|
898
|
+
const seriesRole = (slot) => `--a8c-charts-color-series-${slot}`;
|
|
899
|
+
const SERIES_SLOT_1_FALLBACK = "#3858e9";
|
|
900
|
+
/** The catalog pointer for every slot, in slot order. */
|
|
901
|
+
const SERIES_PALETTE_POINTERS = Array.from({ length: 5 }, (_, index) => index === 0 ? `var(${seriesRole(1)}, ${SERIES_SLOT_1_FALLBACK})` : `var(${seriesRole(index + 1)})`);
|
|
828
902
|
//#endregion
|
|
829
903
|
//#region src/providers/chart-context/themes.ts
|
|
830
904
|
/**
|
|
831
|
-
* Default theme configuration
|
|
905
|
+
* Default theme configuration: the shape and spacing a consumer can override.
|
|
906
|
+
*
|
|
907
|
+
* For a color, set the matching `--a8c-charts-color-*` role in CSS instead; the `var()`
|
|
908
|
+
* chains that deliver those live in `private/catalog-pointers.ts`.
|
|
832
909
|
*/
|
|
833
910
|
const defaultTheme = {
|
|
834
|
-
|
|
835
|
-
labelBackgroundColor: "transparent",
|
|
836
|
-
labelTextColor: "var(--a8c-charts-color-label-on-fill, #FFFFFF)",
|
|
837
|
-
colors: [
|
|
838
|
-
"#98C8DF",
|
|
839
|
-
"#006DAB",
|
|
840
|
-
"#A6DC80",
|
|
841
|
-
"#1F9828",
|
|
842
|
-
"#FF8C8F"
|
|
843
|
-
],
|
|
844
|
-
gridStyles: {
|
|
845
|
-
stroke: "var(--a8c-charts-color-grid, #dbdbdb)",
|
|
846
|
-
strokeWidth: 1
|
|
847
|
-
},
|
|
911
|
+
gridStyles: { strokeWidth: 1 },
|
|
848
912
|
tickLength: 4,
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
xTickLineStyles: {
|
|
852
|
-
stroke: "var(--a8c-charts-color-tick, #dbdbdb)",
|
|
853
|
-
strokeWidth: 1
|
|
854
|
-
},
|
|
855
|
-
xAxisLineStyles: {
|
|
856
|
-
stroke: "var(--a8c-charts-color-axis, #dbdbdb)",
|
|
857
|
-
strokeWidth: 1
|
|
858
|
-
},
|
|
913
|
+
xTickLineStyles: { strokeWidth: 1 },
|
|
914
|
+
xAxisLineStyles: { strokeWidth: 1 },
|
|
859
915
|
legend: {
|
|
860
|
-
labelStyles: {
|
|
916
|
+
labelStyles: {},
|
|
861
917
|
containerStyles: {},
|
|
862
918
|
shapeStyles: []
|
|
863
919
|
},
|
|
864
920
|
seriesLineStyles: [],
|
|
865
921
|
glyphs: [],
|
|
866
|
-
svgLabelSmall: {
|
|
867
|
-
fill: "var(--a8c-charts-color-label-axis, #1e1e1e)",
|
|
868
|
-
fontFamily: "inherit"
|
|
869
|
-
},
|
|
922
|
+
svgLabelSmall: { fontFamily: "inherit" },
|
|
870
923
|
svgLabelBig: { fontFamily: "inherit" },
|
|
871
|
-
annotationStyles: {
|
|
872
|
-
|
|
873
|
-
anchorLineStroke: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
874
|
-
backgroundFill: "var(--a8c-charts-color-surface, #fff)"
|
|
875
|
-
},
|
|
876
|
-
connector: { stroke: "var(--a8c-charts-color-annotation, #1e1e1e)" },
|
|
877
|
-
circleSubject: {
|
|
878
|
-
stroke: "transparent",
|
|
879
|
-
fill: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
880
|
-
radius: 5
|
|
881
|
-
}
|
|
882
|
-
},
|
|
883
|
-
geoChart: { featureFillColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)" },
|
|
884
|
-
leaderboardChart: {
|
|
885
|
-
rowGap: 12,
|
|
886
|
-
columnGap: 4,
|
|
887
|
-
labelSpacing: "xs",
|
|
888
|
-
deltaColors: [
|
|
889
|
-
"var(--a8c-charts-color-trend-down, #cc1818)",
|
|
890
|
-
"var(--a8c-charts-color-trend-neutral, #707070)",
|
|
891
|
-
"var(--a8c-charts-color-trend-up, #008030)"
|
|
892
|
-
]
|
|
893
|
-
},
|
|
894
|
-
conversionFunnelChart: {
|
|
895
|
-
backgroundColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
896
|
-
positiveChangeColor: "var(--a8c-charts-color-trend-up, #008030)",
|
|
897
|
-
negativeChangeColor: "var(--a8c-charts-color-trend-down, #cc1818)"
|
|
898
|
-
},
|
|
924
|
+
annotationStyles: {},
|
|
925
|
+
leaderboardChart: { labelSpacing: "xs" },
|
|
899
926
|
lineChart: { lineStyles: { comparison: {
|
|
900
927
|
strokeDasharray: "4 4",
|
|
901
928
|
strokeLinecap: "square"
|
|
@@ -919,52 +946,9 @@ const defaultTheme = {
|
|
|
919
946
|
}
|
|
920
947
|
};
|
|
921
948
|
//#endregion
|
|
922
|
-
//#region src/providers/chart-context/private/with-catalog-pointers.ts
|
|
923
|
-
const CATALOG_RESTORE_FOR_ROLE = {
|
|
924
|
-
"--a8c-charts-color-background": () => ({ backgroundColor: defaultTheme.backgroundColor }),
|
|
925
|
-
"--a8c-charts-color-grid": (theme) => ({ gridStyles: {
|
|
926
|
-
...theme.gridStyles,
|
|
927
|
-
stroke: defaultTheme.gridStyles.stroke
|
|
928
|
-
} }),
|
|
929
|
-
"--a8c-charts-color-axis": (theme) => ({ xAxisLineStyles: {
|
|
930
|
-
...theme.xAxisLineStyles,
|
|
931
|
-
stroke: defaultTheme.xAxisLineStyles.stroke
|
|
932
|
-
} }),
|
|
933
|
-
"--a8c-charts-color-tick": (theme) => ({ xTickLineStyles: {
|
|
934
|
-
...theme.xTickLineStyles,
|
|
935
|
-
stroke: defaultTheme.xTickLineStyles.stroke
|
|
936
|
-
} }),
|
|
937
|
-
"--a8c-charts-color-label-axis": (theme) => ({ svgLabelSmall: {
|
|
938
|
-
...theme.svgLabelSmall,
|
|
939
|
-
fill: defaultTheme.svgLabelSmall.fill
|
|
940
|
-
} })
|
|
941
|
-
};
|
|
942
|
-
/**
|
|
943
|
-
* 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.
|
|
944
|
-
*
|
|
945
|
-
* 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`.
|
|
946
|
-
*
|
|
947
|
-
* 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.
|
|
948
|
-
*
|
|
949
|
-
* @param merged - The consumer theme merged onto `defaultTheme` (`mergeThemes` output).
|
|
950
|
-
* @param overriddenRoles - The catalog roles the consumer overrode, from `themeOverrideVars`.
|
|
951
|
-
* @return A new theme object; `merged` is not mutated.
|
|
952
|
-
*/
|
|
953
|
-
const withCatalogPointers = (merged, overriddenRoles) => {
|
|
954
|
-
let result = merged;
|
|
955
|
-
for (const role of overriddenRoles) {
|
|
956
|
-
const restore = CATALOG_RESTORE_FOR_ROLE[role];
|
|
957
|
-
if (restore) result = {
|
|
958
|
-
...result,
|
|
959
|
-
...restore(result)
|
|
960
|
-
};
|
|
961
|
-
}
|
|
962
|
-
return result;
|
|
963
|
-
};
|
|
964
|
-
//#endregion
|
|
965
949
|
//#region src/providers/chart-context/global-charts-provider.tsx
|
|
966
950
|
const GlobalChartsContext = (0, react.createContext)(null);
|
|
967
|
-
const GlobalChartsProvider = ({ children, theme }) => {
|
|
951
|
+
const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
968
952
|
const [charts, setCharts] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
969
953
|
const [hiddenSeries, setHiddenSeries] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
970
954
|
const seededCharts = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
@@ -974,11 +958,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
974
958
|
wrapperRef.current = node;
|
|
975
959
|
setScopeNode(node);
|
|
976
960
|
}, []);
|
|
977
|
-
const
|
|
978
|
-
const providerTheme = (0, react.useMemo)(() => {
|
|
979
|
-
if (!theme) return defaultTheme;
|
|
980
|
-
return withCatalogPointers(mergeThemes(defaultTheme, theme), overriddenRoles);
|
|
981
|
-
}, [theme, overriddenRoles]);
|
|
961
|
+
const providerTheme = (0, react.useMemo)(() => theme ? mergeThemes(defaultTheme, theme) : defaultTheme, [theme]);
|
|
982
962
|
const [colorCache, setColorCache] = (0, react.useState)(() => ({
|
|
983
963
|
colors: [],
|
|
984
964
|
hues: [],
|
|
@@ -989,29 +969,26 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
989
969
|
const [isColorPaletteResolved, setIsColorPaletteResolved] = (0, react.useState)(false);
|
|
990
970
|
(0, react.useLayoutEffect)(() => {
|
|
991
971
|
setIsColorPaletteResolved(false);
|
|
992
|
-
const { colors } = providerTheme;
|
|
993
972
|
const resolvedColors = [];
|
|
994
973
|
const hues = [];
|
|
995
974
|
const existingHslColors = [];
|
|
996
975
|
let minHue = 360;
|
|
997
976
|
let maxHue = 0;
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
maxHue = Math.max(maxHue, hslTuple[0]);
|
|
1014
|
-
}
|
|
977
|
+
for (const color of SERIES_PALETTE_POINTERS) {
|
|
978
|
+
const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
|
|
979
|
+
if (normalizedColor.startsWith("#")) {
|
|
980
|
+
resolvedColors.push(normalizedColor);
|
|
981
|
+
const hslColor = (0, _visx_vendor_d3_color.hsl)(normalizedColor);
|
|
982
|
+
if (!isNaN(hslColor.h)) {
|
|
983
|
+
const hslTuple = [
|
|
984
|
+
hslColor.h,
|
|
985
|
+
hslColor.s * 100,
|
|
986
|
+
hslColor.l * 100
|
|
987
|
+
];
|
|
988
|
+
hues.push(hslTuple[0]);
|
|
989
|
+
existingHslColors.push(hslTuple);
|
|
990
|
+
minHue = Math.min(minHue, hslTuple[0]);
|
|
991
|
+
maxHue = Math.max(maxHue, hslTuple[0]);
|
|
1015
992
|
}
|
|
1016
993
|
}
|
|
1017
994
|
}
|
|
@@ -1022,14 +999,15 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1022
999
|
minHue,
|
|
1023
1000
|
maxHue
|
|
1024
1001
|
});
|
|
1025
|
-
}, [
|
|
1002
|
+
}, []);
|
|
1026
1003
|
(0, react.useEffect)(() => {
|
|
1027
1004
|
if (colorCache.colors.length > 0) setIsColorPaletteResolved(true);
|
|
1028
1005
|
}, [colorCache]);
|
|
1029
1006
|
const [groupToColorMap, setGroupToColorMap] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
1007
|
+
const paletteKey = colorCache.colors.join(",");
|
|
1030
1008
|
(0, react.useEffect)(() => {
|
|
1031
1009
|
setGroupToColorMap(/* @__PURE__ */ new Map());
|
|
1032
|
-
}, [
|
|
1010
|
+
}, [paletteKey]);
|
|
1033
1011
|
const registerChart = (0, react.useCallback)((id, data) => {
|
|
1034
1012
|
setCharts((prev) => new Map(prev).set(id, data));
|
|
1035
1013
|
}, []);
|
|
@@ -1113,12 +1091,17 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1113
1091
|
const set = hiddenSeries.get(chartId);
|
|
1114
1092
|
return set ? new Set(set) : /* @__PURE__ */ new Set();
|
|
1115
1093
|
}, [hiddenSeries]);
|
|
1094
|
+
const formatting = (0, react.useMemo)(() => sanitizeFormatting({
|
|
1095
|
+
locale,
|
|
1096
|
+
timeZone
|
|
1097
|
+
}), [locale, timeZone]);
|
|
1116
1098
|
const value = (0, react.useMemo)(() => ({
|
|
1117
1099
|
charts,
|
|
1118
1100
|
registerChart,
|
|
1119
1101
|
unregisterChart,
|
|
1120
1102
|
getChartData,
|
|
1121
1103
|
theme: providerTheme,
|
|
1104
|
+
formatting,
|
|
1122
1105
|
getElementStyles,
|
|
1123
1106
|
toggleSeriesVisibility,
|
|
1124
1107
|
setSeriesVisibility,
|
|
@@ -1134,6 +1117,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1134
1117
|
unregisterChart,
|
|
1135
1118
|
getChartData,
|
|
1136
1119
|
providerTheme,
|
|
1120
|
+
formatting,
|
|
1137
1121
|
getElementStyles,
|
|
1138
1122
|
toggleSeriesVisibility,
|
|
1139
1123
|
setSeriesVisibility,
|
|
@@ -1149,10 +1133,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1149
1133
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1150
1134
|
ref: setWrapperNode,
|
|
1151
1135
|
className: CHART_SCOPE_CLASS,
|
|
1152
|
-
style: {
|
|
1153
|
-
display: "contents",
|
|
1154
|
-
...overrideVars
|
|
1155
|
-
},
|
|
1136
|
+
style: { display: "contents" },
|
|
1156
1137
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartScopeContext.Provider, {
|
|
1157
1138
|
value: scopeNode,
|
|
1158
1139
|
children
|
|
@@ -1216,6 +1197,39 @@ const useDeepMemo = (value) => {
|
|
|
1216
1197
|
return ref.current;
|
|
1217
1198
|
};
|
|
1218
1199
|
//#endregion
|
|
1200
|
+
//#region src/providers/chart-context/private/catalog-pointers.ts
|
|
1201
|
+
const CATALOG_POINTERS = {
|
|
1202
|
+
background: "var(--a8c-charts-color-background, #fff)",
|
|
1203
|
+
labelAxis: "var(--a8c-charts-color-label-axis, #1e1e1e)",
|
|
1204
|
+
grid: "var(--a8c-charts-color-grid, #dbdbdb)",
|
|
1205
|
+
axisX: "var(--a8c-charts-color-axis-x, #dbdbdb)",
|
|
1206
|
+
tickX: "var(--a8c-charts-color-tick-x, #dbdbdb)",
|
|
1207
|
+
axisY: "var(--a8c-charts-color-axis-y, none)",
|
|
1208
|
+
tickY: "var(--a8c-charts-color-tick-y, none)",
|
|
1209
|
+
annotation: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
1210
|
+
surface: "var(--a8c-charts-color-surface, #fff)",
|
|
1211
|
+
surfaceSecondary: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
1212
|
+
trendUp: "var(--a8c-charts-color-trend-up, #008030)",
|
|
1213
|
+
trendDown: "var(--a8c-charts-color-trend-down, #cc1818)",
|
|
1214
|
+
series: SERIES_PALETTE_POINTERS
|
|
1215
|
+
};
|
|
1216
|
+
/**
|
|
1217
|
+
* The annotation parts visx paints, in the shape `@visx/annotation` takes. `radius`
|
|
1218
|
+
* rides along as the base the theme and the per-datum styles merge onto.
|
|
1219
|
+
*/
|
|
1220
|
+
const ANNOTATION_POINTERS = {
|
|
1221
|
+
label: {
|
|
1222
|
+
anchorLineStroke: CATALOG_POINTERS.annotation,
|
|
1223
|
+
backgroundFill: CATALOG_POINTERS.surface
|
|
1224
|
+
},
|
|
1225
|
+
connector: { stroke: CATALOG_POINTERS.annotation },
|
|
1226
|
+
circleSubject: {
|
|
1227
|
+
stroke: "transparent",
|
|
1228
|
+
fill: CATALOG_POINTERS.annotation,
|
|
1229
|
+
radius: 5
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
//#endregion
|
|
1219
1233
|
//#region src/providers/chart-scope/use-chart-scope-element.ts
|
|
1220
1234
|
/**
|
|
1221
1235
|
* Returns the nearest chart scope element, or `null` when rendered outside any scope (and during SSR, before the ref is attached).
|
|
@@ -1242,26 +1256,33 @@ const useXYChartTheme = (data) => {
|
|
|
1242
1256
|
return (0, react.useMemo)(() => {
|
|
1243
1257
|
const resolve = createCssVariableResolver(scopeElement);
|
|
1244
1258
|
const resolveColor = (value) => value ? resolve(value) ?? value : value;
|
|
1245
|
-
const
|
|
1259
|
+
const paletteColors = [...JSON.parse(seriesColorKey), ...CATALOG_POINTERS.series].map((color) => resolveColor(color)).filter((color) => Boolean(color) && !color.includes("var("));
|
|
1260
|
+
const resolvedLabelColor = resolveColor(CATALOG_POINTERS.labelAxis);
|
|
1261
|
+
const htmlLabelColor = resolvedLabelColor ? normalizeColorToHex(resolvedLabelColor) || resolvedLabelColor : resolvedLabelColor;
|
|
1246
1262
|
return (0, _visx_xychart.buildChartTheme)({
|
|
1247
1263
|
...theme,
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1264
|
+
gridColor: "",
|
|
1265
|
+
gridColorDark: "",
|
|
1266
|
+
colors: paletteColors,
|
|
1267
|
+
backgroundColor: resolveColor(CATALOG_POINTERS.background),
|
|
1268
|
+
htmlLabel: htmlLabelColor ? { color: htmlLabelColor } : void 0,
|
|
1269
|
+
gridStyles: {
|
|
1251
1270
|
...theme.gridStyles,
|
|
1252
|
-
stroke:
|
|
1271
|
+
stroke: CATALOG_POINTERS.grid
|
|
1253
1272
|
},
|
|
1254
|
-
xAxisLineStyles:
|
|
1273
|
+
xAxisLineStyles: {
|
|
1255
1274
|
...theme.xAxisLineStyles,
|
|
1256
|
-
stroke:
|
|
1275
|
+
stroke: CATALOG_POINTERS.axisX
|
|
1257
1276
|
},
|
|
1258
|
-
xTickLineStyles:
|
|
1277
|
+
xTickLineStyles: {
|
|
1259
1278
|
...theme.xTickLineStyles,
|
|
1260
|
-
stroke:
|
|
1279
|
+
stroke: CATALOG_POINTERS.tickX
|
|
1261
1280
|
},
|
|
1262
|
-
|
|
1281
|
+
yAxisLineStyles: { stroke: CATALOG_POINTERS.axisY },
|
|
1282
|
+
yTickLineStyles: { stroke: CATALOG_POINTERS.tickY },
|
|
1283
|
+
svgLabelSmall: {
|
|
1263
1284
|
...theme.svgLabelSmall,
|
|
1264
|
-
fill:
|
|
1285
|
+
fill: CATALOG_POINTERS.labelAxis
|
|
1265
1286
|
}
|
|
1266
1287
|
});
|
|
1267
1288
|
}, [
|
|
@@ -1359,11 +1380,12 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1359
1380
|
if (options.axis?.y?.tickValues?.length) return options.axis.y.tickValues;
|
|
1360
1381
|
const minY = Math.min(...allDataPoints.map((d) => d.value));
|
|
1361
1382
|
const maxY = Math.max(...allDataPoints.map((d) => d.value));
|
|
1362
|
-
|
|
1383
|
+
const yScale = (0, _visx_scale.createScale)({
|
|
1363
1384
|
...options.yScale,
|
|
1364
1385
|
domain: [minY, maxY],
|
|
1365
1386
|
range: [height, 0]
|
|
1366
|
-
})
|
|
1387
|
+
});
|
|
1388
|
+
return (0, _visx_scale.getTicks)(yScale, options.axis?.y?.numTicks);
|
|
1367
1389
|
}, [
|
|
1368
1390
|
options,
|
|
1369
1391
|
data,
|
|
@@ -1488,7 +1510,7 @@ const MIN_PIXEL_SIZE = 3;
|
|
|
1488
1510
|
/**
|
|
1489
1511
|
* Pixel size for zero-value bars (1px less than near-zero to be visually distinguishable).
|
|
1490
1512
|
*/
|
|
1491
|
-
const ZERO_PIXEL_SIZE =
|
|
1513
|
+
const ZERO_PIXEL_SIZE = 2;
|
|
1492
1514
|
const useZeroValueDisplay = (data, options = { enabled: false }) => {
|
|
1493
1515
|
const { enabled, valueAxisLength } = options;
|
|
1494
1516
|
return (0, react.useMemo)(() => {
|
|
@@ -1666,6 +1688,21 @@ const useGlobalChartsTheme = () => {
|
|
|
1666
1688
|
return (0, react.useContext)(GlobalChartsContext)?.theme ?? defaultTheme;
|
|
1667
1689
|
};
|
|
1668
1690
|
//#endregion
|
|
1691
|
+
//#region src/providers/chart-context/hooks/use-chart-formatting.ts
|
|
1692
|
+
const RUNTIME_FORMATTING = {};
|
|
1693
|
+
/**
|
|
1694
|
+
* The locale and time zone dates are rendered in, as set on `GlobalChartsProvider`.
|
|
1695
|
+
*
|
|
1696
|
+
* Falls back to the runtime's own rather than throwing: charts render outside a
|
|
1697
|
+
* provider, and a host that sets neither gets exactly the browser-default
|
|
1698
|
+
* behavior this package had before the context existed.
|
|
1699
|
+
*
|
|
1700
|
+
* @return The host's formatting context.
|
|
1701
|
+
*/
|
|
1702
|
+
const useChartFormatting = () => {
|
|
1703
|
+
return (0, react.useContext)(GlobalChartsContext)?.formatting ?? RUNTIME_FORMATTING;
|
|
1704
|
+
};
|
|
1705
|
+
//#endregion
|
|
1669
1706
|
//#region src/components/legend/utils/value-or-identity.ts
|
|
1670
1707
|
/**
|
|
1671
1708
|
* Returns an object's value if defined, or the object.
|
|
@@ -2103,9 +2140,311 @@ const BaseTooltip = ({ data, top, left, component: Component = DefaultTooltipCon
|
|
|
2103
2140
|
});
|
|
2104
2141
|
};
|
|
2105
2142
|
//#endregion
|
|
2143
|
+
//#region src/components/tooltip/private/bounded-tooltip.tsx
|
|
2144
|
+
const DEFAULT_OFFSET = 10;
|
|
2145
|
+
const isClipping = (element) => {
|
|
2146
|
+
const { overflow, overflowX, overflowY } = getComputedStyle(element);
|
|
2147
|
+
return [
|
|
2148
|
+
overflow,
|
|
2149
|
+
overflowX,
|
|
2150
|
+
overflowY
|
|
2151
|
+
].some((value) => value && value !== "visible");
|
|
2152
|
+
};
|
|
2153
|
+
const findClippingAncestor = (wrapper) => {
|
|
2154
|
+
let element = wrapper.parentElement;
|
|
2155
|
+
while (element && element !== document.body) {
|
|
2156
|
+
if (isClipping(element)) return element;
|
|
2157
|
+
element = element.parentElement;
|
|
2158
|
+
}
|
|
2159
|
+
return null;
|
|
2160
|
+
};
|
|
2161
|
+
/**
|
|
2162
|
+
* Where the box goes, in wrapper coordinates. Below and to the right of the
|
|
2163
|
+
* anchor; flipped to the other side when that side clips less, as visx's
|
|
2164
|
+
* `TooltipWithBounds` decides it; then clamped so the box stays inside
|
|
2165
|
+
* `bounds` whenever it fits at all.
|
|
2166
|
+
*
|
|
2167
|
+
* @param params - Anchor, offsets, the box size and the bounds to keep inside.
|
|
2168
|
+
* @param params.left - Anchor x, in wrapper coordinates.
|
|
2169
|
+
* @param params.top - Anchor y, in wrapper coordinates.
|
|
2170
|
+
* @param params.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2171
|
+
* @param params.offsetTop - Gap between the anchor and the box, vertically.
|
|
2172
|
+
* @param params.box - Rendered size of the box.
|
|
2173
|
+
* @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
|
|
2174
|
+
* @return The box's top-left corner, rounded to whole pixels.
|
|
2175
|
+
*/
|
|
2176
|
+
const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) => {
|
|
2177
|
+
const rightX = left + offsetLeft;
|
|
2178
|
+
const leftX = left - offsetLeft - box.width;
|
|
2179
|
+
const rightOverflow = rightX + box.width - bounds.right;
|
|
2180
|
+
const leftOverflow = bounds.left - leftX;
|
|
2181
|
+
let x = rightOverflow > 0 && rightOverflow > leftOverflow ? leftX : rightX;
|
|
2182
|
+
const downY = top + offsetTop;
|
|
2183
|
+
const upY = top - offsetTop - box.height;
|
|
2184
|
+
const downOverflow = downY + box.height - bounds.bottom;
|
|
2185
|
+
const upOverflow = bounds.top - upY;
|
|
2186
|
+
let y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
|
|
2187
|
+
x = Math.min(Math.max(x, bounds.left), Math.max(bounds.left, bounds.right - box.width));
|
|
2188
|
+
y = Math.min(Math.max(y, bounds.top), Math.max(bounds.top, bounds.bottom - box.height));
|
|
2189
|
+
return {
|
|
2190
|
+
x: Math.round(x),
|
|
2191
|
+
y: Math.round(y)
|
|
2192
|
+
};
|
|
2193
|
+
};
|
|
2194
|
+
/**
|
|
2195
|
+
* visx's `Tooltip`, positioned like its `TooltipWithBounds` but kept inside the
|
|
2196
|
+
* nearest clipping ancestor — or the viewport when there is none — rather than
|
|
2197
|
+
* inside its own parent. Rendered in-tree, a tooltip's parent is the chart
|
|
2198
|
+
* wrapper, which is often narrower than the box; measuring against the parent
|
|
2199
|
+
* alone would let the box spill into an `overflow: hidden` card and be cut off.
|
|
2200
|
+
*
|
|
2201
|
+
* Re-measures on every render, so a box whose content changes width between
|
|
2202
|
+
* two hovers is placed for its current size.
|
|
2203
|
+
*
|
|
2204
|
+
* @param props - visx `Tooltip` props.
|
|
2205
|
+
* @param props.left - Anchor x, in wrapper coordinates.
|
|
2206
|
+
* @param props.top - Anchor y, in wrapper coordinates.
|
|
2207
|
+
* @param props.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2208
|
+
* @param props.offsetTop - Gap between the anchor and the box, vertically.
|
|
2209
|
+
* @param props.style - Box styles; visx's defaults unless `unstyled`.
|
|
2210
|
+
* @param props.unstyled - Skip `style` and leave the box bare.
|
|
2211
|
+
* @param props.children - Box content.
|
|
2212
|
+
* @return The tooltip box.
|
|
2213
|
+
*/
|
|
2214
|
+
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = _visx_tooltip.defaultStyles, unstyled = false, children, ...rest }) => {
|
|
2215
|
+
const nodeRef = (0, react.useRef)(null);
|
|
2216
|
+
const clipRef = (0, react.useRef)(null);
|
|
2217
|
+
const [position, setPosition] = (0, react.useState)(null);
|
|
2218
|
+
(0, react.useLayoutEffect)(() => {
|
|
2219
|
+
const node = nodeRef.current;
|
|
2220
|
+
const wrapper = node?.parentElement;
|
|
2221
|
+
if (!node || !wrapper) return;
|
|
2222
|
+
if (clipRef.current?.wrapper !== wrapper) clipRef.current = {
|
|
2223
|
+
wrapper,
|
|
2224
|
+
clip: findClippingAncestor(wrapper)
|
|
2225
|
+
};
|
|
2226
|
+
const own = node.getBoundingClientRect();
|
|
2227
|
+
const wrapperRect = wrapper.getBoundingClientRect();
|
|
2228
|
+
const clipRect = clipRef.current.clip?.getBoundingClientRect() ?? {
|
|
2229
|
+
left: 0,
|
|
2230
|
+
top: 0,
|
|
2231
|
+
right: window.innerWidth,
|
|
2232
|
+
bottom: window.innerHeight
|
|
2233
|
+
};
|
|
2234
|
+
const next = getBoundedPosition({
|
|
2235
|
+
left,
|
|
2236
|
+
top,
|
|
2237
|
+
offsetLeft,
|
|
2238
|
+
offsetTop,
|
|
2239
|
+
box: {
|
|
2240
|
+
width: own.width,
|
|
2241
|
+
height: own.height
|
|
2242
|
+
},
|
|
2243
|
+
bounds: {
|
|
2244
|
+
left: clipRect.left - wrapperRect.left,
|
|
2245
|
+
top: clipRect.top - wrapperRect.top,
|
|
2246
|
+
right: clipRect.right - wrapperRect.left,
|
|
2247
|
+
bottom: clipRect.bottom - wrapperRect.top
|
|
2248
|
+
}
|
|
2249
|
+
});
|
|
2250
|
+
setPosition((current) => current && current.x === next.x && current.y === next.y ? current : next);
|
|
2251
|
+
}, [
|
|
2252
|
+
left,
|
|
2253
|
+
top,
|
|
2254
|
+
offsetLeft,
|
|
2255
|
+
offsetTop,
|
|
2256
|
+
children
|
|
2257
|
+
]);
|
|
2258
|
+
const x = position?.x ?? left + offsetLeft;
|
|
2259
|
+
const y = position?.y ?? top + offsetTop;
|
|
2260
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_tooltip.Tooltip, {
|
|
2261
|
+
ref: nodeRef,
|
|
2262
|
+
style: {
|
|
2263
|
+
position: "absolute",
|
|
2264
|
+
left: 0,
|
|
2265
|
+
top: 0,
|
|
2266
|
+
transform: `translate(${x}px, ${y}px)`,
|
|
2267
|
+
...!unstyled && style
|
|
2268
|
+
},
|
|
2269
|
+
...rest,
|
|
2270
|
+
children
|
|
2271
|
+
});
|
|
2272
|
+
};
|
|
2273
|
+
//#endregion
|
|
2274
|
+
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2275
|
+
const CROSSHAIR_STROKE_WIDTH = 1.5;
|
|
2276
|
+
const DEFAULT_GLYPH_RADIUS = 4;
|
|
2277
|
+
const FALLBACK_COLOR = "#222";
|
|
2278
|
+
const DEFAULT_TOOLTIP_Z_INDEX = 3;
|
|
2279
|
+
const PORTAL_OPTIONS = /* @__PURE__ */ new Set([
|
|
2280
|
+
"scroll",
|
|
2281
|
+
"debounce",
|
|
2282
|
+
"resizeObserverPolyfill"
|
|
2283
|
+
]);
|
|
2284
|
+
const isValidNumber = (value) => typeof value === "number" && Number.isFinite(value);
|
|
2285
|
+
const scaleBandwidth = (scale) => {
|
|
2286
|
+
const bandwidth = scale?.bandwidth;
|
|
2287
|
+
return typeof bandwidth === "function" ? Number(bandwidth()) : 0;
|
|
2288
|
+
};
|
|
2289
|
+
const DefaultGlyph$1 = ({ x, y, size, color, glyphStyle, seriesKey }) => {
|
|
2290
|
+
const { theme } = (0, react.useContext)(_visx_xychart.DataContext) || {};
|
|
2291
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
2292
|
+
cx: x,
|
|
2293
|
+
cy: y,
|
|
2294
|
+
r: size,
|
|
2295
|
+
fill: color,
|
|
2296
|
+
stroke: theme?.backgroundColor,
|
|
2297
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2298
|
+
paintOrder: "fill",
|
|
2299
|
+
...glyphStyle
|
|
2300
|
+
});
|
|
2301
|
+
};
|
|
2302
|
+
const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultGlyph$1, {
|
|
2303
|
+
seriesKey: key,
|
|
2304
|
+
...props
|
|
2305
|
+
}, key);
|
|
2306
|
+
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 }) => {
|
|
2307
|
+
const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
|
|
2308
|
+
const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = (0, react.useContext)(_visx_xychart.DataContext) || {};
|
|
2309
|
+
const tooltipContent = renderTooltip ? renderTooltip({
|
|
2310
|
+
...tooltipContext,
|
|
2311
|
+
colorScale
|
|
2312
|
+
}) : null;
|
|
2313
|
+
if (tooltipContent == null) return null;
|
|
2314
|
+
const scaleX = xScale;
|
|
2315
|
+
const scaleY = yScale;
|
|
2316
|
+
const getDatumLeftTop = (key, datum) => {
|
|
2317
|
+
const entry = dataRegistry?.get(key);
|
|
2318
|
+
return {
|
|
2319
|
+
left: scaleX && entry?.xAccessor ? Number(scaleX(entry.xAccessor(datum))) + scaleBandwidth(xScale) / 2 : void 0,
|
|
2320
|
+
top: scaleY && entry?.yAccessor ? Number(scaleY(entry.yAccessor(datum))) + scaleBandwidth(yScale) / 2 : void 0
|
|
2321
|
+
};
|
|
2322
|
+
};
|
|
2323
|
+
const nearestDatum = tooltipContext.tooltipData?.nearestDatum;
|
|
2324
|
+
let { tooltipLeft, tooltipTop } = tooltipContext;
|
|
2325
|
+
if (nearestDatum && (snapTooltipToDatumX || snapTooltipToDatumY)) {
|
|
2326
|
+
const { left, top } = getDatumLeftTop(nearestDatum.key, nearestDatum.datum);
|
|
2327
|
+
if (snapTooltipToDatumX && isValidNumber(left)) tooltipLeft = left;
|
|
2328
|
+
if (snapTooltipToDatumY && isValidNumber(top)) tooltipTop = top;
|
|
2329
|
+
}
|
|
2330
|
+
const glyphs = [];
|
|
2331
|
+
if (showDatumGlyph || showSeriesGlyphs) {
|
|
2332
|
+
const size = Number(glyphStyle?.radius ?? DEFAULT_GLYPH_RADIUS);
|
|
2333
|
+
const labelColor = theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2334
|
+
const fallbackColor = showSeriesGlyphs ? labelColor : theme?.gridStyles?.stroke ?? labelColor;
|
|
2335
|
+
let entries = [];
|
|
2336
|
+
if (showSeriesGlyphs) entries = Object.values(tooltipContext.tooltipData?.datumByKey ?? {});
|
|
2337
|
+
else if (nearestDatum) entries = [nearestDatum];
|
|
2338
|
+
for (const { key, datum, index } of entries) {
|
|
2339
|
+
const { left, top } = getDatumLeftTop(key, datum);
|
|
2340
|
+
if (!isValidNumber(left) || !isValidNumber(top)) continue;
|
|
2341
|
+
glyphs.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", {
|
|
2342
|
+
className: "visx-tooltip-glyph",
|
|
2343
|
+
transform: `translate(${left}, ${top})`,
|
|
2344
|
+
children: renderGlyph({
|
|
2345
|
+
key,
|
|
2346
|
+
color: colorScale?.(key) ?? fallbackColor,
|
|
2347
|
+
datum,
|
|
2348
|
+
index,
|
|
2349
|
+
size,
|
|
2350
|
+
x: 0,
|
|
2351
|
+
y: 0,
|
|
2352
|
+
glyphStyle,
|
|
2353
|
+
isNearestDatum: nearestDatum?.key === key
|
|
2354
|
+
})
|
|
2355
|
+
}, key));
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2359
|
+
const marginTop = margin?.top ?? 0;
|
|
2360
|
+
const marginLeft = margin?.left ?? 0;
|
|
2361
|
+
const TooltipComponent = detectBounds ? BoundedTooltip : _visx_tooltip.Tooltip;
|
|
2362
|
+
const boxStyle = {
|
|
2363
|
+
..._visx_tooltip.defaultStyles,
|
|
2364
|
+
zIndex,
|
|
2365
|
+
background: theme?.backgroundColor ?? "white",
|
|
2366
|
+
boxShadow: `0 1px 2px ${theme?.htmlLabel?.color ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2367
|
+
...theme?.htmlLabel
|
|
2368
|
+
};
|
|
2369
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
2370
|
+
className: "visx-tooltip-overlay",
|
|
2371
|
+
pointerEvents: "none",
|
|
2372
|
+
children: [
|
|
2373
|
+
showVerticalCrosshair && isValidNumber(tooltipLeft) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
2374
|
+
className: "visx-crosshair visx-crosshair-vertical",
|
|
2375
|
+
x1: tooltipLeft,
|
|
2376
|
+
x2: tooltipLeft,
|
|
2377
|
+
y1: marginTop,
|
|
2378
|
+
y2: marginTop + innerHeight,
|
|
2379
|
+
stroke: crosshairStroke,
|
|
2380
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2381
|
+
...verticalCrosshairStyle
|
|
2382
|
+
}),
|
|
2383
|
+
showHorizontalCrosshair && isValidNumber(tooltipTop) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
2384
|
+
className: "visx-crosshair visx-crosshair-horizontal",
|
|
2385
|
+
x1: marginLeft,
|
|
2386
|
+
x2: marginLeft + innerWidth,
|
|
2387
|
+
y1: tooltipTop,
|
|
2388
|
+
y2: tooltipTop,
|
|
2389
|
+
stroke: crosshairStroke,
|
|
2390
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2391
|
+
...horizontalCrosshairStyle
|
|
2392
|
+
}),
|
|
2393
|
+
glyphs
|
|
2394
|
+
]
|
|
2395
|
+
}), container && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipComponent, {
|
|
2396
|
+
left: tooltipLeft,
|
|
2397
|
+
top: tooltipTop,
|
|
2398
|
+
style: boxStyle,
|
|
2399
|
+
applyPositionStyle: true,
|
|
2400
|
+
...tooltipProps,
|
|
2401
|
+
children: tooltipContent
|
|
2402
|
+
}), container)] });
|
|
2403
|
+
};
|
|
2404
|
+
/**
|
|
2405
|
+
* In-tree replacement for `@visx/xychart`'s `Tooltip`.
|
|
2406
|
+
*
|
|
2407
|
+
* visx renders its tooltip box, glyphs and crosshairs through portals appended
|
|
2408
|
+
* to `document.body`. That puts them in the page's root stacking context, where
|
|
2409
|
+
* they paint above every sticky or fixed element that lives inside a nested
|
|
2410
|
+
* stacking context, and no z-index on that element can change the order. This
|
|
2411
|
+
* component draws the glyphs and crosshairs straight into the chart SVG and
|
|
2412
|
+
* renders the tooltip box into the SVG's parent element, so all of them stack
|
|
2413
|
+
* as ordinary descendants of the chart.
|
|
2414
|
+
*
|
|
2415
|
+
* Render it as a child of `XYChart`. The element wrapping that `XYChart` must
|
|
2416
|
+
* be `position: relative` with the SVG at its origin, and `isolation: isolate`:
|
|
2417
|
+
* the box is placed with the SVG-local coordinates visx reports, and the
|
|
2418
|
+
* isolation keeps the box's `zIndex` from competing with page chrome. The box
|
|
2419
|
+
* flips and clamps to stay inside the nearest ancestor that clips its overflow
|
|
2420
|
+
* (or the viewport), so it may extend past the chart wrapper but is never cut
|
|
2421
|
+
* off unless that ancestor is smaller than the box itself.
|
|
2422
|
+
*
|
|
2423
|
+
* @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
|
|
2424
|
+
* @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
|
|
2425
|
+
*/
|
|
2426
|
+
const XyChartTooltip = (props) => {
|
|
2427
|
+
const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
2428
|
+
const [container, setContainer] = (0, react.useState)(null);
|
|
2429
|
+
const anchorRef = (0, react.useCallback)((node) => {
|
|
2430
|
+
setContainer(node?.ownerSVGElement?.parentElement ?? null);
|
|
2431
|
+
}, []);
|
|
2432
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("g", { ref: anchorRef }), tooltipContext?.tooltipOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltipContent, {
|
|
2433
|
+
...props,
|
|
2434
|
+
tooltipContext,
|
|
2435
|
+
container
|
|
2436
|
+
})] });
|
|
2437
|
+
};
|
|
2438
|
+
//#endregion
|
|
2106
2439
|
//#region src/components/tooltip/accessible-tooltip.tsx
|
|
2107
|
-
const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", ...props }) => {
|
|
2440
|
+
const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
|
|
2108
2441
|
const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
2442
|
+
const scopeElement = useChartScopeElement();
|
|
2443
|
+
const crosshairStroke = (0, react.useMemo)(() => {
|
|
2444
|
+
const stroke = resolveCssVariable(CATALOG_POINTERS.grid, scopeElement);
|
|
2445
|
+
return stroke ? { stroke } : void 0;
|
|
2446
|
+
}, [scopeElement]);
|
|
2447
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
2109
2448
|
const tooltipData = (0, react.useMemo)(() => {
|
|
2110
2449
|
if (mode !== "individual") return [];
|
|
2111
2450
|
if (series.length === 0) return [];
|
|
@@ -2166,11 +2505,11 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2166
2505
|
tabIndex: -1,
|
|
2167
2506
|
role: "tooltip",
|
|
2168
2507
|
"aria-atomic": "true",
|
|
2169
|
-
className: (0, clsx.default)(
|
|
2508
|
+
className: (0, clsx.default)(standaloneScopeClass, keyboardFocusedClassName),
|
|
2170
2509
|
children: tooltipContent
|
|
2171
2510
|
}, `chart-tooltip-${selectedIndex}`);
|
|
2172
2511
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2173
|
-
className:
|
|
2512
|
+
className: standaloneScopeClass,
|
|
2174
2513
|
role: "tooltip",
|
|
2175
2514
|
"aria-live": "polite",
|
|
2176
2515
|
children: tooltipContent
|
|
@@ -2180,14 +2519,23 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2180
2519
|
renderTooltip,
|
|
2181
2520
|
selectedIndex,
|
|
2182
2521
|
tooltipRef,
|
|
2183
|
-
keyboardFocusedClassName
|
|
2522
|
+
keyboardFocusedClassName,
|
|
2523
|
+
standaloneScopeClass
|
|
2184
2524
|
]);
|
|
2185
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2525
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltip, {
|
|
2186
2526
|
...props,
|
|
2527
|
+
verticalCrosshairStyle: {
|
|
2528
|
+
...crosshairStroke,
|
|
2529
|
+
...verticalCrosshairStyle
|
|
2530
|
+
},
|
|
2531
|
+
horizontalCrosshairStyle: {
|
|
2532
|
+
...crosshairStroke,
|
|
2533
|
+
...horizontalCrosshairStyle
|
|
2534
|
+
},
|
|
2187
2535
|
renderTooltip: focusableRenderTooltip
|
|
2188
2536
|
});
|
|
2189
2537
|
};
|
|
2190
|
-
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints }) => {
|
|
2538
|
+
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate }) => {
|
|
2191
2539
|
return {
|
|
2192
2540
|
tooltipRef: (0, react.useCallback)((element) => {
|
|
2193
2541
|
if (element && selectedIndex !== void 0) element.focus();
|
|
@@ -2228,13 +2576,14 @@ const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating,
|
|
|
2228
2576
|
setSelectedIndex(void 0);
|
|
2229
2577
|
setIsNavigating(false);
|
|
2230
2578
|
chartRef.current?.focus();
|
|
2231
|
-
}
|
|
2579
|
+
} else if ((event.key === "Enter" || event.key === " ") && selectedIndex !== void 0) onActivate?.(selectedIndex);
|
|
2232
2580
|
}, [
|
|
2233
2581
|
totalPoints,
|
|
2234
2582
|
selectedIndex,
|
|
2235
2583
|
setSelectedIndex,
|
|
2236
2584
|
setIsNavigating,
|
|
2237
|
-
chartRef
|
|
2585
|
+
chartRef,
|
|
2586
|
+
onActivate
|
|
2238
2587
|
])
|
|
2239
2588
|
};
|
|
2240
2589
|
};
|
|
@@ -2521,72 +2870,90 @@ const getCurveType = (type, smoothing) => {
|
|
|
2521
2870
|
default: return _visx_curve.curveLinear;
|
|
2522
2871
|
}
|
|
2523
2872
|
};
|
|
2524
|
-
const
|
|
2525
|
-
|
|
2526
|
-
return (timestamp) => {
|
|
2527
|
-
if (!Number.isFinite(Number(timestamp))) return new Date(timestamp).toLocaleDateString();
|
|
2528
|
-
formatter = formatter ?? new Intl.DateTimeFormat(void 0, options);
|
|
2529
|
-
return formatter.format(timestamp);
|
|
2530
|
-
};
|
|
2531
|
-
};
|
|
2532
|
-
const formatYearTick = dateTimeFormat({ year: "numeric" });
|
|
2533
|
-
const formatDateTick = dateTimeFormat({
|
|
2873
|
+
const YEAR_TICK = { year: "numeric" };
|
|
2874
|
+
const DATE_TICK = {
|
|
2534
2875
|
month: "short",
|
|
2535
2876
|
day: "numeric"
|
|
2536
|
-
}
|
|
2537
|
-
const
|
|
2538
|
-
|
|
2539
|
-
hour12: true
|
|
2540
|
-
});
|
|
2541
|
-
const formatMonthTick = dateTimeFormat({ month: "short" });
|
|
2877
|
+
};
|
|
2878
|
+
const HOUR_TICK = { hour: "numeric" };
|
|
2879
|
+
const MONTH_TICK = { month: "short" };
|
|
2542
2880
|
const boundaryFormat = (isAnchor, atBoundary, between) => {
|
|
2543
2881
|
const format = (timestamp) => isAnchor(new Date(timestamp)) ? atBoundary(timestamp) : between(timestamp);
|
|
2544
2882
|
format.isAnchor = isAnchor;
|
|
2545
2883
|
return format;
|
|
2546
2884
|
};
|
|
2547
|
-
const
|
|
2548
|
-
const
|
|
2885
|
+
const tickFormats = (formatting) => {
|
|
2886
|
+
const clock = createZonedClock(formatting.timeZone);
|
|
2887
|
+
const year = createDateFormatter(YEAR_TICK, formatting);
|
|
2888
|
+
const date = createDateFormatter(DATE_TICK, formatting);
|
|
2889
|
+
const hour = createDateFormatter(HOUR_TICK, formatting);
|
|
2890
|
+
const month = createDateFormatter(MONTH_TICK, formatting);
|
|
2891
|
+
const datedTick = (timestamp) => date(timestamp);
|
|
2892
|
+
datedTick.anchorsAtLabelChange = true;
|
|
2893
|
+
return {
|
|
2894
|
+
year,
|
|
2895
|
+
date: datedTick,
|
|
2896
|
+
dateOrHour: boundaryFormat((value) => clock(value).hour === 0, date, hour),
|
|
2897
|
+
hour,
|
|
2898
|
+
monthOrYear: boundaryFormat((value) => clock(value).month === 1, year, month)
|
|
2899
|
+
};
|
|
2900
|
+
};
|
|
2549
2901
|
const getSpan = (sortedData) => {
|
|
2550
|
-
const bounds = sortedData.map((datom) => [datom.data.at(0)?.date, datom.data.at(-1)?.date]).filter(([first, last]) => first
|
|
2902
|
+
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)));
|
|
2551
2903
|
if (!bounds.length) return null;
|
|
2552
2904
|
return {
|
|
2553
2905
|
minX: Math.min(...bounds.map(([first]) => Number(first))),
|
|
2554
2906
|
maxX: Math.max(...bounds.map(([, last]) => Number(last)))
|
|
2555
2907
|
};
|
|
2556
2908
|
};
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
const
|
|
2567
|
-
|
|
2568
|
-
const spacingInHours = getPointSpacingInHours(sortedData);
|
|
2569
|
-
if (spacingInHours < SUB_DAILY_SPACING_HOURS) return "hour";
|
|
2570
|
-
if (!Number.isFinite(spacingInHours) || spacingInHours < MONTHLY_SPACING_HOURS) return "day";
|
|
2571
|
-
return spacingInHours < 12 * MONTHLY_SPACING_HOURS ? "month" : "year";
|
|
2572
|
-
};
|
|
2573
|
-
const getFormatter = (sortedData, tickResolution) => {
|
|
2909
|
+
/**
|
|
2910
|
+
* The most informative tick format for a bucket resolution and the span on screen.
|
|
2911
|
+
*
|
|
2912
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
2913
|
+
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
2914
|
+
* @param formatting - Host locale and time zone.
|
|
2915
|
+
* @param domain - The effective scale domain, or undefined for the data's own extent.
|
|
2916
|
+
* @return The formatter the axis labels its ticks with.
|
|
2917
|
+
*/
|
|
2918
|
+
const getFormatter = (sortedData, tickResolution, formatting = {}, domain) => {
|
|
2919
|
+
const format = tickFormats(formatting);
|
|
2574
2920
|
const resolution = getBucketResolution(sortedData, tickResolution);
|
|
2575
|
-
if (resolution === "year") return
|
|
2576
|
-
if (resolution === "month") return
|
|
2577
|
-
const span =
|
|
2578
|
-
|
|
2921
|
+
if (resolution === "year") return format.year;
|
|
2922
|
+
if (resolution === "month") return format.monthOrYear;
|
|
2923
|
+
const span = domain ? {
|
|
2924
|
+
minX: domain[0].getTime(),
|
|
2925
|
+
maxX: domain[1].getTime()
|
|
2926
|
+
} : getSpan(sortedData);
|
|
2927
|
+
if (!span) return format.date;
|
|
2579
2928
|
const diffInHours = Math.abs((0, date_fns.differenceInHours)(span.maxX, span.minX));
|
|
2580
2929
|
if (resolution === "hour") {
|
|
2581
|
-
if (diffInHours
|
|
2582
|
-
if (diffInHours <= 168) return
|
|
2930
|
+
if (diffInHours < 24) return format.hour;
|
|
2931
|
+
if (diffInHours <= 168) return format.dateOrHour;
|
|
2583
2932
|
}
|
|
2584
|
-
return Math.abs((0, date_fns.differenceInYears)(span.maxX, span.minX)) <= 1 ?
|
|
2933
|
+
return Math.abs((0, date_fns.differenceInYears)(span.maxX, span.minX)) <= 1 ? format.date : format.year;
|
|
2934
|
+
};
|
|
2935
|
+
/**
|
|
2936
|
+
* The instants a set of series spans, as a scale domain.
|
|
2937
|
+
*
|
|
2938
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
2939
|
+
* @return Earliest and latest dated point, or undefined when nothing is dated.
|
|
2940
|
+
*/
|
|
2941
|
+
const getSeriesExtent = (sortedData) => {
|
|
2942
|
+
const span = getSpan(sortedData);
|
|
2943
|
+
return span ? [new Date(span.minX), new Date(span.maxX)] : void 0;
|
|
2944
|
+
};
|
|
2945
|
+
const getAnchorIndices = (domain, tickFormatter, labels) => {
|
|
2946
|
+
if (tickFormatter.anchorsAtLabelChange) return labels.reduce((indices, label, index) => {
|
|
2947
|
+
if (index === 0 || label !== labels[index - 1]) indices.push(index);
|
|
2948
|
+
return indices;
|
|
2949
|
+
}, []);
|
|
2950
|
+
const { isAnchor } = tickFormatter;
|
|
2951
|
+
if (!isAnchor) return [];
|
|
2952
|
+
return domain.reduce((indices, date, index) => {
|
|
2953
|
+
if (isAnchor(date)) indices.push(index);
|
|
2954
|
+
return indices;
|
|
2955
|
+
}, []);
|
|
2585
2956
|
};
|
|
2586
|
-
const getAnchorIndices = (domain, isAnchor) => domain.reduce((indices, date, index) => {
|
|
2587
|
-
if (isAnchor(date)) indices.push(index);
|
|
2588
|
-
return indices;
|
|
2589
|
-
}, []);
|
|
2590
2957
|
const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
2591
2958
|
const steps = /* @__PURE__ */ new Set();
|
|
2592
2959
|
for (let count = maxTicks; count > 1; count--) {
|
|
@@ -2601,26 +2968,25 @@ const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
|
2601
2968
|
return steps;
|
|
2602
2969
|
};
|
|
2603
2970
|
/**
|
|
2604
|
-
* Tick values for
|
|
2971
|
+
* Tick values sampled by index, for the bar chart's band axis and for evenly
|
|
2972
|
+
* spaced points on a continuous one.
|
|
2605
2973
|
*
|
|
2606
|
-
* visx samples
|
|
2607
|
-
*
|
|
2608
|
-
*
|
|
2609
|
-
*
|
|
2610
|
-
*
|
|
2611
|
-
*
|
|
2612
|
-
* identical labels side by side.
|
|
2974
|
+
* visx samples by index from offset zero, blind to which labels carry a boundary
|
|
2975
|
+
* and without collapsing repeats — so the tick that prints the year or the date
|
|
2976
|
+
* often isn't sampled at all, and a long series can show the same label twice.
|
|
2977
|
+
* Choose the values instead: sweep the evenly spaced candidates, including those
|
|
2978
|
+
* that step from anchor to anchor, and keep the one that reaches the most anchors
|
|
2979
|
+
* without thinning the axis or putting two identical labels side by side.
|
|
2613
2980
|
*
|
|
2614
|
-
* @param domain -
|
|
2981
|
+
* @param domain - Buckets in axis order.
|
|
2615
2982
|
* @param tickFormatter - Formatter the axis will render these values with.
|
|
2616
2983
|
* @param maxTicks - Most ticks the axis should carry.
|
|
2617
2984
|
* @return Values to hand the axis as `tickValues`.
|
|
2618
2985
|
*/
|
|
2619
2986
|
const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
2620
2987
|
if (!domain.length) return [];
|
|
2621
|
-
const { isAnchor } = tickFormatter;
|
|
2622
|
-
const anchorIndices = isAnchor ? getAnchorIndices(domain, isAnchor) : [];
|
|
2623
2988
|
const domainLabels = domain.map((date) => tickFormatter(date.getTime()));
|
|
2989
|
+
const anchorIndices = getAnchorIndices(domain, tickFormatter, domainLabels);
|
|
2624
2990
|
const candidates = [];
|
|
2625
2991
|
const consider = (indices) => {
|
|
2626
2992
|
if (!indices.length || indices.length > maxTicks) return;
|
|
@@ -2632,15 +2998,108 @@ const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
|
2632
2998
|
for (let index = offset; index < domain.length; index += step) indices.push(index);
|
|
2633
2999
|
consider(indices);
|
|
2634
3000
|
}
|
|
2635
|
-
|
|
3001
|
+
const minStride = Math.max(1, Math.ceil(anchorIndices.length / maxTicks));
|
|
3002
|
+
for (let stride = minStride; stride <= anchorIndices.length; stride++) {
|
|
3003
|
+
const stepped = [];
|
|
3004
|
+
for (let position = 0; position < anchorIndices.length; position += stride) stepped.push(anchorIndices[position]);
|
|
3005
|
+
consider(stepped);
|
|
3006
|
+
}
|
|
2636
3007
|
if (!candidates.length) return [domain[0]];
|
|
2637
3008
|
const densest = candidates.reduce((most, indices) => Math.max(most, indices.length), 0);
|
|
2638
|
-
const
|
|
3009
|
+
const anchorIndexSet = new Set(anchorIndices);
|
|
3010
|
+
const anchorsIn = (indices) => indices.filter((index) => anchorIndexSet.has(index)).length;
|
|
2639
3011
|
return candidates.filter((indices) => indices.length >= densest - 1).reduce((chosen, indices) => {
|
|
2640
3012
|
const gain = anchorsIn(indices) - anchorsIn(chosen);
|
|
2641
3013
|
return gain > 0 || gain === 0 && indices.length > chosen.length ? indices : chosen;
|
|
2642
3014
|
}).map((index) => domain[index]);
|
|
2643
3015
|
};
|
|
3016
|
+
/**
|
|
3017
|
+
* The most x-axis ticks a chart of this width has room for.
|
|
3018
|
+
*
|
|
3019
|
+
* @param chartWidth - Chart width in pixels.
|
|
3020
|
+
* @return A tick budget of at least one.
|
|
3021
|
+
*/
|
|
3022
|
+
const getMaxTicksForWidth = (chartWidth) => Math.max(1, Math.floor(chartWidth / X_TICK_WIDTH));
|
|
3023
|
+
const MIN_GAP_IN_LABELS = .9;
|
|
3024
|
+
const nearestValue = (sorted, target) => {
|
|
3025
|
+
let low = 0;
|
|
3026
|
+
let high = sorted.length - 1;
|
|
3027
|
+
while (low < high) {
|
|
3028
|
+
const middle = Math.floor((low + high) / 2);
|
|
3029
|
+
if (sorted[middle] < target) low = middle + 1;
|
|
3030
|
+
else high = middle;
|
|
3031
|
+
}
|
|
3032
|
+
const above = sorted[low];
|
|
3033
|
+
const below = low > 0 ? sorted[low - 1] : above;
|
|
3034
|
+
return Math.abs(above - target) <= Math.abs(below - target) ? above : below;
|
|
3035
|
+
};
|
|
3036
|
+
const getPositionTickValues = (points, tickFormatter, maxTicks, axis) => {
|
|
3037
|
+
const times = points.map((point) => point.getTime());
|
|
3038
|
+
const { first, last } = axis;
|
|
3039
|
+
if (maxTicks <= 1 || times.length === 1 || first === last) return [points[0]];
|
|
3040
|
+
const step = (last - first) / (maxTicks - 1);
|
|
3041
|
+
const labels = points.map((point) => tickFormatter(point.getTime()));
|
|
3042
|
+
const minGap = (last - first) / maxTicks * MIN_GAP_IN_LABELS;
|
|
3043
|
+
const anchors = getAnchorIndices(points, tickFormatter, labels).map((index) => times[index]);
|
|
3044
|
+
const chosen = [];
|
|
3045
|
+
let lastLabel = null;
|
|
3046
|
+
for (let index = 0; index < maxTicks; index++) {
|
|
3047
|
+
const target = first + index * step;
|
|
3048
|
+
const anchor = anchors.length ? nearestValue(anchors, target) : null;
|
|
3049
|
+
let tick = anchor !== null && Math.abs(anchor - target) <= step / 2 ? anchor : null;
|
|
3050
|
+
if (tick === null) {
|
|
3051
|
+
const point = nearestValue(times, target);
|
|
3052
|
+
tick = Math.abs(point - target) <= step / 2 ? point : target;
|
|
3053
|
+
}
|
|
3054
|
+
const previous = chosen[chosen.length - 1];
|
|
3055
|
+
if (previous !== void 0 && (tick <= previous || tick - previous < minGap)) continue;
|
|
3056
|
+
const label = tickFormatter(tick);
|
|
3057
|
+
if (label === lastLabel) continue;
|
|
3058
|
+
chosen.push(tick);
|
|
3059
|
+
lastLabel = label;
|
|
3060
|
+
}
|
|
3061
|
+
return chosen.map((timestamp) => new Date(timestamp));
|
|
3062
|
+
};
|
|
3063
|
+
const isIndexSamplingUnusable = (ticks, points, maxTicks, axis) => {
|
|
3064
|
+
if (ticks.length < 2 || points.length < 2) return false;
|
|
3065
|
+
const span = axis.last - axis.first;
|
|
3066
|
+
if (!span) return false;
|
|
3067
|
+
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;
|
|
3068
|
+
};
|
|
3069
|
+
/**
|
|
3070
|
+
* Tick values for a continuous time axis, chosen from the points it draws.
|
|
3071
|
+
*
|
|
3072
|
+
* Sampled by index while the points are evenly spaced, which keeps the axis on
|
|
3073
|
+
* the calendar boundaries `getBandTickValues` steers towards, and by position
|
|
3074
|
+
* once they are not, where an index stride crowds one end of the scale.
|
|
3075
|
+
*
|
|
3076
|
+
* Values are taken from the data wherever there is one to take, so a local time
|
|
3077
|
+
* that does not exist cannot become a tick and DST needs no special case. Only a
|
|
3078
|
+
* target stranded in a gap is constructed, as a plain instant.
|
|
3079
|
+
*
|
|
3080
|
+
* @param sortedData - Series as returned by `useChartDataTransform`.
|
|
3081
|
+
* @param domain - The effective scale domain, or undefined for all data.
|
|
3082
|
+
* @param tickFormatter - The formatter the ticks will be labeled with.
|
|
3083
|
+
* @param maxTicks - The most ticks the axis has room for.
|
|
3084
|
+
* @return Tick dates, or null when no series carries a usable date.
|
|
3085
|
+
*/
|
|
3086
|
+
const getTimeAxisTickValues = (sortedData, domain, tickFormatter, maxTicks) => {
|
|
3087
|
+
const byTimestamp = /* @__PURE__ */ new Map();
|
|
3088
|
+
for (const series of sortedData) for (const point of series.data) {
|
|
3089
|
+
const date = point.date;
|
|
3090
|
+
if (date instanceof Date && Number.isFinite(date.getTime())) byTimestamp.set(date.getTime(), date);
|
|
3091
|
+
}
|
|
3092
|
+
if (!byTimestamp.size) return null;
|
|
3093
|
+
const min = domain?.[0]?.getTime();
|
|
3094
|
+
const max = domain?.[1]?.getTime();
|
|
3095
|
+
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));
|
|
3096
|
+
const axis = {
|
|
3097
|
+
first: min ?? visible[0].getTime(),
|
|
3098
|
+
last: max ?? visible[visible.length - 1].getTime()
|
|
3099
|
+
};
|
|
3100
|
+
const ticks = getBandTickValues(visible, tickFormatter, maxTicks);
|
|
3101
|
+
return isIndexSamplingUnusable(ticks, visible, maxTicks, axis) ? getPositionTickValues(visible, tickFormatter, maxTicks, axis) : ticks;
|
|
3102
|
+
};
|
|
2644
3103
|
const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
2645
3104
|
const span = getSpan(data);
|
|
2646
3105
|
if (!span) return 1;
|
|
@@ -2655,7 +3114,43 @@ const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
|
2655
3114
|
if (ticks.some((tick, idx) => idx > 0 && tick === ticks[idx - 1])) continue;
|
|
2656
3115
|
return ticks.length;
|
|
2657
3116
|
}
|
|
2658
|
-
return secondBestGuess;
|
|
3117
|
+
return Math.max(1, secondBestGuess);
|
|
3118
|
+
};
|
|
3119
|
+
//#endregion
|
|
3120
|
+
//#region src/charts/private/time-axis-options.ts
|
|
3121
|
+
const toDateDomain = (domain) => domain ? [new Date(domain[0]), new Date(domain[1])] : void 0;
|
|
3122
|
+
/**
|
|
3123
|
+
* The x-axis options for a continuous time chart, shared by LineChart and AreaChart.
|
|
3124
|
+
*
|
|
3125
|
+
* Kept in one place so the tick-selection logic isn't duplicated between them.
|
|
3126
|
+
*
|
|
3127
|
+
* @param args - Named arguments.
|
|
3128
|
+
* @param args.dataSorted - Series as returned by `useChartDataTransform`.
|
|
3129
|
+
* @param args.width - Chart width in pixels, which bounds how many ticks fit.
|
|
3130
|
+
* @param args.axisOptions - The caller's `options.axis.x`.
|
|
3131
|
+
* @param args.scaleDomain - The caller's `options.xScale.domain`.
|
|
3132
|
+
* @param args.zoomDomain - The chart's current zoom window, when zoomed.
|
|
3133
|
+
* @param args.formatting - Host locale and time zone.
|
|
3134
|
+
* @param args.isSeriesRendered - Whether visx mounts a series, i.e. the legend shows it. Defaults to all of them.
|
|
3135
|
+
* @return Options ready to spread into the chart's `axis.x`; `orientation` is always set.
|
|
3136
|
+
*/
|
|
3137
|
+
const buildTimeAxisOptions = ({ dataSorted, width, axisOptions, scaleDomain, zoomDomain, formatting, isSeriesRendered }) => {
|
|
3138
|
+
const { tickResolution, tickFormat, tickValues: callerTickValues, numTicks: callerNumTicks, orientation: callerOrientation, display: callerDisplay, ...rest } = axisOptions ?? {};
|
|
3139
|
+
const rendered = isSeriesRendered ? dataSorted.filter(isSeriesRendered) : dataSorted;
|
|
3140
|
+
const effectiveDomain = zoomDomain ?? toDateDomain(scaleDomain) ?? getSeriesExtent(rendered);
|
|
3141
|
+
const ownFormatter = getFormatter(rendered, tickResolution, formatting, effectiveDomain);
|
|
3142
|
+
const formatter = tickFormat || ownFormatter;
|
|
3143
|
+
const ownTickValues = tickFormat || callerTickValues ? null : getTimeAxisTickValues(rendered, effectiveDomain, ownFormatter, callerNumTicks ?? getMaxTicksForWidth(width));
|
|
3144
|
+
const tickValues = callerTickValues ?? (ownTickValues?.length ? ownTickValues : void 0);
|
|
3145
|
+
const numTicks = callerNumTicks ?? (tickValues ? void 0 : guessOptimalNumTicks(rendered, width, formatter));
|
|
3146
|
+
return {
|
|
3147
|
+
orientation: callerOrientation ?? "bottom",
|
|
3148
|
+
tickFormat: formatter,
|
|
3149
|
+
display: callerDisplay ?? true,
|
|
3150
|
+
...rest,
|
|
3151
|
+
...tickValues ? { tickValues } : {},
|
|
3152
|
+
...numTicks === void 0 ? {} : { numTicks }
|
|
3153
|
+
};
|
|
2659
3154
|
};
|
|
2660
3155
|
//#endregion
|
|
2661
3156
|
//#region src/charts/private/with-responsive/with-responsive.module.scss
|
|
@@ -2936,6 +3431,9 @@ function ZoomResetButton({ onClick }) {
|
|
|
2936
3431
|
});
|
|
2937
3432
|
}
|
|
2938
3433
|
//#endregion
|
|
3434
|
+
//#region src/charts/private/xy-plot/xy-plot.module.scss
|
|
3435
|
+
var xy_plot_module_default = { "xy-plot": "a8ccharts-bIyhgG-xy-plot" };
|
|
3436
|
+
//#endregion
|
|
2939
3437
|
//#region src/charts/line-chart/line-chart.module.scss
|
|
2940
3438
|
var line_chart_module_default = {
|
|
2941
3439
|
"line-chart": "a8ccharts-inuQka-line-chart",
|
|
@@ -3001,7 +3499,7 @@ const LineChartAnnotationLabelWithPopover = ({ title, subtitle, renderLabel, ren
|
|
|
3001
3499
|
style: {
|
|
3002
3500
|
width: `44px`,
|
|
3003
3501
|
height: `44px`,
|
|
3004
|
-
transform: `translate(
|
|
3502
|
+
transform: `translate(22px, 0)`
|
|
3005
3503
|
},
|
|
3006
3504
|
"aria-label": title || (0, _wordpress_i18n.__)("View details", "jetpack-charts"),
|
|
3007
3505
|
children: renderLabel({
|
|
@@ -3176,12 +3674,14 @@ const getVerticalAnchor = (subjectType, isFlippedVertically, y, yMax, height) =>
|
|
|
3176
3674
|
};
|
|
3177
3675
|
const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", styles: datumStyles, testId, renderLabel, renderLabelPopover }) => {
|
|
3178
3676
|
const providerTheme = useGlobalChartsTheme();
|
|
3179
|
-
const scopeElement = useChartScopeElement();
|
|
3180
3677
|
const { xScale, yScale } = (0, react.useContext)(_visx_xychart.DataContext) || {};
|
|
3181
3678
|
const labelRef = (0, react.useRef)(null);
|
|
3182
3679
|
const [height, setHeight] = (0, react.useState)(null);
|
|
3183
|
-
const styles = (0,
|
|
3184
|
-
|
|
3680
|
+
const styles = (0, react.useMemo)(() => deepmerge.default.all([
|
|
3681
|
+
ANNOTATION_POINTERS,
|
|
3682
|
+
providerTheme.annotationStyles ?? {},
|
|
3683
|
+
datumStyles ?? {}
|
|
3684
|
+
]), [providerTheme.annotationStyles, datumStyles]);
|
|
3185
3685
|
(0, react.useEffect)(() => {
|
|
3186
3686
|
if (labelRef.current?.getBBox) {
|
|
3187
3687
|
const bbox = labelRef.current.getBBox();
|
|
@@ -3267,15 +3767,8 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3267
3767
|
dx,
|
|
3268
3768
|
dy,
|
|
3269
3769
|
children: [
|
|
3270
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.Connector, {
|
|
3271
|
-
|
|
3272
|
-
stroke: resolveColor(styles?.connector?.stroke)
|
|
3273
|
-
}),
|
|
3274
|
-
subjectType === "circle" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.CircleSubject, {
|
|
3275
|
-
...styles?.circleSubject,
|
|
3276
|
-
fill: resolveColor(styles?.circleSubject?.fill),
|
|
3277
|
-
stroke: resolveColor(styles?.circleSubject?.stroke)
|
|
3278
|
-
}),
|
|
3770
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.Connector, { ...styles?.connector }),
|
|
3771
|
+
subjectType === "circle" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.CircleSubject, { ...styles?.circleSubject }),
|
|
3279
3772
|
subjectType === "line-vertical" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.LineSubject, {
|
|
3280
3773
|
min: yMax,
|
|
3281
3774
|
max: yMin,
|
|
@@ -3309,8 +3802,6 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3309
3802
|
title,
|
|
3310
3803
|
subtitle,
|
|
3311
3804
|
...styles?.label,
|
|
3312
|
-
anchorLineStroke: resolveColor(styles?.label?.anchorLineStroke),
|
|
3313
|
-
backgroundFill: resolveColor(styles?.label?.backgroundFill),
|
|
3314
3805
|
...labelPosition,
|
|
3315
3806
|
horizontalAnchor: getHorizontalAnchor(subjectType, isFlippedHorizontally),
|
|
3316
3807
|
verticalAnchor: getVerticalAnchor(subjectType, isFlippedVertically, y, yMax, height ?? ANNOTATION_INIT_HEIGHT)
|
|
@@ -3358,16 +3849,33 @@ const toNumber = (val) => {
|
|
|
3358
3849
|
const num = typeof val === "number" ? val : parseFloat(val);
|
|
3359
3850
|
return isNaN(num) ? void 0 : num;
|
|
3360
3851
|
};
|
|
3852
|
+
const TOOLTIP_DATE = {};
|
|
3853
|
+
const TOOLTIP_FORMAT_BY_RESOLUTION$1 = {
|
|
3854
|
+
hour: {
|
|
3855
|
+
year: "numeric",
|
|
3856
|
+
month: "numeric",
|
|
3857
|
+
day: "numeric",
|
|
3858
|
+
hour: "numeric"
|
|
3859
|
+
},
|
|
3860
|
+
day: TOOLTIP_DATE,
|
|
3861
|
+
month: TOOLTIP_DATE,
|
|
3862
|
+
year: TOOLTIP_DATE
|
|
3863
|
+
};
|
|
3864
|
+
const TooltipDate = ({ date, displayResolution }) => {
|
|
3865
|
+
const formatting = useChartFormatting();
|
|
3866
|
+
const format = (0, react.useMemo)(() => createDateFormatter(TOOLTIP_FORMAT_BY_RESOLUTION$1[displayResolution], formatting), [displayResolution, formatting]);
|
|
3867
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: date ? format(date) : null });
|
|
3868
|
+
};
|
|
3361
3869
|
/**
|
|
3362
3870
|
* Default visx-tooltip render that prints the hovered date as a heading and
|
|
3363
3871
|
* one row per visible series (label + formatted value), sorted descending by
|
|
3364
3872
|
* value. Reused by AreaChart, which has the same multi-series shape.
|
|
3365
3873
|
*
|
|
3366
|
-
* @param params - visx `RenderTooltipParams< DataPointDate
|
|
3874
|
+
* @param params - visx `RenderTooltipParams< DataPointDate >`, plus the chart's optional `bucketInfo`.
|
|
3367
3875
|
* @return Tooltip JSX, or `null` when no datum is hovered.
|
|
3368
3876
|
*/
|
|
3369
3877
|
const renderDefaultTooltip = (params) => {
|
|
3370
|
-
const { tooltipData } = params;
|
|
3878
|
+
const { tooltipData, bucketInfo } = params;
|
|
3371
3879
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
3372
3880
|
if (!nearestDatum) return null;
|
|
3373
3881
|
const tooltipPoints = Object.entries(tooltipData?.datumByKey || {}).map(([key, { datum }]) => ({
|
|
@@ -3378,7 +3886,10 @@ const renderDefaultTooltip = (params) => {
|
|
|
3378
3886
|
className: line_chart_module_default["line-chart__tooltip"],
|
|
3379
3887
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3380
3888
|
className: line_chart_module_default["line-chart__tooltip-date"],
|
|
3381
|
-
children:
|
|
3889
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipDate, {
|
|
3890
|
+
date: nearestDatum.date,
|
|
3891
|
+
displayResolution: bucketInfo?.displayResolution ?? "day"
|
|
3892
|
+
})
|
|
3382
3893
|
}), tooltipPoints.map((point) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
3383
3894
|
direction: "row",
|
|
3384
3895
|
align: "center",
|
|
@@ -3422,14 +3933,14 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
3422
3933
|
]);
|
|
3423
3934
|
return null;
|
|
3424
3935
|
};
|
|
3425
|
-
const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, 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) => {
|
|
3936
|
+
const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, 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) => {
|
|
3426
3937
|
const legendInteractive = legend.interactive ?? false;
|
|
3427
3938
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
3428
3939
|
const legendShape = legend.shape ?? "line";
|
|
3429
3940
|
const legendPosition = legend.position ?? "bottom";
|
|
3430
|
-
const
|
|
3941
|
+
const formatting = useChartFormatting();
|
|
3431
3942
|
const theme = useXYChartTheme(data);
|
|
3432
|
-
const resolvedBackgroundColor = theme.backgroundColor
|
|
3943
|
+
const resolvedBackgroundColor = theme.backgroundColor;
|
|
3433
3944
|
const chartId = useChartId(providedChartId);
|
|
3434
3945
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
3435
3946
|
const isSeriesVisible = (0, react.useCallback)((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
|
|
@@ -3484,26 +3995,36 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3484
3995
|
}
|
|
3485
3996
|
return min < max ? [min, max] : void 0;
|
|
3486
3997
|
}, [rescaleYOnVisibilityChange, dataSorted]);
|
|
3998
|
+
const activateSelectedPoint = (0, react.useCallback)((index) => {
|
|
3999
|
+
const series = dataSorted[0];
|
|
4000
|
+
const datum = series?.data[index];
|
|
4001
|
+
if (series && datum) onDatumActivate?.({
|
|
4002
|
+
datum,
|
|
4003
|
+
index,
|
|
4004
|
+
key: series.label
|
|
4005
|
+
});
|
|
4006
|
+
}, [dataSorted, onDatumActivate]);
|
|
3487
4007
|
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
3488
4008
|
selectedIndex,
|
|
3489
4009
|
setSelectedIndex,
|
|
3490
4010
|
isNavigating,
|
|
3491
4011
|
setIsNavigating,
|
|
3492
4012
|
chartRef,
|
|
3493
|
-
totalPoints: dataSorted[0]?.data.length || 0
|
|
4013
|
+
totalPoints: dataSorted[0]?.data.length || 0,
|
|
4014
|
+
onActivate: activateSelectedPoint
|
|
3494
4015
|
});
|
|
3495
4016
|
const chartOptions = (0, react.useMemo)(() => {
|
|
3496
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
3497
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
3498
4017
|
return {
|
|
3499
4018
|
axis: {
|
|
3500
|
-
x: {
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
4019
|
+
x: buildTimeAxisOptions({
|
|
4020
|
+
dataSorted,
|
|
4021
|
+
width,
|
|
4022
|
+
axisOptions: options?.axis?.x,
|
|
4023
|
+
scaleDomain: options?.xScale?.domain,
|
|
4024
|
+
zoomDomain: zoom.domain,
|
|
4025
|
+
formatting,
|
|
4026
|
+
isSeriesRendered: (series) => isSeriesVisible(series.label)
|
|
4027
|
+
}),
|
|
3507
4028
|
y: {
|
|
3508
4029
|
orientation: "left",
|
|
3509
4030
|
numTicks: 4,
|
|
@@ -3530,7 +4051,14 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3530
4051
|
dataSorted,
|
|
3531
4052
|
width,
|
|
3532
4053
|
zoom.domain,
|
|
3533
|
-
stableYDomain
|
|
4054
|
+
stableYDomain,
|
|
4055
|
+
formatting,
|
|
4056
|
+
isSeriesVisible
|
|
4057
|
+
]);
|
|
4058
|
+
const bucketInfo = (0, react.useMemo)(() => getBucketInfo(dataSorted.filter((series) => isSeriesVisible(series.label)), options?.axis?.x?.tickResolution), [
|
|
4059
|
+
dataSorted,
|
|
4060
|
+
isSeriesVisible,
|
|
4061
|
+
options?.axis?.x?.tickResolution
|
|
3534
4062
|
]);
|
|
3535
4063
|
const tooltipRenderGlyph = (0, react.useMemo)(() => {
|
|
3536
4064
|
return (props) => {
|
|
@@ -3554,42 +4082,48 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3554
4082
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme);
|
|
3555
4083
|
const error = validateData$4(dataSorted);
|
|
3556
4084
|
const isDataValid = !error;
|
|
4085
|
+
const legendItems = useChartLegendItems(dataSorted, (0, react.useMemo)(() => ({
|
|
4086
|
+
withGlyph: withLegendGlyph,
|
|
4087
|
+
glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
|
|
4088
|
+
collapseGroups: legendCollapseGroups,
|
|
4089
|
+
renderGlyph
|
|
4090
|
+
}), [
|
|
4091
|
+
withLegendGlyph,
|
|
4092
|
+
glyphStyle?.radius,
|
|
4093
|
+
legendCollapseGroups,
|
|
4094
|
+
renderGlyph
|
|
4095
|
+
]), legendShape);
|
|
4096
|
+
const chartMetadata = (0, react.useMemo)(() => ({
|
|
4097
|
+
withGradientFill,
|
|
4098
|
+
smoothing,
|
|
4099
|
+
curveType,
|
|
4100
|
+
withStartGlyphs,
|
|
4101
|
+
withEndGlyphs,
|
|
4102
|
+
withLegendGlyph
|
|
4103
|
+
}), [
|
|
4104
|
+
withGradientFill,
|
|
4105
|
+
smoothing,
|
|
4106
|
+
curveType,
|
|
4107
|
+
withStartGlyphs,
|
|
4108
|
+
withEndGlyphs,
|
|
4109
|
+
withLegendGlyph
|
|
4110
|
+
]);
|
|
3557
4111
|
useChartRegistration({
|
|
3558
4112
|
chartId,
|
|
3559
|
-
legendItems
|
|
3560
|
-
withGlyph: withLegendGlyph,
|
|
3561
|
-
glyphSize: Math.max(0, toNumber(glyphStyle?.radius) ?? 4),
|
|
3562
|
-
collapseGroups: legendCollapseGroups,
|
|
3563
|
-
renderGlyph
|
|
3564
|
-
}), [
|
|
3565
|
-
withLegendGlyph,
|
|
3566
|
-
glyphStyle?.radius,
|
|
3567
|
-
legendCollapseGroups,
|
|
3568
|
-
renderGlyph
|
|
3569
|
-
]), legendShape),
|
|
4113
|
+
legendItems,
|
|
3570
4114
|
chartType: "line",
|
|
3571
4115
|
isDataValid,
|
|
3572
|
-
metadata:
|
|
3573
|
-
withGradientFill,
|
|
3574
|
-
smoothing,
|
|
3575
|
-
curveType,
|
|
3576
|
-
withStartGlyphs,
|
|
3577
|
-
withEndGlyphs,
|
|
3578
|
-
withLegendGlyph
|
|
3579
|
-
}), [
|
|
3580
|
-
withGradientFill,
|
|
3581
|
-
smoothing,
|
|
3582
|
-
curveType,
|
|
3583
|
-
withStartGlyphs,
|
|
3584
|
-
withEndGlyphs,
|
|
3585
|
-
withLegendGlyph
|
|
3586
|
-
])
|
|
4116
|
+
metadata: chartMetadata
|
|
3587
4117
|
});
|
|
3588
4118
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
3589
4119
|
const accessors = {
|
|
3590
4120
|
xAccessor: (d) => d?.date,
|
|
3591
4121
|
yAccessor: (d) => d?.value
|
|
3592
4122
|
};
|
|
4123
|
+
const tooltipRenderer = (0, react.useMemo)(() => (params) => renderTooltip({
|
|
4124
|
+
...params,
|
|
4125
|
+
bucketInfo
|
|
4126
|
+
}), [renderTooltip, bucketInfo]);
|
|
3593
4127
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3594
4128
|
className: (0, clsx.default)("line-chart", line_chart_module_default["line-chart"]),
|
|
3595
4129
|
children: error
|
|
@@ -3638,7 +4172,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3638
4172
|
onBlur: onChartBlur,
|
|
3639
4173
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3640
4174
|
ref: chartRef,
|
|
3641
|
-
|
|
4175
|
+
className: xy_plot_module_default["xy-plot"],
|
|
3642
4176
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
3643
4177
|
theme,
|
|
3644
4178
|
width,
|
|
@@ -3730,7 +4264,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3730
4264
|
snapTooltipToDatumX: true,
|
|
3731
4265
|
snapTooltipToDatumY: true,
|
|
3732
4266
|
showSeriesGlyphs: true,
|
|
3733
|
-
renderTooltip,
|
|
4267
|
+
renderTooltip: tooltipRenderer,
|
|
3734
4268
|
renderGlyph: tooltipRenderGlyph,
|
|
3735
4269
|
glyphStyle,
|
|
3736
4270
|
showVerticalCrosshair: withTooltipCrosshairs?.showVertical,
|
|
@@ -3868,12 +4402,11 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
|
|
|
3868
4402
|
};
|
|
3869
4403
|
//#endregion
|
|
3870
4404
|
//#region src/charts/area-chart/area-chart.tsx
|
|
3871
|
-
const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange
|
|
4405
|
+
const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, stacked = true, stackOffset = "none", smoothing = true, curveType, fillOpacity, withStroke, renderTooltip = renderDefaultTooltip, animation, options = {}, onPointerDown, onPointerUp, onPointerMove, onPointerOut, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
3872
4406
|
const legendInteractive = legend.interactive ?? false;
|
|
3873
4407
|
const legendShape = legend.shape ?? "rect";
|
|
3874
4408
|
const legendPosition = legend.position ?? "bottom";
|
|
3875
|
-
const
|
|
3876
|
-
const providerTheme = useGlobalChartsTheme();
|
|
4409
|
+
const formatting = useChartFormatting();
|
|
3877
4410
|
const theme = useXYChartTheme(data);
|
|
3878
4411
|
const chartId = useChartId(providedChartId);
|
|
3879
4412
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
@@ -3923,7 +4456,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3923
4456
|
totalPoints: dataSorted[0]?.data.length || 0
|
|
3924
4457
|
});
|
|
3925
4458
|
const fixedYDomain = (0, react.useMemo)(() => {
|
|
3926
|
-
if (
|
|
4459
|
+
if (rescaleYOnVisibilityChange || !dataSorted.length || !dataSorted[0].data.length || stacked && stackOffset !== "none") return;
|
|
3927
4460
|
if (stacked) {
|
|
3928
4461
|
const numPoints = Math.max(...dataSorted.map((s) => s.data.length));
|
|
3929
4462
|
let posMax = 0;
|
|
@@ -3957,20 +4490,19 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3957
4490
|
dataSorted,
|
|
3958
4491
|
stacked,
|
|
3959
4492
|
stackOffset,
|
|
3960
|
-
|
|
4493
|
+
rescaleYOnVisibilityChange
|
|
3961
4494
|
]);
|
|
3962
4495
|
const chartOptions = (0, react.useMemo)(() => {
|
|
3963
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
3964
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
3965
4496
|
return {
|
|
3966
4497
|
axis: {
|
|
3967
|
-
x: {
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
3973
|
-
|
|
4498
|
+
x: buildTimeAxisOptions({
|
|
4499
|
+
dataSorted,
|
|
4500
|
+
width,
|
|
4501
|
+
axisOptions: options?.axis?.x,
|
|
4502
|
+
scaleDomain: options?.xScale?.domain,
|
|
4503
|
+
zoomDomain: zoom.domain,
|
|
4504
|
+
formatting
|
|
4505
|
+
}),
|
|
3974
4506
|
y: {
|
|
3975
4507
|
orientation: "left",
|
|
3976
4508
|
numTicks: 4,
|
|
@@ -3998,31 +4530,34 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3998
4530
|
width,
|
|
3999
4531
|
stacked,
|
|
4000
4532
|
fixedYDomain,
|
|
4001
|
-
zoom.domain
|
|
4533
|
+
zoom.domain,
|
|
4534
|
+
formatting
|
|
4002
4535
|
]);
|
|
4003
4536
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme);
|
|
4004
4537
|
const error = validateData$3(dataSorted);
|
|
4005
4538
|
const isDataValid = !error;
|
|
4539
|
+
const legendItems = useChartLegendItems(dataSorted, (0, react.useMemo)(() => ({
|
|
4540
|
+
withGlyph: false,
|
|
4541
|
+
glyphSize: 0,
|
|
4542
|
+
collapseGroups: legend.collapseGroups ?? false
|
|
4543
|
+
}), [legend.collapseGroups]), legendShape);
|
|
4544
|
+
const chartMetadata = (0, react.useMemo)(() => ({
|
|
4545
|
+
stacked,
|
|
4546
|
+
stackOffset,
|
|
4547
|
+
smoothing,
|
|
4548
|
+
curveType
|
|
4549
|
+
}), [
|
|
4550
|
+
stacked,
|
|
4551
|
+
stackOffset,
|
|
4552
|
+
smoothing,
|
|
4553
|
+
curveType
|
|
4554
|
+
]);
|
|
4006
4555
|
useChartRegistration({
|
|
4007
4556
|
chartId,
|
|
4008
|
-
legendItems
|
|
4009
|
-
withGlyph: false,
|
|
4010
|
-
glyphSize: 0,
|
|
4011
|
-
collapseGroups: legend.collapseGroups ?? false
|
|
4012
|
-
}), [legend.collapseGroups]), legendShape),
|
|
4557
|
+
legendItems,
|
|
4013
4558
|
chartType: "area",
|
|
4014
4559
|
isDataValid,
|
|
4015
|
-
metadata:
|
|
4016
|
-
stacked,
|
|
4017
|
-
stackOffset,
|
|
4018
|
-
smoothing,
|
|
4019
|
-
curveType
|
|
4020
|
-
}), [
|
|
4021
|
-
stacked,
|
|
4022
|
-
stackOffset,
|
|
4023
|
-
smoothing,
|
|
4024
|
-
curveType
|
|
4025
|
-
])
|
|
4560
|
+
metadata: chartMetadata
|
|
4026
4561
|
});
|
|
4027
4562
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
4028
4563
|
const animationEnabled = !!animation && !prefersReducedMotion;
|
|
@@ -4032,9 +4567,17 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4032
4567
|
};
|
|
4033
4568
|
const zeroYAccessor = (0, react.useCallback)(() => 0, []);
|
|
4034
4569
|
const visibleLabels = (0, react.useMemo)(() => new Set(seriesWithVisibility.filter((s) => s.isVisible).map((s) => s.series.label)), [seriesWithVisibility]);
|
|
4570
|
+
const bucketInfo = (0, react.useMemo)(() => getBucketInfo(dataSorted.filter((series) => visibleLabels.has(series.label)), options?.axis?.x?.tickResolution), [
|
|
4571
|
+
dataSorted,
|
|
4572
|
+
visibleLabels,
|
|
4573
|
+
options?.axis?.x?.tickResolution
|
|
4574
|
+
]);
|
|
4035
4575
|
const filteredRenderTooltip = (0, react.useCallback)((params) => {
|
|
4036
4576
|
const datumByKey = params?.tooltipData?.datumByKey;
|
|
4037
|
-
if (!datumByKey) return renderTooltip(
|
|
4577
|
+
if (!datumByKey) return renderTooltip({
|
|
4578
|
+
...params,
|
|
4579
|
+
bucketInfo
|
|
4580
|
+
});
|
|
4038
4581
|
const filtered = Object.fromEntries(Object.entries(datumByKey).filter(([key]) => visibleLabels.has(key)));
|
|
4039
4582
|
if (Object.keys(filtered).length === 0) return null;
|
|
4040
4583
|
const nearestDatum = params?.tooltipData?.nearestDatum;
|
|
@@ -4044,13 +4587,18 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4044
4587
|
};
|
|
4045
4588
|
return renderTooltip({
|
|
4046
4589
|
...params,
|
|
4590
|
+
bucketInfo,
|
|
4047
4591
|
tooltipData: {
|
|
4048
4592
|
...params.tooltipData,
|
|
4049
4593
|
datumByKey: filtered,
|
|
4050
4594
|
nearestDatum: nextNearest
|
|
4051
4595
|
}
|
|
4052
4596
|
});
|
|
4053
|
-
}, [
|
|
4597
|
+
}, [
|
|
4598
|
+
renderTooltip,
|
|
4599
|
+
visibleLabels,
|
|
4600
|
+
bucketInfo
|
|
4601
|
+
]);
|
|
4054
4602
|
const resolvedFillOpacity = fillOpacity ?? (stacked ? .85 : .4);
|
|
4055
4603
|
const resolvedWithStroke = withStroke ?? !stacked;
|
|
4056
4604
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4125,7 +4673,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4125
4673
|
onBlur: onChartBlur,
|
|
4126
4674
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4127
4675
|
ref: chartRef,
|
|
4128
|
-
|
|
4676
|
+
className: xy_plot_module_default["xy-plot"],
|
|
4129
4677
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
4130
4678
|
theme,
|
|
4131
4679
|
width,
|
|
@@ -4181,7 +4729,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4181
4729
|
stacked,
|
|
4182
4730
|
stackOffset,
|
|
4183
4731
|
getElementStyles,
|
|
4184
|
-
strokeColor: theme.backgroundColor
|
|
4732
|
+
strokeColor: theme.backgroundColor
|
|
4185
4733
|
})] }),
|
|
4186
4734
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AreaChartScalesRef, {
|
|
4187
4735
|
chartRef: internalChartRef,
|
|
@@ -4349,8 +4897,7 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4349
4897
|
year: "numeric",
|
|
4350
4898
|
month: "long",
|
|
4351
4899
|
day: "numeric",
|
|
4352
|
-
hour: "numeric"
|
|
4353
|
-
hour12: true
|
|
4900
|
+
hour: "numeric"
|
|
4354
4901
|
},
|
|
4355
4902
|
day: {
|
|
4356
4903
|
year: "numeric",
|
|
@@ -4369,16 +4916,16 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4369
4916
|
*
|
|
4370
4917
|
* @param data - Date-based series, already parsed and sorted by `useChartDataTransform`.
|
|
4371
4918
|
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
4919
|
+
* @param formatting - Host locale and time zone.
|
|
4372
4920
|
* @return Tooltip label formatter.
|
|
4373
4921
|
*/
|
|
4374
|
-
const getTooltipFormatter = (data, tickResolution) => {
|
|
4375
|
-
if (tickResolution === "week")
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
}));
|
|
4922
|
+
const getTooltipFormatter = (data, tickResolution, formatting) => {
|
|
4923
|
+
if (tickResolution === "week") {
|
|
4924
|
+
const formatDay = createDateFormatter(TOOLTIP_FORMAT_BY_RESOLUTION.day, formatting);
|
|
4925
|
+
return (timestamp) => (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("Week of %s", "jetpack-charts"), formatDay(timestamp));
|
|
4926
|
+
}
|
|
4380
4927
|
const format = TOOLTIP_FORMAT_BY_RESOLUTION[getBucketResolution(data, tickResolution)] ?? TOOLTIP_FORMAT_BY_RESOLUTION.day;
|
|
4381
|
-
return (
|
|
4928
|
+
return createDateFormatter(format, formatting);
|
|
4382
4929
|
};
|
|
4383
4930
|
const identity = (label) => label;
|
|
4384
4931
|
const byBucket = (format) => (bucket) => typeof bucket === "string" ? bucket : format(Number(bucket));
|
|
@@ -4429,6 +4976,7 @@ const getGroupPadding = (scale) => {
|
|
|
4429
4976
|
*/
|
|
4430
4977
|
function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = ALL_RENDERED) {
|
|
4431
4978
|
const stableOptions = useDeepMemo(options);
|
|
4979
|
+
const formatting = useChartFormatting();
|
|
4432
4980
|
const axisConfig = (0, react.useMemo)(() => {
|
|
4433
4981
|
const { labelOverflow: xLabelOverflow, tickResolution: xTickResolution, tickFormat: xTickFormat, ...xAxisOptions } = stableOptions.axis?.x || {};
|
|
4434
4982
|
const { labelOverflow: yLabelOverflow, tickResolution: yTickResolution, tickFormat: yTickFormat, ...yAxisOptions } = stableOptions.axis?.y || {};
|
|
@@ -4455,9 +5003,9 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4455
5003
|
zero: false
|
|
4456
5004
|
};
|
|
4457
5005
|
const hasLabels = Boolean(data?.[0]?.data?.[0]?.label);
|
|
4458
|
-
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution);
|
|
5006
|
+
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution, formatting);
|
|
4459
5007
|
const labelFormatter = timeTickFormatter ? byBucket(timeTickFormatter) : identity;
|
|
4460
|
-
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution));
|
|
5008
|
+
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution, formatting));
|
|
4461
5009
|
const valueFormatter = _automattic_number_formatters.formatNumberCompact;
|
|
4462
5010
|
const bandDomain = timeTickFormatter ? getBandDomain(data, isSeriesRendered) : null;
|
|
4463
5011
|
const valueAccessor = (d) => {
|
|
@@ -4493,7 +5041,8 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4493
5041
|
}, [
|
|
4494
5042
|
data,
|
|
4495
5043
|
tickResolution,
|
|
4496
|
-
isSeriesRendered
|
|
5044
|
+
isSeriesRendered,
|
|
5045
|
+
formatting
|
|
4497
5046
|
]);
|
|
4498
5047
|
return (0, react.useMemo)(() => {
|
|
4499
5048
|
const { xTickFormat: defaultXTickFormat, yTickFormat: defaultYTickFormat, tooltipLabelFormatter: defaultTooltipLabelFormatter, xAccessor, yAccessor, gridVisibility, xScale: baseXScale, yScale: baseYScale } = defaultOptions[horizontal ? "horizontal" : "vertical"];
|
|
@@ -4617,11 +5166,6 @@ function computeComparisonRect(params) {
|
|
|
4617
5166
|
};
|
|
4618
5167
|
}
|
|
4619
5168
|
/**
|
|
4620
|
-
* Fraction of each per-series step left as a gap between bars within a single tick.
|
|
4621
|
-
* Larger = more space between adjacent series; the shadow spans `1 - COMPARISON_INNER_GAP` of the step.
|
|
4622
|
-
*/
|
|
4623
|
-
const COMPARISON_INNER_GAP = .1;
|
|
4624
|
-
/**
|
|
4625
5169
|
* Upper clamp on the computed group padding, so bars can never collapse to zero width
|
|
4626
5170
|
* even at very large `widthFactor` values.
|
|
4627
5171
|
*/
|
|
@@ -4709,7 +5253,7 @@ const renderTooltipRow = (label, value) => /* @__PURE__ */ (0, react_jsx_runtime
|
|
|
4709
5253
|
className: bar_chart_module_default["bar-chart__tooltip-row"],
|
|
4710
5254
|
children: (0, _wordpress_i18n.sprintf)((0, _wordpress_i18n.__)("%1$s: %2$s", "jetpack-charts"), label, value)
|
|
4711
5255
|
});
|
|
4712
|
-
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" }) => {
|
|
5256
|
+
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 }) => {
|
|
4713
5257
|
const legendInteractive = legend.interactive ?? false;
|
|
4714
5258
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
4715
5259
|
const horizontal = orientation === "horizontal";
|
|
@@ -4736,14 +5280,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4736
5280
|
const [selectedIndex, setSelectedIndex] = (0, react.useState)(void 0);
|
|
4737
5281
|
const [isNavigating, setIsNavigating] = (0, react.useState)(false);
|
|
4738
5282
|
const primarySeriesForNav = dataWithVisibleZeros.filter((s) => s.options?.type !== "comparison");
|
|
4739
|
-
const
|
|
4740
|
-
selectedIndex,
|
|
4741
|
-
setSelectedIndex,
|
|
4742
|
-
isNavigating,
|
|
4743
|
-
setIsNavigating,
|
|
4744
|
-
chartRef,
|
|
4745
|
-
totalPoints: Math.max(0, ...primarySeriesForNav.map((s) => s.data?.length || 0)) * primarySeriesForNav.length
|
|
4746
|
-
});
|
|
5283
|
+
const totalPoints = Math.max(0, ...primarySeriesForNav.map((s) => s.data?.length || 0)) * primarySeriesForNav.length;
|
|
4747
5284
|
const seriesWithVisibility = (0, react.useMemo)(() => dataWithVisibleZeros.map((series, index) => ({
|
|
4748
5285
|
series,
|
|
4749
5286
|
index,
|
|
@@ -4755,6 +5292,27 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4755
5292
|
const primaryEntries = (0, react.useMemo)(() => seriesWithVisibility.filter(({ isVisible, series }) => isVisible && series.options?.type !== "comparison"), [seriesWithVisibility]);
|
|
4756
5293
|
const primaryKeys = (0, react.useMemo)(() => primaryEntries.map(({ series }) => series.label), [primaryEntries]);
|
|
4757
5294
|
const primarySeries = (0, react.useMemo)(() => primaryEntries.map(({ series }) => series), [primaryEntries]);
|
|
5295
|
+
const activateSelectedBar = (0, react.useCallback)((index) => {
|
|
5296
|
+
const primaryCount = primaryEntries.length;
|
|
5297
|
+
if (!primaryCount) return;
|
|
5298
|
+
const dataPointIndex = Math.floor(index / primaryCount);
|
|
5299
|
+
const series = primaryEntries[index % primaryCount]?.series;
|
|
5300
|
+
const datum = series?.data[dataPointIndex];
|
|
5301
|
+
if (series && datum) onDatumActivate?.({
|
|
5302
|
+
datum,
|
|
5303
|
+
index: dataPointIndex,
|
|
5304
|
+
key: series.label
|
|
5305
|
+
});
|
|
5306
|
+
}, [primaryEntries, onDatumActivate]);
|
|
5307
|
+
const { tooltipRef, onChartFocus, onChartBlur, onChartKeyDown } = useKeyboardNavigation({
|
|
5308
|
+
selectedIndex,
|
|
5309
|
+
setSelectedIndex,
|
|
5310
|
+
isNavigating,
|
|
5311
|
+
setIsNavigating,
|
|
5312
|
+
chartRef,
|
|
5313
|
+
totalPoints,
|
|
5314
|
+
onActivate: activateSelectedBar
|
|
5315
|
+
});
|
|
4758
5316
|
const comparisonEntries = (0, react.useMemo)(() => {
|
|
4759
5317
|
const primaryByGroup = new Map(primaryEntries.map(({ series, index }) => [series.group, {
|
|
4760
5318
|
label: series.label,
|
|
@@ -4791,7 +5349,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4791
5349
|
const groupPadding = (0, react.useMemo)(() => {
|
|
4792
5350
|
const basePadding = chartOptions.barGroup.padding;
|
|
4793
5351
|
if (!comparisonWidthFactor || comparisonWidthFactor <= 1) return basePadding;
|
|
4794
|
-
const p = 1 -
|
|
5352
|
+
const p = 1 - .9 / comparisonWidthFactor;
|
|
4795
5353
|
return Math.min(Math.max(p, basePadding), MAX_GROUP_PADDING);
|
|
4796
5354
|
}, [chartOptions.barGroup.padding, comparisonWidthFactor]);
|
|
4797
5355
|
const { xScale, yScale } = (0, react.useMemo)(() => {
|
|
@@ -4929,15 +5487,17 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4929
5487
|
chartId
|
|
4930
5488
|
]);
|
|
4931
5489
|
const error = validateData$2(dataSorted);
|
|
5490
|
+
const isDataValid = !error;
|
|
5491
|
+
const chartMetadata = (0, react.useMemo)(() => ({
|
|
5492
|
+
orientation,
|
|
5493
|
+
withPatterns
|
|
5494
|
+
}), [orientation, withPatterns]);
|
|
4932
5495
|
useChartRegistration({
|
|
4933
5496
|
chartId,
|
|
4934
5497
|
legendItems,
|
|
4935
5498
|
chartType: "bar",
|
|
4936
|
-
isDataValid
|
|
4937
|
-
metadata:
|
|
4938
|
-
orientation,
|
|
4939
|
-
withPatterns
|
|
4940
|
-
}), [orientation, withPatterns])
|
|
5499
|
+
isDataValid,
|
|
5500
|
+
metadata: chartMetadata
|
|
4941
5501
|
});
|
|
4942
5502
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
4943
5503
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4991,6 +5551,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
4991
5551
|
onBlur: onChartBlur,
|
|
4992
5552
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4993
5553
|
ref: chartRef,
|
|
5554
|
+
className: xy_plot_module_default["xy-plot"],
|
|
4994
5555
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
4995
5556
|
theme,
|
|
4996
5557
|
width,
|
|
@@ -5002,6 +5563,8 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5002
5563
|
xScale,
|
|
5003
5564
|
yScale,
|
|
5004
5565
|
horizontal,
|
|
5566
|
+
onPointerDown,
|
|
5567
|
+
onPointerUp,
|
|
5005
5568
|
pointerEventsDataKey: "nearest",
|
|
5006
5569
|
children: [
|
|
5007
5570
|
!allSeriesHidden && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_xychart.Grid, {
|
|
@@ -5156,7 +5719,26 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5156
5719
|
right: 20,
|
|
5157
5720
|
bottom: 0,
|
|
5158
5721
|
top: 0
|
|
5159
|
-
}, ...rest }) => {
|
|
5722
|
+
}, className, ...rest }) => {
|
|
5723
|
+
const { getElementStyles } = useGlobalChartsContext();
|
|
5724
|
+
const tintedData = (0, react.useMemo)(() => {
|
|
5725
|
+
if (data.length > 1) return data;
|
|
5726
|
+
return data.map((series, index) => {
|
|
5727
|
+
if (series.options?.stroke) return series;
|
|
5728
|
+
const { color } = getElementStyles({
|
|
5729
|
+
data: series,
|
|
5730
|
+
index
|
|
5731
|
+
});
|
|
5732
|
+
if (!isValidHexColor(color)) return series;
|
|
5733
|
+
return {
|
|
5734
|
+
...series,
|
|
5735
|
+
options: {
|
|
5736
|
+
...series.options,
|
|
5737
|
+
stroke: lightenHexColor(color, .6)
|
|
5738
|
+
}
|
|
5739
|
+
};
|
|
5740
|
+
});
|
|
5741
|
+
}, [data, getElementStyles]);
|
|
5160
5742
|
const chartOptions = (0, react.useMemo)(() => {
|
|
5161
5743
|
const isMultiSeries = data.length > 1;
|
|
5162
5744
|
const defaultYScale = {
|
|
@@ -5189,7 +5771,8 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5189
5771
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarChart, {
|
|
5190
5772
|
orientation: "horizontal",
|
|
5191
5773
|
gridVisibility: "none",
|
|
5192
|
-
|
|
5774
|
+
className: (0, clsx.default)("bar-list-chart", className),
|
|
5775
|
+
data: tintedData,
|
|
5193
5776
|
width,
|
|
5194
5777
|
height,
|
|
5195
5778
|
margin,
|
|
@@ -5225,6 +5808,9 @@ const BarListChartResponsive = withResponsive(BarListChart);
|
|
|
5225
5808
|
var conversion_funnel_chart_module_default = {
|
|
5226
5809
|
"bar-container": "a8ccharts-mGEVca-bar-container",
|
|
5227
5810
|
"change-indicator": "a8ccharts-mGEVca-change-indicator",
|
|
5811
|
+
"change-indicator--negative": "a8ccharts-mGEVca-change-indicator--negative",
|
|
5812
|
+
"change-indicator--positive": "a8ccharts-mGEVca-change-indicator--positive",
|
|
5813
|
+
"conversion-funnel-chart": "a8ccharts-mGEVca-conversion-funnel-chart",
|
|
5228
5814
|
"conversion-funnel-chart--loading": "a8ccharts-mGEVca-conversion-funnel-chart--loading",
|
|
5229
5815
|
"empty-state": "a8ccharts-mGEVca-empty-state",
|
|
5230
5816
|
"funnel-bar": "a8ccharts-mGEVca-funnel-bar",
|
|
@@ -5305,23 +5891,14 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
5305
5891
|
*/
|
|
5306
5892
|
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip }) => {
|
|
5307
5893
|
const chartId = useChartId(providedChartId);
|
|
5308
|
-
const { conversionFunnelChart: conversionFunnelChartSettings } = useGlobalChartsTheme();
|
|
5309
5894
|
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
5310
5895
|
const chartRef = (0, react.useRef)(null);
|
|
5311
5896
|
const selectedBarRef = (0, react.useRef)(null);
|
|
5312
5897
|
const [scopeNode, setScopeNode] = (0, react.useState)(null);
|
|
5313
5898
|
const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
5314
5899
|
const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
|
|
5315
|
-
const
|
|
5316
|
-
detectBounds: true,
|
|
5317
|
-
scroll: true
|
|
5318
|
-
});
|
|
5319
|
-
const portalContainerRefRef = (0, react.useRef)(portalContainerRef);
|
|
5320
|
-
(0, react.useEffect)(() => {
|
|
5321
|
-
portalContainerRefRef.current = portalContainerRef;
|
|
5322
|
-
}, [portalContainerRef]);
|
|
5900
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
5323
5901
|
const setChartRef = (0, react.useCallback)((node) => {
|
|
5324
|
-
portalContainerRefRef.current(node);
|
|
5325
5902
|
chartRef.current = node;
|
|
5326
5903
|
setScopeNode(node);
|
|
5327
5904
|
}, []);
|
|
@@ -5338,30 +5915,22 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5338
5915
|
});
|
|
5339
5916
|
}, [showTooltip]);
|
|
5340
5917
|
const getMouseTooltipCoords = (0, react.useCallback)((event) => {
|
|
5341
|
-
|
|
5918
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5919
|
+
if (!bounds) return null;
|
|
5342
5920
|
return {
|
|
5343
|
-
x: event.clientX -
|
|
5344
|
-
y: event.clientY -
|
|
5921
|
+
x: event.clientX - bounds.left,
|
|
5922
|
+
y: event.clientY - bounds.top
|
|
5345
5923
|
};
|
|
5346
|
-
}, [
|
|
5347
|
-
containerBounds.width,
|
|
5348
|
-
containerBounds.height,
|
|
5349
|
-
containerBounds.left,
|
|
5350
|
-
containerBounds.top
|
|
5351
|
-
]);
|
|
5924
|
+
}, []);
|
|
5352
5925
|
const getKeyboardTooltipCoords = (0, react.useCallback)((event) => {
|
|
5353
|
-
|
|
5926
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5927
|
+
if (!bounds) return null;
|
|
5354
5928
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
5355
5929
|
return {
|
|
5356
|
-
x: rect.left + rect.width / 2 -
|
|
5357
|
-
y: rect.top -
|
|
5930
|
+
x: rect.left + rect.width / 2 - bounds.left,
|
|
5931
|
+
y: rect.top - bounds.top
|
|
5358
5932
|
};
|
|
5359
|
-
}, [
|
|
5360
|
-
containerBounds.width,
|
|
5361
|
-
containerBounds.height,
|
|
5362
|
-
containerBounds.left,
|
|
5363
|
-
containerBounds.top
|
|
5364
|
-
]);
|
|
5933
|
+
}, []);
|
|
5365
5934
|
const handleStepInteraction = (0, react.useCallback)((step, event, interactionType) => {
|
|
5366
5935
|
selectedBarRef.current = event.currentTarget;
|
|
5367
5936
|
const { isClicked } = getStepState(step.id);
|
|
@@ -5422,19 +5991,14 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5422
5991
|
};
|
|
5423
5992
|
}, [clearSelectionAndRef]);
|
|
5424
5993
|
const resolvedHeight = height ?? style?.height ?? "100%";
|
|
5425
|
-
const {
|
|
5426
|
-
const
|
|
5427
|
-
|
|
5428
|
-
overrideColor: primaryColor
|
|
5429
|
-
}) : { color: primaryColor || "#000000" };
|
|
5430
|
-
const changeColor = changeIndicator?.startsWith("+") ? positiveChangeColor : negativeChangeColor;
|
|
5431
|
-
const barBackgroundColor = backgroundColor || hexToRgba(barColor, .08) || "rgba(0, 0, 0, 0.08)";
|
|
5994
|
+
const { color: barColor } = getElementStyles ? getElementStyles({ index: 0 }) : { color: "#000000" };
|
|
5995
|
+
const isPositiveChange = changeIndicator?.startsWith("+");
|
|
5996
|
+
const changeColor = isPositiveChange ? CATALOG_POINTERS.trendUp : CATALOG_POINTERS.trendDown;
|
|
5432
5997
|
const renderDefaultMainMetric = () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5433
5998
|
className: conversion_funnel_chart_module_default["main-rate"],
|
|
5434
5999
|
children: formatPercentage(mainRate)
|
|
5435
6000
|
}), changeIndicator && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5436
|
-
className: conversion_funnel_chart_module_default["change-indicator"],
|
|
5437
|
-
style: { color: changeColor },
|
|
6001
|
+
className: (0, clsx.default)(conversion_funnel_chart_module_default["change-indicator"], conversion_funnel_chart_module_default[isPositiveChange ? "change-indicator--positive" : "change-indicator--negative"]),
|
|
5438
6002
|
children: changeIndicator
|
|
5439
6003
|
})] });
|
|
5440
6004
|
const renderDefaultTooltip = (step) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
@@ -5450,20 +6014,21 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5450
6014
|
})]
|
|
5451
6015
|
});
|
|
5452
6016
|
const isDataValid = Boolean(steps && steps.length > 0);
|
|
6017
|
+
const chartMetadata = (0, react.useMemo)(() => ({
|
|
6018
|
+
mainRate,
|
|
6019
|
+
changeIndicator,
|
|
6020
|
+
stepsCount: steps?.length || 0
|
|
6021
|
+
}), [
|
|
6022
|
+
mainRate,
|
|
6023
|
+
changeIndicator,
|
|
6024
|
+
steps?.length
|
|
6025
|
+
]);
|
|
5453
6026
|
useChartRegistration({
|
|
5454
6027
|
chartId,
|
|
5455
6028
|
legendItems: [],
|
|
5456
6029
|
chartType: "conversion-funnel",
|
|
5457
6030
|
isDataValid,
|
|
5458
|
-
metadata:
|
|
5459
|
-
mainRate,
|
|
5460
|
-
changeIndicator,
|
|
5461
|
-
stepsCount: steps?.length || 0
|
|
5462
|
-
}), [
|
|
5463
|
-
mainRate,
|
|
5464
|
-
changeIndicator,
|
|
5465
|
-
steps?.length
|
|
5466
|
-
])
|
|
6031
|
+
metadata: chartMetadata
|
|
5467
6032
|
});
|
|
5468
6033
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
5469
6034
|
if (!isDataValid) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Stack, {
|
|
@@ -5471,7 +6036,7 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5471
6036
|
align: "center",
|
|
5472
6037
|
justify: "center",
|
|
5473
6038
|
ref: setScopeNode,
|
|
5474
|
-
className: (0, clsx.default)(conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
6039
|
+
className: (0, clsx.default)("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
5475
6040
|
style: {
|
|
5476
6041
|
...style,
|
|
5477
6042
|
height: resolvedHeight
|
|
@@ -5482,16 +6047,16 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5482
6047
|
})
|
|
5483
6048
|
});
|
|
5484
6049
|
const maxRate = Math.max(...steps.map((step) => step.rate));
|
|
5485
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
6050
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
5486
6051
|
direction: "column",
|
|
5487
6052
|
gap: "xl",
|
|
5488
6053
|
ref: setChartRef,
|
|
5489
|
-
className: (0, clsx.default)(conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
6054
|
+
className: (0, clsx.default)("conversion-funnel-chart", conversion_funnel_chart_module_default["conversion-funnel-chart"], loading && conversion_funnel_chart_module_default["conversion-funnel-chart--loading"], className),
|
|
5490
6055
|
style: {
|
|
5491
6056
|
...style,
|
|
5492
6057
|
height: resolvedHeight
|
|
5493
6058
|
},
|
|
5494
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ChartScopeContext.Provider, {
|
|
6059
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ChartScopeContext.Provider, {
|
|
5495
6060
|
value: scopeNode,
|
|
5496
6061
|
children: [renderMainMetric ? renderMainMetric({
|
|
5497
6062
|
mainRate,
|
|
@@ -5543,7 +6108,6 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5543
6108
|
role: "button",
|
|
5544
6109
|
tabIndex: isBlurred ? -1 : 0,
|
|
5545
6110
|
"aria-label": step.label,
|
|
5546
|
-
style: { backgroundColor: barBackgroundColor },
|
|
5547
6111
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5548
6112
|
className: (0, clsx.default)(conversion_funnel_chart_module_default["funnel-bar"], { [conversion_funnel_chart_module_default["funnel-bar--animated"]]: animation && !loading && !prefersReducedMotion }),
|
|
5549
6113
|
style: {
|
|
@@ -5555,23 +6119,23 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5555
6119
|
}, step.id);
|
|
5556
6120
|
})
|
|
5557
6121
|
})]
|
|
5558
|
-
})
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
}
|
|
5574
|
-
})
|
|
6122
|
+
}), tooltipOpen && tooltipData && (() => {
|
|
6123
|
+
const tooltipContent = renderTooltip ? renderTooltip({
|
|
6124
|
+
step: tooltipData,
|
|
6125
|
+
index: steps.findIndex((s) => s.id === tooltipData.id),
|
|
6126
|
+
top: tooltipTop,
|
|
6127
|
+
left: tooltipLeft,
|
|
6128
|
+
className: conversion_funnel_chart_module_default["tooltip-wrapper"]
|
|
6129
|
+
}) : renderDefaultTooltip(tooltipData);
|
|
6130
|
+
if (!tooltipContent) return null;
|
|
6131
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
6132
|
+
top: tooltipTop,
|
|
6133
|
+
left: tooltipLeft,
|
|
6134
|
+
className: (0, clsx.default)(standaloneScopeClass, conversion_funnel_chart_module_default["tooltip-wrapper"]),
|
|
6135
|
+
children: tooltipContent
|
|
6136
|
+
});
|
|
6137
|
+
})()]
|
|
6138
|
+
});
|
|
5575
6139
|
};
|
|
5576
6140
|
/**
|
|
5577
6141
|
* ConversionFunnelChart component with provider wrapper
|
|
@@ -5717,7 +6281,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
5717
6281
|
* @return A React component displaying an interactive map with data visualization
|
|
5718
6282
|
*/
|
|
5719
6283
|
const GeoChartInternal = ({ className, data, width, height, region = "world", resolution = "countries", onError, renderPlaceholder }) => {
|
|
5720
|
-
const { getElementStyles
|
|
6284
|
+
const { getElementStyles } = useGlobalChartsContext();
|
|
5721
6285
|
const scopeElement = useChartScopeElement();
|
|
5722
6286
|
const containerRef = (0, react.useRef)(null);
|
|
5723
6287
|
const reportedErrorIdsRef = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
@@ -5751,8 +6315,8 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5751
6315
|
});
|
|
5752
6316
|
const fullColorHex = getElementStyles({ index: 0 }).color;
|
|
5753
6317
|
const lightColorHex = lightenHexColor(fullColorHex, .8);
|
|
5754
|
-
const backgroundColorHex = normalizeColorToHex(
|
|
5755
|
-
const defaultFillColorHex = normalizeColorToHex(
|
|
6318
|
+
const backgroundColorHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable) || DEFAULT_BACKGROUND_COLOR;
|
|
6319
|
+
const defaultFillColorHex = normalizeColorToHex(CATALOG_POINTERS.surfaceSecondary, scopeElement, resolveCssVariable) || DEFAULT_FEATURE_FILL_COLOR;
|
|
5756
6320
|
const sanitizedData = (0, react.useMemo)(() => {
|
|
5757
6321
|
if (data.length === 0) return {
|
|
5758
6322
|
data,
|
|
@@ -5813,8 +6377,7 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5813
6377
|
className: (0, clsx.default)("geo-chart", geo_chart_module_default.container, className),
|
|
5814
6378
|
style: {
|
|
5815
6379
|
width,
|
|
5816
|
-
height
|
|
5817
|
-
backgroundColor
|
|
6380
|
+
height
|
|
5818
6381
|
},
|
|
5819
6382
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_google_charts.Chart, {
|
|
5820
6383
|
chartType: "GeoChart",
|
|
@@ -5864,6 +6427,7 @@ var heatmap_chart_module_default = {
|
|
|
5864
6427
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
5865
6428
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
5866
6429
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
6430
|
+
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
5867
6431
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
5868
6432
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
5869
6433
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
@@ -6006,7 +6570,7 @@ const HeatmapContext = (0, react.createContext)(null);
|
|
|
6006
6570
|
//#region src/charts/heatmap-chart/private/heatmap-legend.tsx
|
|
6007
6571
|
const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
6008
6572
|
const context = (0, react.useContext)(HeatmapContext);
|
|
6009
|
-
const { legend
|
|
6573
|
+
const { legend } = useGlobalChartsTheme();
|
|
6010
6574
|
if (!context) return null;
|
|
6011
6575
|
const { primaryColorHex } = context;
|
|
6012
6576
|
const labelStyle = legend.labelStyles;
|
|
@@ -6017,6 +6581,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6017
6581
|
children: [
|
|
6018
6582
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6019
6583
|
variant: "body-sm",
|
|
6584
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6020
6585
|
style: labelStyle,
|
|
6021
6586
|
children: lessLabel ?? (0, _wordpress_i18n.__)("Less", "jetpack-charts")
|
|
6022
6587
|
}),
|
|
@@ -6030,7 +6595,6 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6030
6595
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
6031
6596
|
style: {
|
|
6032
6597
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6033
|
-
"--a8c-charts-color-heatmap-background": backgroundColor,
|
|
6034
6598
|
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
6035
6599
|
}
|
|
6036
6600
|
}, index);
|
|
@@ -6038,6 +6602,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6038
6602
|
}),
|
|
6039
6603
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6040
6604
|
variant: "body-sm",
|
|
6605
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6041
6606
|
style: labelStyle,
|
|
6042
6607
|
children: moreLabel ?? (0, _wordpress_i18n.__)("More", "jetpack-charts")
|
|
6043
6608
|
})
|
|
@@ -6055,19 +6620,16 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6055
6620
|
const { nonLegendChildren } = useChartChildren(children, "HeatmapChart");
|
|
6056
6621
|
const [selectedIndex, setSelectedIndex] = (0, react.useState)();
|
|
6057
6622
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
6058
|
-
const
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
});
|
|
6062
|
-
const containerBoundsRef = (0, react.useRef)(containerBounds);
|
|
6063
|
-
containerBoundsRef.current = containerBounds;
|
|
6623
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
6624
|
+
const containerRef = (0, react.useRef)(null);
|
|
6625
|
+
const getTooltipOrigin = (0, react.useCallback)(() => containerRef.current?.closest(`[data-chart-id="heatmap-chart-${chartId}"]`)?.getBoundingClientRect() ?? null, [chartId]);
|
|
6064
6626
|
const { color: primaryColorHex } = getElementStyles({
|
|
6065
6627
|
index: 0,
|
|
6066
|
-
overrideColor: primaryColor
|
|
6628
|
+
overrideColor: primaryColor
|
|
6067
6629
|
});
|
|
6068
|
-
const chartBackgroundHex = normalizeColorToHex(
|
|
6630
|
+
const chartBackgroundHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable);
|
|
6069
6631
|
const primaryHex = normalizeColorToHex(primaryColorHex);
|
|
6070
|
-
const cellHasLightText = (intensity) => isValidHexColor(primaryHex) && isValidHexColor(chartBackgroundHex) && prefersLightText(mixHexColors(primaryHex, chartBackgroundHex, 1 - (CELL_MIX_FLOOR +
|
|
6632
|
+
const cellHasLightText = (intensity) => isValidHexColor(primaryHex) && isValidHexColor(chartBackgroundHex) && prefersLightText(mixHexColors(primaryHex, chartBackgroundHex, 1 - (CELL_MIX_FLOOR + .85 * intensity)));
|
|
6071
6633
|
const extent = (0, react.useMemo)(() => getValueExtent(data), [data]);
|
|
6072
6634
|
const heatmapContext = (0, react.useMemo)(() => ({
|
|
6073
6635
|
extent,
|
|
@@ -6141,19 +6703,21 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6141
6703
|
]);
|
|
6142
6704
|
const handleCellMouseMove = (0, react.useCallback)((event) => {
|
|
6143
6705
|
if (!withTooltips) return;
|
|
6706
|
+
const origin = getTooltipOrigin();
|
|
6707
|
+
if (!origin) return;
|
|
6144
6708
|
const target = event.currentTarget;
|
|
6145
6709
|
const columnIndex = Number(target.dataset.column);
|
|
6146
6710
|
const rowIndex = Number(target.dataset.row);
|
|
6147
|
-
const bounds = containerBoundsRef.current;
|
|
6148
6711
|
showTooltip({
|
|
6149
|
-
tooltipLeft: event.clientX -
|
|
6150
|
-
tooltipTop: event.clientY -
|
|
6712
|
+
tooltipLeft: event.clientX - origin.left,
|
|
6713
|
+
tooltipTop: event.clientY - origin.top,
|
|
6151
6714
|
tooltipData: buildTooltipData(columnIndex, rowIndex)
|
|
6152
6715
|
});
|
|
6153
6716
|
}, [
|
|
6154
6717
|
withTooltips,
|
|
6155
6718
|
showTooltip,
|
|
6156
|
-
buildTooltipData
|
|
6719
|
+
buildTooltipData,
|
|
6720
|
+
getTooltipOrigin
|
|
6157
6721
|
]);
|
|
6158
6722
|
const handleCellMouseLeave = (0, react.useCallback)(() => {
|
|
6159
6723
|
if (withTooltips && selectedIndex === void 0) hideTooltip();
|
|
@@ -6164,13 +6728,14 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6164
6728
|
]);
|
|
6165
6729
|
(0, react.useEffect)(() => {
|
|
6166
6730
|
if (!withTooltips || selectedIndex === void 0) return;
|
|
6731
|
+
const origin = getTooltipOrigin();
|
|
6732
|
+
if (!origin) return;
|
|
6167
6733
|
const col = Math.floor(selectedIndex / rows);
|
|
6168
6734
|
const row = selectedIndex % rows;
|
|
6169
6735
|
const rect = (typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null)?.getBoundingClientRect();
|
|
6170
|
-
const bounds = containerBoundsRef.current;
|
|
6171
6736
|
showTooltip({
|
|
6172
|
-
tooltipLeft: rect ? rect.left + rect.width / 2 -
|
|
6173
|
-
tooltipTop: rect ? rect.top + rect.height / 2 -
|
|
6737
|
+
tooltipLeft: rect ? rect.left + rect.width / 2 - origin.left : 0,
|
|
6738
|
+
tooltipTop: rect ? rect.top + rect.height / 2 - origin.top : 0,
|
|
6174
6739
|
tooltipData: buildTooltipData(col, row)
|
|
6175
6740
|
});
|
|
6176
6741
|
}, [
|
|
@@ -6179,7 +6744,8 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6179
6744
|
rows,
|
|
6180
6745
|
chartId,
|
|
6181
6746
|
buildTooltipData,
|
|
6182
|
-
showTooltip
|
|
6747
|
+
showTooltip,
|
|
6748
|
+
getTooltipOrigin
|
|
6183
6749
|
]);
|
|
6184
6750
|
const defaultRenderTooltip = (0, react.useCallback)((info) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: info.cellLabel || `${info.columnLabel ?? ""} ${info.rowLabel ?? ""}`.trim() }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: info.value === null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(info.value) })] }), []);
|
|
6185
6751
|
if (!columns || !rows) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Center, {
|
|
@@ -6197,7 +6763,6 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6197
6763
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
6198
6764
|
const gridStyle = {
|
|
6199
6765
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6200
|
-
"--a8c-charts-color-heatmap-background": theme.backgroundColor,
|
|
6201
6766
|
gridTemplateColumns: `auto repeat(${columns}, ${columnTrack})`,
|
|
6202
6767
|
gridTemplateRows: `auto repeat(${rows}, ${rowTrack})`
|
|
6203
6768
|
};
|
|
@@ -6295,11 +6860,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6295
6860
|
})]
|
|
6296
6861
|
}, `row-${rowIndex}`);
|
|
6297
6862
|
})]
|
|
6298
|
-
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
6863
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
6299
6864
|
top: tooltipTop,
|
|
6300
6865
|
left: tooltipLeft,
|
|
6301
6866
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6302
|
-
className:
|
|
6867
|
+
className: standaloneScopeClass,
|
|
6303
6868
|
role: "tooltip",
|
|
6304
6869
|
tabIndex: -1,
|
|
6305
6870
|
children: (renderTooltip ?? defaultRenderTooltip)(tooltipData)
|
|
@@ -6323,7 +6888,7 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ (0, react_jsx_run
|
|
|
6323
6888
|
HeatmapChartResponsiveInner.displayName = "HeatmapChart";
|
|
6324
6889
|
const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
|
|
6325
6890
|
//#endregion
|
|
6326
|
-
//#region ../../../node_modules/.pnpm/is-plain-object@5.
|
|
6891
|
+
//#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
|
|
6327
6892
|
/*!
|
|
6328
6893
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
6329
6894
|
*
|
|
@@ -6686,7 +7251,7 @@ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6686
7251
|
tslib_1.__exportStar(require_dist$1(), exports);
|
|
6687
7252
|
}));
|
|
6688
7253
|
//#endregion
|
|
6689
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
7254
|
+
//#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
|
|
6690
7255
|
function useUpdateEffect(effect, deps) {
|
|
6691
7256
|
const mountedRef = (0, react.useRef)(false);
|
|
6692
7257
|
(0, react.useEffect)(() => {
|
|
@@ -6718,10 +7283,11 @@ var StyleSheet = /*#__PURE__*/ function() {
|
|
|
6718
7283
|
var _this = this;
|
|
6719
7284
|
this._insertTag = function(tag) {
|
|
6720
7285
|
var before;
|
|
6721
|
-
if (_this.tags.length === 0)
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
7286
|
+
if (_this.tags.length === 0) {
|
|
7287
|
+
if (_this.insertionPoint) before = _this.insertionPoint.nextSibling;
|
|
7288
|
+
else if (_this.prepend) before = _this.container.firstChild;
|
|
7289
|
+
else before = _this.before;
|
|
7290
|
+
} else before = _this.tags[_this.tags.length - 1].nextSibling;
|
|
6725
7291
|
_this.container.insertBefore(tag, before);
|
|
6726
7292
|
_this.tags.push(tag);
|
|
6727
7293
|
};
|
|
@@ -7040,9 +7606,7 @@ function delimiter(type) {
|
|
|
7040
7606
|
case 40:
|
|
7041
7607
|
if (type === 41) delimiter(type);
|
|
7042
7608
|
break;
|
|
7043
|
-
case 92:
|
|
7044
|
-
next();
|
|
7045
|
-
break;
|
|
7609
|
+
case 92: next();
|
|
7046
7610
|
}
|
|
7047
7611
|
return position;
|
|
7048
7612
|
}
|
|
@@ -8065,14 +8629,12 @@ function handleInterpolation(mergedProps, registered, interpolation) {
|
|
|
8065
8629
|
return serializedStyles.styles + ";";
|
|
8066
8630
|
}
|
|
8067
8631
|
return createStringFromObject(mergedProps, registered, interpolation);
|
|
8068
|
-
case "function":
|
|
8069
|
-
|
|
8070
|
-
|
|
8071
|
-
|
|
8072
|
-
|
|
8073
|
-
|
|
8074
|
-
}
|
|
8075
|
-
break;
|
|
8632
|
+
case "function": if (mergedProps !== void 0) {
|
|
8633
|
+
var previousCursor = cursor;
|
|
8634
|
+
var result = interpolation(mergedProps);
|
|
8635
|
+
cursor = previousCursor;
|
|
8636
|
+
return handleInterpolation(mergedProps, registered, result);
|
|
8637
|
+
}
|
|
8076
8638
|
}
|
|
8077
8639
|
var asString = interpolation;
|
|
8078
8640
|
if (registered == null) return asString;
|
|
@@ -8327,7 +8889,7 @@ _createEmotion.css;
|
|
|
8327
8889
|
_createEmotion.sheet;
|
|
8328
8890
|
_createEmotion.cache;
|
|
8329
8891
|
//#endregion
|
|
8330
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8892
|
+
//#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
|
|
8331
8893
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
8332
8894
|
var useCx = () => {
|
|
8333
8895
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -8434,7 +8996,7 @@ function memize(fn, options) {
|
|
|
8434
8996
|
return memoized;
|
|
8435
8997
|
}
|
|
8436
8998
|
//#endregion
|
|
8437
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
8999
|
+
//#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
|
|
8438
9000
|
var white = "#fff";
|
|
8439
9001
|
var GRAY = {
|
|
8440
9002
|
900: "#1e1e1e",
|
|
@@ -8513,7 +9075,7 @@ var COLORS = Object.freeze({
|
|
|
8513
9075
|
ui: UI
|
|
8514
9076
|
});
|
|
8515
9077
|
//#endregion
|
|
8516
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9078
|
+
//#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
|
|
8517
9079
|
var CONTROL_HEIGHT = "36px";
|
|
8518
9080
|
var CONTROL_PROPS = {
|
|
8519
9081
|
controlPaddingX: 12,
|
|
@@ -8528,9 +9090,6 @@ var CONTROL_PROPS = {
|
|
|
8528
9090
|
};
|
|
8529
9091
|
var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
8530
9092
|
colorDivider: "rgba(0, 0, 0, 0.1)",
|
|
8531
|
-
colorScrollbarThumb: "rgba(0, 0, 0, 0.2)",
|
|
8532
|
-
colorScrollbarThumbHover: "rgba(0, 0, 0, 0.5)",
|
|
8533
|
-
colorScrollbarTrack: "rgba(0, 0, 0, 0.04)",
|
|
8534
9093
|
elevationIntensity: 1,
|
|
8535
9094
|
radiusXSmall: "1px",
|
|
8536
9095
|
radiusSmall: "2px",
|
|
@@ -8541,7 +9100,6 @@ var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
|
8541
9100
|
borderWidth: "1px",
|
|
8542
9101
|
borderWidthFocus: "1.5px",
|
|
8543
9102
|
borderWidthTab: "4px",
|
|
8544
|
-
spinnerSize: 16,
|
|
8545
9103
|
fontSize: "13px",
|
|
8546
9104
|
fontSizeH1: "calc(2.44 * 13px)",
|
|
8547
9105
|
fontSizeH2: "calc(1.95 * 13px)",
|
|
@@ -8618,10 +9176,10 @@ var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
8618
9176
|
};
|
|
8619
9177
|
}));
|
|
8620
9178
|
//#endregion
|
|
8621
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.
|
|
9179
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/utils.mjs
|
|
8622
9180
|
var logged = /* @__PURE__ */ new Set();
|
|
8623
9181
|
//#endregion
|
|
8624
|
-
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.
|
|
9182
|
+
//#region ../../../node_modules/.pnpm/@wordpress+warning@3.54.0/node_modules/@wordpress/warning/build-module/index.mjs
|
|
8625
9183
|
function isDev() {
|
|
8626
9184
|
return globalThis.SCRIPT_DEBUG === true;
|
|
8627
9185
|
}
|
|
@@ -8635,7 +9193,7 @@ function warning(message) {
|
|
|
8635
9193
|
logged.add(message);
|
|
8636
9194
|
}
|
|
8637
9195
|
//#endregion
|
|
8638
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9196
|
+
//#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
|
|
8639
9197
|
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
8640
9198
|
var ComponentsContext = (0, react.createContext)(
|
|
8641
9199
|
/** @type {Record<string, any>} */
|
|
@@ -8662,19 +9220,19 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
8662
9220
|
};
|
|
8663
9221
|
(0, react.memo)(BaseContextSystemProvider);
|
|
8664
9222
|
//#endregion
|
|
8665
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9223
|
+
//#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
|
|
8666
9224
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
8667
9225
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
8668
9226
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
8669
9227
|
//#endregion
|
|
8670
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9228
|
+
//#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
|
|
8671
9229
|
var import_dist = require_dist();
|
|
8672
9230
|
function getStyledClassName(namespace) {
|
|
8673
9231
|
return `components-${(0, import_dist.paramCase)(namespace)}`;
|
|
8674
9232
|
}
|
|
8675
9233
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
8676
9234
|
//#endregion
|
|
8677
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9235
|
+
//#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
|
|
8678
9236
|
function contextConnect(Component, namespace) {
|
|
8679
9237
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
8680
9238
|
}
|
|
@@ -8691,7 +9249,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
8691
9249
|
});
|
|
8692
9250
|
}
|
|
8693
9251
|
//#endregion
|
|
8694
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9252
|
+
//#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
|
|
8695
9253
|
function getNamespace(componentName) {
|
|
8696
9254
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
8697
9255
|
}
|
|
@@ -8699,7 +9257,7 @@ function getConnectedNamespace() {
|
|
|
8699
9257
|
return { [CONNECTED_NAMESPACE]: true };
|
|
8700
9258
|
}
|
|
8701
9259
|
//#endregion
|
|
8702
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9260
|
+
//#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
|
|
8703
9261
|
function useContextSystem(props, namespace) {
|
|
8704
9262
|
const contextSystemProps = useComponentsContext();
|
|
8705
9263
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -8719,7 +9277,7 @@ function useContextSystem(props, namespace) {
|
|
|
8719
9277
|
return finalComponentProps;
|
|
8720
9278
|
}
|
|
8721
9279
|
//#endregion
|
|
8722
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9280
|
+
//#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
|
|
8723
9281
|
var visuallyHidden = {
|
|
8724
9282
|
border: 0,
|
|
8725
9283
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -8735,7 +9293,7 @@ var visuallyHidden = {
|
|
|
8735
9293
|
wordBreak: "normal"
|
|
8736
9294
|
};
|
|
8737
9295
|
//#endregion
|
|
8738
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9296
|
+
//#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
|
|
8739
9297
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
8740
9298
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
8741
9299
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -8817,14 +9375,15 @@ function filterIntrinsicElementProps(props, element) {
|
|
|
8817
9375
|
}
|
|
8818
9376
|
function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
8819
9377
|
const Element = as || "div";
|
|
9378
|
+
const forwardedProps = typeof Element === "string" ? filterIntrinsicElementProps(props, Element) : props;
|
|
8820
9379
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Element, {
|
|
8821
9380
|
ref,
|
|
8822
|
-
...
|
|
9381
|
+
...forwardedProps
|
|
8823
9382
|
});
|
|
8824
9383
|
}
|
|
8825
9384
|
var PolymorphicElement = (0, react.forwardRef)(UnforwardedPolymorphicElement);
|
|
8826
9385
|
//#endregion
|
|
8827
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9386
|
+
//#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
|
|
8828
9387
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
8829
9388
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PolymorphicElement, {
|
|
8830
9389
|
ref,
|
|
@@ -8833,7 +9392,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
8833
9392
|
}
|
|
8834
9393
|
var component_default$2 = Object.assign((0, react.forwardRef)(UnforwardedView), { selector: ".components-view" });
|
|
8835
9394
|
//#endregion
|
|
8836
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9395
|
+
//#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
|
|
8837
9396
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
8838
9397
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
8839
9398
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
@@ -8848,7 +9407,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
8848
9407
|
}
|
|
8849
9408
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
8850
9409
|
//#endregion
|
|
8851
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9410
|
+
//#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
|
|
8852
9411
|
var breakpoints = [
|
|
8853
9412
|
"40em",
|
|
8854
9413
|
"52em",
|
|
@@ -8882,7 +9441,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
8882
9441
|
return array[index >= array.length ? array.length - 1 : index];
|
|
8883
9442
|
}
|
|
8884
9443
|
//#endregion
|
|
8885
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9444
|
+
//#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
|
|
8886
9445
|
var ALIGNMENTS = {
|
|
8887
9446
|
bottom: {
|
|
8888
9447
|
alignItems: "flex-end",
|
|
@@ -8930,7 +9489,7 @@ function getAlignmentProps(alignment) {
|
|
|
8930
9489
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
8931
9490
|
}
|
|
8932
9491
|
//#endregion
|
|
8933
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9492
|
+
//#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
|
|
8934
9493
|
function useGrid(props) {
|
|
8935
9494
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
8936
9495
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -8951,7 +9510,7 @@ function useGrid(props) {
|
|
|
8951
9510
|
justifyContent: justify,
|
|
8952
9511
|
verticalAlign: isInline ? "middle" : void 0,
|
|
8953
9512
|
...alignmentProps
|
|
8954
|
-
}, process.env.NODE_ENV === "production" ? "" : ";label:gridClasses;", process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
9513
|
+
}, process.env.NODE_ENV === "production" ? "" : ";label:gridClasses;", process.env.NODE_ENV === "production" ? "" : "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImhvb2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBNENzQiIsImZpbGUiOiJob29rLnRzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3NzIH0gZnJvbSAnQGVtb3Rpb24vcmVhY3QnO1xuaW1wb3J0IHsgdXNlTWVtbyB9IGZyb20gJ0B3b3JkcHJlc3MvZWxlbWVudCc7XG5pbXBvcnQgdHlwZSB7IFdvcmRQcmVzc0NvbXBvbmVudFByb3BzIH0gZnJvbSAnLi4vY29udGV4dCc7XG5pbXBvcnQgeyB1c2VDb250ZXh0U3lzdGVtIH0gZnJvbSAnLi4vY29udGV4dCc7XG5pbXBvcnQgeyBnZXRBbGlnbm1lbnRQcm9wcyB9IGZyb20gJy4vdXRpbHMnO1xuaW1wb3J0IHsgdXNlUmVzcG9uc2l2ZVZhbHVlIH0gZnJvbSAnLi4vdXRpbHMvdXNlLXJlc3BvbnNpdmUtdmFsdWUnO1xuaW1wb3J0IENPTkZJRyBmcm9tICcuLi91dGlscy9jb25maWctdmFsdWVzJztcbmltcG9ydCB7IHVzZUN4IH0gZnJvbSAnLi4vdXRpbHMvaG9va3MvdXNlLWN4JztcbmltcG9ydCB0eXBlIHsgR3JpZFByb3BzIH0gZnJvbSAnLi90eXBlcyc7XG5cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVzZUdyaWQoXG5cdHByb3BzOiBXb3JkUHJlc3NDb21wb25lbnRQcm9wczwgR3JpZFByb3BzLCAnZGl2JyA+XG4pIHtcblx0Y29uc3Qge1xuXHRcdGFsaWduLFxuXHRcdGFsaWdubWVudCxcblx0XHRjbGFzc05hbWUsXG5cdFx0Y29sdW1uR2FwLFxuXHRcdGNvbHVtbnMgPSAyLFxuXHRcdGdhcCA9IDMsXG5cdFx0aXNJbmxpbmUgPSBmYWxzZSxcblx0XHRqdXN0aWZ5LFxuXHRcdHJvd0dhcCxcblx0XHRyb3dzLFxuXHRcdHRlbXBsYXRlQ29sdW1ucyxcblx0XHR0ZW1wbGF0ZVJvd3MsXG5cdFx0Li4ub3RoZXJQcm9wc1xuXHR9ID0gdXNlQ29udGV4dFN5c3RlbSggcHJvcHMsICdHcmlkJyApO1xuXG5cdGNvbnN0IGNvbHVtbnNBc0FycmF5ID0gQXJyYXkuaXNBcnJheSggY29sdW1ucyApID8gY29sdW1ucyA6IFsgY29sdW1ucyBdO1xuXHRjb25zdCBjb2x1bW4gPSB1c2VSZXNwb25zaXZlVmFsdWUoIGNvbHVtbnNBc0FycmF5ICk7XG5cdGNvbnN0IHJvd3NBc0FycmF5ID0gQXJyYXkuaXNBcnJheSggcm93cyApID8gcm93cyA6IFsgcm93cyBdO1xuXHRjb25zdCByb3cgPSB1c2VSZXNwb25zaXZlVmFsdWUoIHJvd3NBc0FycmF5ICk7XG5cblx0Y29uc3QgZ3JpZFRlbXBsYXRlQ29sdW1ucyA9XG5cdFx0dGVtcGxhdGVDb2x1bW5zIHx8ICggISEgY29sdW1ucyAmJiBgcmVwZWF0KCAkeyBjb2x1bW4gfSwgMWZyIClgICk7XG5cdGNvbnN0IGdyaWRUZW1wbGF0ZVJvd3MgPVxuXHRcdHRlbXBsYXRlUm93cyB8fCAoICEhIHJvd3MgJiYgYHJlcGVhdCggJHsgcm93IH0sIDFmciApYCApO1xuXG5cdGNvbnN0IGN4ID0gdXNlQ3goKTtcblxuXHRjb25zdCBjbGFzc2VzID0gdXNlTWVtbyggKCkgPT4ge1xuXHRcdGNvbnN0IGFsaWdubWVudFByb3BzID0gZ2V0QWxpZ25tZW50UHJvcHMoIGFsaWdubWVudCApO1xuXG5cdFx0Y29uc3QgZ3JpZENsYXNzZXMgPSBjc3MoIHtcblx0XHRcdGFsaWduSXRlbXM6IGFsaWduLFxuXHRcdFx0ZGlzcGxheTogaXNJbmxpbmUgPyAnaW5saW5lLWdyaWQnIDogJ2dyaWQnLFxuXHRcdFx0Z2FwOiBgY2FsYyggJHsgQ09ORklHLmdyaWRCYXNlIH0gKiAkeyBnYXAgfSApYCxcblx0XHRcdGdyaWRUZW1wbGF0ZUNvbHVtbnM6IGdyaWRUZW1wbGF0ZUNvbHVtbnMgfHwgdW5kZWZpbmVkLFxuXHRcdFx0Z3JpZFRlbXBsYXRlUm93czogZ3JpZFRlbXBsYXRlUm93cyB8fCB1bmRlZmluZWQsXG5cdFx0XHRncmlkUm93R2FwOiByb3dHYXAsXG5cdFx0XHRncmlkQ29sdW1uR2FwOiBjb2x1bW5HYXAsXG5cdFx0XHRqdXN0aWZ5Q29udGVudDoganVzdGlmeSxcblx0XHRcdHZlcnRpY2FsQWxpZ246IGlzSW5saW5lID8gJ21pZGRsZScgOiB1bmRlZmluZWQsXG5cdFx0XHQuLi5hbGlnbm1lbnRQcm9wcyxcblx0XHR9ICk7XG5cblx0XHRyZXR1cm4gY3goIGdyaWRDbGFzc2VzLCBjbGFzc05hbWUgKTtcblx0fSwgW1xuXHRcdGFsaWduLFxuXHRcdGFsaWdubWVudCxcblx0XHRjbGFzc05hbWUsXG5cdFx0Y29sdW1uR2FwLFxuXHRcdGN4LFxuXHRcdGdhcCxcblx0XHRncmlkVGVtcGxhdGVDb2x1bW5zLFxuXHRcdGdyaWRUZW1wbGF0ZVJvd3MsXG5cdFx0aXNJbmxpbmUsXG5cdFx0anVzdGlmeSxcblx0XHRyb3dHYXAsXG5cdF0gKTtcblxuXHRyZXR1cm4geyAuLi5vdGhlclByb3BzLCBjbGFzc05hbWU6IGNsYXNzZXMgfTtcbn1cbiJdfQ== */");
|
|
8955
9514
|
return cx(gridClasses, className);
|
|
8956
9515
|
}, [
|
|
8957
9516
|
align,
|
|
@@ -8972,10 +9531,11 @@ function useGrid(props) {
|
|
|
8972
9531
|
};
|
|
8973
9532
|
}
|
|
8974
9533
|
//#endregion
|
|
8975
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@
|
|
9534
|
+
//#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
|
|
8976
9535
|
function UnconnectedGrid(props, forwardedRef) {
|
|
9536
|
+
const gridProps = useGrid(props);
|
|
8977
9537
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
8978
|
-
...
|
|
9538
|
+
...gridProps,
|
|
8979
9539
|
ref: forwardedRef
|
|
8980
9540
|
});
|
|
8981
9541
|
}
|
|
@@ -8994,8 +9554,8 @@ const SUBPIXEL_TOLERANCE = .5;
|
|
|
8994
9554
|
* Counts how many leading rows fit inside the content container.
|
|
8995
9555
|
*
|
|
8996
9556
|
* Rows are read from the DOM rather than derived from constants: row height
|
|
8997
|
-
* depends on
|
|
8998
|
-
* as a label, so any restated number would drift.
|
|
9557
|
+
* depends on `--a8c-charts-dimension-leaderboard-row-gap`, label wrapping, and
|
|
9558
|
+
* whatever a caller renders as a label, so any restated number would drift.
|
|
8999
9559
|
*
|
|
9000
9560
|
* Every row is a direct grid child marked with `data-row-index`; interactive rows
|
|
9001
9561
|
* use a button wrapper and non-interactive rows use a div wrapper.
|
|
@@ -9080,14 +9640,13 @@ function useFittedRowCount(enabled, rowCount, data) {
|
|
|
9080
9640
|
* @return Array of legend items for the leaderboard chart
|
|
9081
9641
|
*/
|
|
9082
9642
|
function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withComparison = false, withOverlayLabel = false, legendLabels }) {
|
|
9083
|
-
const { leaderboardChart: leaderboardChartSettings } = useGlobalChartsTheme();
|
|
9084
9643
|
const { getElementStyles } = useGlobalChartsContext();
|
|
9085
9644
|
return (0, react.useMemo)(() => {
|
|
9086
9645
|
if (!data || data.length === 0) return [];
|
|
9087
9646
|
const items = [];
|
|
9088
9647
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
9089
9648
|
index: 0,
|
|
9090
|
-
overrideColor: primaryColor
|
|
9649
|
+
overrideColor: primaryColor
|
|
9091
9650
|
});
|
|
9092
9651
|
items.push({
|
|
9093
9652
|
label: legendLabels?.primary || (0, _wordpress_i18n.__)("Current period", "jetpack-charts"),
|
|
@@ -9096,7 +9655,7 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
9096
9655
|
if (withComparison && !withOverlayLabel) {
|
|
9097
9656
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
9098
9657
|
index: 1,
|
|
9099
|
-
overrideColor: secondaryColor
|
|
9658
|
+
overrideColor: secondaryColor
|
|
9100
9659
|
});
|
|
9101
9660
|
items.push({
|
|
9102
9661
|
label: legendLabels?.comparison || (0, _wordpress_i18n.__)("Previous period", "jetpack-charts"),
|
|
@@ -9110,7 +9669,6 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
9110
9669
|
secondaryColor,
|
|
9111
9670
|
withComparison,
|
|
9112
9671
|
legendLabels,
|
|
9113
|
-
leaderboardChartSettings,
|
|
9114
9672
|
getElementStyles,
|
|
9115
9673
|
withOverlayLabel
|
|
9116
9674
|
]);
|
|
@@ -9124,6 +9682,9 @@ var leaderboard_chart_module_default = {
|
|
|
9124
9682
|
"chevron": "a8ccharts-GovfoW-chevron",
|
|
9125
9683
|
"deltaPlaceholder": "a8ccharts-GovfoW-deltaPlaceholder",
|
|
9126
9684
|
"deltaValue": "a8ccharts-GovfoW-deltaValue",
|
|
9685
|
+
"deltaValue--down": "a8ccharts-GovfoW-deltaValue--down",
|
|
9686
|
+
"deltaValue--neutral": "a8ccharts-GovfoW-deltaValue--neutral",
|
|
9687
|
+
"deltaValue--up": "a8ccharts-GovfoW-deltaValue--up",
|
|
9127
9688
|
"emptyState": "a8ccharts-GovfoW-emptyState",
|
|
9128
9689
|
"fitEmptyState": "a8ccharts-GovfoW-fitEmptyState",
|
|
9129
9690
|
"interactiveRow": "a8ccharts-GovfoW-interactiveRow",
|
|
@@ -9142,6 +9703,14 @@ var leaderboard_chart_module_default = {
|
|
|
9142
9703
|
};
|
|
9143
9704
|
//#endregion
|
|
9144
9705
|
//#region src/charts/leaderboard-chart/leaderboard-chart.tsx
|
|
9706
|
+
const ROW_GAP = "var(--a8c-charts-dimension-leaderboard-row-gap, 12px)";
|
|
9707
|
+
const COLUMN_GAP = "var(--a8c-charts-dimension-leaderboard-column-gap, 4px)";
|
|
9708
|
+
/** Indexed by `Math.sign( delta ) + 1`, so [negative, neutral, positive]. */
|
|
9709
|
+
const DELTA_TREND_CLASS = [
|
|
9710
|
+
"deltaValue--down",
|
|
9711
|
+
"deltaValue--neutral",
|
|
9712
|
+
"deltaValue--up"
|
|
9713
|
+
];
|
|
9145
9714
|
/**
|
|
9146
9715
|
* Default value formatter using formatMetricValue
|
|
9147
9716
|
*
|
|
@@ -9244,15 +9813,15 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9244
9813
|
...legend.shapeStyles
|
|
9245
9814
|
};
|
|
9246
9815
|
const { legendChildren, nonLegendChildren } = useChartChildren(children, "LeaderboardChart");
|
|
9247
|
-
const { labelSpacing
|
|
9816
|
+
const { labelSpacing } = leaderboardChartSettings;
|
|
9248
9817
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
9249
9818
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
9250
9819
|
index: 0,
|
|
9251
|
-
overrideColor: primaryColor
|
|
9820
|
+
overrideColor: primaryColor
|
|
9252
9821
|
});
|
|
9253
9822
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
9254
9823
|
index: 1,
|
|
9255
|
-
overrideColor: secondaryColor
|
|
9824
|
+
overrideColor: secondaryColor
|
|
9256
9825
|
});
|
|
9257
9826
|
const legendItems = useLeaderboardLegendItems({
|
|
9258
9827
|
data: data || [],
|
|
@@ -9287,15 +9856,17 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9287
9856
|
withComparison,
|
|
9288
9857
|
withOverlayLabel
|
|
9289
9858
|
]);
|
|
9859
|
+
const isDataValid = Boolean(data && data.length > 0);
|
|
9860
|
+
const chartMetadata = (0, react.useMemo)(() => ({
|
|
9861
|
+
withComparison,
|
|
9862
|
+
withOverlayLabel
|
|
9863
|
+
}), [withComparison, withOverlayLabel]);
|
|
9290
9864
|
useChartRegistration({
|
|
9291
9865
|
chartId,
|
|
9292
9866
|
legendItems,
|
|
9293
9867
|
chartType: "leaderboard",
|
|
9294
|
-
isDataValid
|
|
9295
|
-
metadata:
|
|
9296
|
-
withComparison,
|
|
9297
|
-
withOverlayLabel
|
|
9298
|
-
}), [withComparison, withOverlayLabel])
|
|
9868
|
+
isDataValid,
|
|
9869
|
+
metadata: chartMetadata
|
|
9299
9870
|
});
|
|
9300
9871
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
9301
9872
|
const { contentRef, fittedCount, isMeasurable } = useFittedRowCount(fitRows && !allSeriesHidden, data?.length ?? 0, data);
|
|
@@ -9306,7 +9877,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9306
9877
|
legendPosition,
|
|
9307
9878
|
legendElement: false,
|
|
9308
9879
|
legendChildren,
|
|
9309
|
-
className: (0, clsx.default)(leaderboard_chart_module_default.leaderboardChart, {
|
|
9880
|
+
className: (0, clsx.default)("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
9310
9881
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
9311
9882
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
9312
9883
|
}, className),
|
|
@@ -9341,7 +9912,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9341
9912
|
legendPosition,
|
|
9342
9913
|
legendElement,
|
|
9343
9914
|
legendChildren,
|
|
9344
|
-
className: (0, clsx.default)(leaderboard_chart_module_default.leaderboardChart, {
|
|
9915
|
+
className: (0, clsx.default)("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
9345
9916
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
9346
9917
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
9347
9918
|
}, className),
|
|
@@ -9363,8 +9934,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9363
9934
|
children: getAllHiddenMessage(legendInteractive, "series")
|
|
9364
9935
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default, {
|
|
9365
9936
|
templateColumns: "minmax(0, 1fr) auto",
|
|
9366
|
-
rowGap,
|
|
9367
|
-
columnGap,
|
|
9937
|
+
rowGap: ROW_GAP,
|
|
9938
|
+
columnGap: COLUMN_GAP,
|
|
9368
9939
|
"data-leaderboard-grid": true,
|
|
9369
9940
|
children: data.map((entry, rowIndex) => {
|
|
9370
9941
|
const rowStyle = shouldFitRows && rowIndex >= fittedCount ? { visibility: "hidden" } : void 0;
|
|
@@ -9373,8 +9944,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9373
9944
|
const hasDelta = hasDeltaValue(entry);
|
|
9374
9945
|
const showComparisonValue = showComparisonColumn && hasDelta;
|
|
9375
9946
|
const showComparisonPlaceholder = showComparisonColumn && !hasDelta;
|
|
9376
|
-
const
|
|
9377
|
-
const deltaColor = deltaColors[colorIndex];
|
|
9947
|
+
const deltaTrendClass = leaderboard_chart_module_default[DELTA_TREND_CLASS[showComparisonValue ? Math.sign(entry.delta) + 1 : 1]];
|
|
9378
9948
|
const rowCells = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Stack, {
|
|
9379
9949
|
direction: "column",
|
|
9380
9950
|
gap: labelSpacing,
|
|
@@ -9395,13 +9965,11 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9395
9965
|
children: [
|
|
9396
9966
|
isPrimaryVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, { children: valueFormatter(entry.currentValue) }),
|
|
9397
9967
|
showComparisonValue && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
9398
|
-
className: leaderboard_chart_module_default.deltaValue,
|
|
9399
|
-
style: { color: deltaColor },
|
|
9968
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.deltaValue, deltaTrendClass),
|
|
9400
9969
|
children: deltaFormatter(entry.delta)
|
|
9401
9970
|
}),
|
|
9402
9971
|
showComparisonPlaceholder && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Text, {
|
|
9403
|
-
className: (0, clsx.default)(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder),
|
|
9404
|
-
style: { color: deltaColor },
|
|
9972
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder, deltaTrendClass),
|
|
9405
9973
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9406
9974
|
"aria-hidden": "true",
|
|
9407
9975
|
children: "—"
|
|
@@ -9485,7 +10053,9 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
|
|
|
9485
10053
|
//#endregion
|
|
9486
10054
|
//#region src/charts/pie-chart/pie-chart.module.scss
|
|
9487
10055
|
var pie_chart_module_default = {
|
|
9488
|
-
"pie-
|
|
10056
|
+
"pie-chart__label-plate": "a8ccharts-gnszbG-pie-chart__label-plate",
|
|
10057
|
+
"pie-chart__label-text": "a8ccharts-gnszbG-pie-chart__label-text",
|
|
10058
|
+
"pie-chart__plot": "a8ccharts-gnszbG-pie-chart__plot",
|
|
9489
10059
|
"pie-chart--responsive": "a8ccharts-gnszbG-pie-chart--responsive"
|
|
9490
10060
|
};
|
|
9491
10061
|
//#endregion
|
|
@@ -9540,18 +10110,16 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9540
10110
|
const providerTheme = useGlobalChartsTheme();
|
|
9541
10111
|
const chartId = useChartId(providedChartId);
|
|
9542
10112
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
9543
|
-
const
|
|
9544
|
-
|
|
9545
|
-
scroll: true,
|
|
9546
|
-
debounce: 0
|
|
9547
|
-
});
|
|
10113
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
10114
|
+
const containerRef = (0, react.useRef)(null);
|
|
9548
10115
|
const onMouseLeave = (0, react.useCallback)(() => {
|
|
9549
10116
|
if (!withTooltips) return;
|
|
9550
10117
|
hideTooltip();
|
|
9551
10118
|
}, [withTooltips, hideTooltip]);
|
|
9552
10119
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
10120
|
+
const dataWithPercentages = useDataWithPercentages(data);
|
|
9553
10121
|
const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
|
|
9554
|
-
data:
|
|
10122
|
+
data: dataWithPercentages,
|
|
9555
10123
|
chartId,
|
|
9556
10124
|
isSeriesVisible
|
|
9557
10125
|
});
|
|
@@ -9561,20 +10129,21 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9561
10129
|
}), [legendValueDisplay]));
|
|
9562
10130
|
const { isValid, message } = validateData$1(data);
|
|
9563
10131
|
const { svgChildren, htmlChildren, legendChildren, otherChildren } = useChartChildren(children, "PieChart");
|
|
10132
|
+
const chartMetadata = (0, react.useMemo)(() => ({
|
|
10133
|
+
thickness,
|
|
10134
|
+
gapScale,
|
|
10135
|
+
cornerScale
|
|
10136
|
+
}), [
|
|
10137
|
+
thickness,
|
|
10138
|
+
gapScale,
|
|
10139
|
+
cornerScale
|
|
10140
|
+
]);
|
|
9564
10141
|
useChartRegistration({
|
|
9565
10142
|
chartId,
|
|
9566
10143
|
legendItems,
|
|
9567
10144
|
chartType: "pie",
|
|
9568
10145
|
isDataValid: isValid,
|
|
9569
|
-
metadata:
|
|
9570
|
-
thickness,
|
|
9571
|
-
gapScale,
|
|
9572
|
-
cornerScale
|
|
9573
|
-
}), [
|
|
9574
|
-
thickness,
|
|
9575
|
-
gapScale,
|
|
9576
|
-
cornerScale
|
|
9577
|
-
])
|
|
10146
|
+
metadata: chartMetadata
|
|
9578
10147
|
});
|
|
9579
10148
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
9580
10149
|
if (!isValid) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -9625,19 +10194,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9625
10194
|
width: propWidth || void 0,
|
|
9626
10195
|
height: propHeight || void 0
|
|
9627
10196
|
},
|
|
9628
|
-
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9629
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipInPortal, {
|
|
9630
|
-
top: tooltipTop || 0,
|
|
9631
|
-
left: tooltipLeft || 0,
|
|
9632
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9633
|
-
className: "a8c-charts-scope",
|
|
9634
|
-
role: "tooltip",
|
|
9635
|
-
children: renderTooltip({ tooltipData })
|
|
9636
|
-
})
|
|
9637
|
-
}),
|
|
9638
|
-
htmlChildren,
|
|
9639
|
-
otherChildren
|
|
9640
|
-
] }),
|
|
10197
|
+
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [htmlChildren, otherChildren] }),
|
|
9641
10198
|
children: ({ contentWidth, contentHeight }) => {
|
|
9642
10199
|
const availableSize = Math.min(contentWidth > 0 ? contentWidth : 300, contentHeight > 0 ? contentHeight : 300);
|
|
9643
10200
|
const actualSize = size ? Math.min(size, availableSize) : availableSize;
|
|
@@ -9650,9 +10207,10 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9650
10207
|
const innerRadius = thickness === 0 ? 0 : outerRadius * (1 - thickness);
|
|
9651
10208
|
const maxCornerRadius = (outerRadius - innerRadius) / 2;
|
|
9652
10209
|
const cornerRadius = cornerScale ? Math.min(cornerScale * outerRadius, maxCornerRadius) : 0;
|
|
9653
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
10210
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
9654
10211
|
ref: containerRef,
|
|
9655
|
-
|
|
10212
|
+
className: pie_chart_module_default["pie-chart__plot"],
|
|
10213
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
9656
10214
|
viewBox: `0 0 ${width} ${height}`,
|
|
9657
10215
|
preserveAspectRatio: "xMidYMid meet",
|
|
9658
10216
|
width,
|
|
@@ -9684,11 +10242,12 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9684
10242
|
const hasSpaceForLabel = arc.endAngle - arc.startAngle >= .25;
|
|
9685
10243
|
const handleMouseMove = (event) => {
|
|
9686
10244
|
if (!withTooltips) return;
|
|
9687
|
-
|
|
10245
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
10246
|
+
if (!bounds) return;
|
|
9688
10247
|
showTooltip({
|
|
9689
10248
|
tooltipData: arc.data,
|
|
9690
|
-
tooltipLeft: event.clientX -
|
|
9691
|
-
tooltipTop: event.clientY -
|
|
10249
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
10250
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9692
10251
|
});
|
|
9693
10252
|
};
|
|
9694
10253
|
const pathProps = {
|
|
@@ -9703,30 +10262,28 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9703
10262
|
}
|
|
9704
10263
|
const svgLabelSmall = providerTheme.svgLabelSmall;
|
|
9705
10264
|
const fontSize = resolveFontSize(svgLabelSmall?.fontSize) ?? 12;
|
|
9706
|
-
const
|
|
10265
|
+
const backgroundWidth = (0, _visx_text.getStringWidth)(arc.data.label, {
|
|
9707
10266
|
fontSize,
|
|
9708
10267
|
fontFamily: svgLabelSmall?.fontFamily,
|
|
9709
10268
|
fontWeight: svgLabelSmall?.fontWeight
|
|
9710
|
-
});
|
|
9711
|
-
const
|
|
9712
|
-
const backgroundWidth = estimatedTextWidth + labelPadding * 2;
|
|
9713
|
-
const backgroundHeight = fontSize + labelPadding * 2;
|
|
10269
|
+
}) + 12;
|
|
10270
|
+
const backgroundHeight = fontSize + 12;
|
|
9714
10271
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
9715
10272
|
...groupProps,
|
|
9716
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [
|
|
10273
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { ...pathProps }), showLabels && hasSpaceForLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
|
|
10274
|
+
className: pie_chart_module_default["pie-chart__label-plate"],
|
|
9717
10275
|
x: centroidX - backgroundWidth / 2,
|
|
9718
10276
|
y: centroidY - backgroundHeight / 2,
|
|
9719
10277
|
width: backgroundWidth,
|
|
9720
10278
|
height: backgroundHeight,
|
|
9721
|
-
fill: providerTheme.labelBackgroundColor,
|
|
9722
10279
|
rx: 4,
|
|
9723
10280
|
ry: 4,
|
|
9724
10281
|
pointerEvents: "none"
|
|
9725
10282
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
10283
|
+
className: pie_chart_module_default["pie-chart__label-text"],
|
|
9726
10284
|
x: centroidX,
|
|
9727
10285
|
y: centroidY,
|
|
9728
10286
|
dy: ".33em",
|
|
9729
|
-
fill: providerTheme.labelTextColor || "#333",
|
|
9730
10287
|
fontSize,
|
|
9731
10288
|
textAnchor: "middle",
|
|
9732
10289
|
pointerEvents: "none",
|
|
@@ -9737,7 +10294,15 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9737
10294
|
}
|
|
9738
10295
|
}), !allSegmentsHidden && svgChildren]
|
|
9739
10296
|
})]
|
|
9740
|
-
})
|
|
10297
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
10298
|
+
top: tooltipTop || 0,
|
|
10299
|
+
left: tooltipLeft || 0,
|
|
10300
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10301
|
+
className: standaloneScopeClass,
|
|
10302
|
+
role: "tooltip",
|
|
10303
|
+
children: renderTooltip({ tooltipData })
|
|
10304
|
+
})
|
|
10305
|
+
})]
|
|
9741
10306
|
});
|
|
9742
10307
|
}
|
|
9743
10308
|
})
|
|
@@ -9764,6 +10329,7 @@ var pie_semi_circle_chart_module_default = {
|
|
|
9764
10329
|
"label": "a8ccharts-YtTOxW-label",
|
|
9765
10330
|
"note": "a8ccharts-YtTOxW-note",
|
|
9766
10331
|
"pie-semi-circle-chart": "a8ccharts-YtTOxW-pie-semi-circle-chart",
|
|
10332
|
+
"pie-semi-circle-chart__plot": "a8ccharts-YtTOxW-pie-semi-circle-chart__plot",
|
|
9767
10333
|
"pie-semi-circle-chart--responsive": "a8ccharts-YtTOxW-pie-semi-circle-chart--responsive"
|
|
9768
10334
|
};
|
|
9769
10335
|
//#endregion
|
|
@@ -9813,23 +10379,17 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9813
10379
|
const legendPosition = legend.position ?? "bottom";
|
|
9814
10380
|
const chartId = useChartId(providedChartId);
|
|
9815
10381
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
9816
|
-
const
|
|
9817
|
-
|
|
9818
|
-
scroll: true,
|
|
9819
|
-
debounce: 0
|
|
9820
|
-
});
|
|
10382
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
10383
|
+
const containerRef = (0, react.useRef)(null);
|
|
9821
10384
|
const handleMouseMove = (0, react.useCallback)((event, arc) => {
|
|
9822
|
-
|
|
10385
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
10386
|
+
if (!bounds) return;
|
|
9823
10387
|
showTooltip({
|
|
9824
10388
|
tooltipData: arc.data,
|
|
9825
|
-
tooltipLeft: event.clientX -
|
|
9826
|
-
tooltipTop: event.clientY -
|
|
10389
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
10390
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9827
10391
|
});
|
|
9828
10392
|
}, [
|
|
9829
|
-
containerBounds.width,
|
|
9830
|
-
containerBounds.height,
|
|
9831
|
-
containerBounds.left,
|
|
9832
|
-
containerBounds.top,
|
|
9833
10393
|
showTooltip,
|
|
9834
10394
|
tooltipOffsetX,
|
|
9835
10395
|
tooltipOffsetY
|
|
@@ -9842,8 +10402,9 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9842
10402
|
}, [handleMouseMove]);
|
|
9843
10403
|
const { isValid, message } = validateData(data);
|
|
9844
10404
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
10405
|
+
const dataWithPercentages = useDataWithPercentages(data);
|
|
9845
10406
|
const { visibleData, allSegmentsHidden, legendData } = useLegendVisibilityData({
|
|
9846
|
-
data:
|
|
10407
|
+
data: dataWithPercentages,
|
|
9847
10408
|
chartId,
|
|
9848
10409
|
isSeriesVisible
|
|
9849
10410
|
});
|
|
@@ -9860,15 +10421,16 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9860
10421
|
legendValueDisplay
|
|
9861
10422
|
}), [legendValueDisplay]));
|
|
9862
10423
|
const { svgChildren, htmlChildren, legendChildren, otherChildren } = useChartChildren(children, "PieSemiCircleChart");
|
|
10424
|
+
const chartMetadata = (0, react.useMemo)(() => ({
|
|
10425
|
+
thickness,
|
|
10426
|
+
clockwise
|
|
10427
|
+
}), [thickness, clockwise]);
|
|
9863
10428
|
useChartRegistration({
|
|
9864
10429
|
chartId,
|
|
9865
10430
|
legendItems,
|
|
9866
10431
|
chartType: "pie-semi-circle",
|
|
9867
10432
|
isDataValid: isValid,
|
|
9868
|
-
metadata:
|
|
9869
|
-
thickness,
|
|
9870
|
-
clockwise
|
|
9871
|
-
}), [thickness, clockwise])
|
|
10433
|
+
metadata: chartMetadata
|
|
9872
10434
|
});
|
|
9873
10435
|
const prefersReducedMotion = usePrefersReducedMotion();
|
|
9874
10436
|
const effectiveWidth = propWidth || DEFAULT_WIDTH$1;
|
|
@@ -9876,7 +10438,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9876
10438
|
const errorWidth = propHeight ? Math.min(propWidth || propHeight * 2, propHeight * 2) : effectiveWidth;
|
|
9877
10439
|
const errorHeight = errorWidth / 2;
|
|
9878
10440
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9879
|
-
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart"],
|
|
10441
|
+
className: (0, clsx.default)("pie-semi-circle-chart", pie_semi_circle_chart_module_default["pie-semi-circle-chart"], className),
|
|
9880
10442
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
9881
10443
|
width: errorWidth,
|
|
9882
10444
|
height: errorHeight,
|
|
@@ -9923,19 +10485,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9923
10485
|
width: propWidth || void 0,
|
|
9924
10486
|
height: propHeight || void 0
|
|
9925
10487
|
},
|
|
9926
|
-
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9927
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipInPortal, {
|
|
9928
|
-
top: tooltipTop || 0,
|
|
9929
|
-
left: tooltipLeft || 0,
|
|
9930
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9931
|
-
className: "a8c-charts-scope",
|
|
9932
|
-
role: "tooltip",
|
|
9933
|
-
children: renderTooltip({ tooltipData })
|
|
9934
|
-
})
|
|
9935
|
-
}),
|
|
9936
|
-
htmlChildren,
|
|
9937
|
-
otherChildren
|
|
9938
|
-
] }),
|
|
10488
|
+
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [htmlChildren, otherChildren] }),
|
|
9939
10489
|
children: ({ contentWidth, contentHeight }) => {
|
|
9940
10490
|
const availableWidth = contentWidth > 0 ? contentWidth : effectiveWidth;
|
|
9941
10491
|
const availableHeight = contentHeight > 0 ? contentHeight : propHeight || effectiveWidth / 2;
|
|
@@ -9943,9 +10493,10 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9943
10493
|
const height = width / 2;
|
|
9944
10494
|
const radius = height;
|
|
9945
10495
|
const innerRadius = radius * (1 - thickness);
|
|
9946
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
10496
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
9947
10497
|
ref: containerRef,
|
|
9948
|
-
|
|
10498
|
+
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart__plot"],
|
|
10499
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
9949
10500
|
width,
|
|
9950
10501
|
height,
|
|
9951
10502
|
viewBox: `0 0 ${width} ${height}`,
|
|
@@ -10003,7 +10554,15 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
10003
10554
|
!allSegmentsHidden && svgChildren
|
|
10004
10555
|
] })
|
|
10005
10556
|
})]
|
|
10006
|
-
})
|
|
10557
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
10558
|
+
top: tooltipTop || 0,
|
|
10559
|
+
left: tooltipLeft || 0,
|
|
10560
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10561
|
+
className: standaloneScopeClass,
|
|
10562
|
+
role: "tooltip",
|
|
10563
|
+
children: renderTooltip({ tooltipData })
|
|
10564
|
+
})
|
|
10565
|
+
})]
|
|
10007
10566
|
});
|
|
10008
10567
|
}
|
|
10009
10568
|
})
|
|
@@ -10059,6 +10618,7 @@ const transformToSeriesData = (data, color, strokeWidth) => {
|
|
|
10059
10618
|
};
|
|
10060
10619
|
const SparklineComponent = (0, react.forwardRef)(({ data, width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, color, strokeWidth: strokeWidthProp, withGradientFill = true, gradient, className, chartId, margin: marginProp, animation }, ref) => {
|
|
10061
10620
|
const theme = useGlobalChartsTheme();
|
|
10621
|
+
const chartsContext = (0, react.useContext)(GlobalChartsContext);
|
|
10062
10622
|
const themeStrokeWidth = theme.sparkline?.strokeWidth ?? 1.5;
|
|
10063
10623
|
const strokeWidth = strokeWidthProp ?? themeStrokeWidth;
|
|
10064
10624
|
const seriesData = (0, react.useMemo)(() => {
|
|
@@ -10112,7 +10672,7 @@ const SparklineComponent = (0, react.forwardRef)(({ data, width = DEFAULT_WIDTH,
|
|
|
10112
10672
|
if (data.length === 1) {
|
|
10113
10673
|
const cx = width / 2;
|
|
10114
10674
|
const cy = height / 2;
|
|
10115
|
-
const resolvedColor = color || "#000000";
|
|
10675
|
+
const resolvedColor = color || chartsContext?.getElementStyles({ index: 0 }).color || "#000000";
|
|
10116
10676
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10117
10677
|
ref,
|
|
10118
10678
|
className: (0, clsx.default)("sparkline", sparkline_module_default.sparkline, sparkline_module_default["sparkline--single-point"], className),
|
|
@@ -10215,8 +10775,9 @@ const Icon = ({ direction }) => {
|
|
|
10215
10775
|
*/
|
|
10216
10776
|
function TrendIndicator({ direction, value, className, style, showIcon = true }) {
|
|
10217
10777
|
const ariaLabel = `${DIRECTION_LABELS[direction]}: ${value}`;
|
|
10778
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
10218
10779
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10219
|
-
className: (0, clsx.default)(
|
|
10780
|
+
className: (0, clsx.default)(standaloneScopeClass, trend_indicator_module_default["trend-indicator"], trend_indicator_module_default[`trend-indicator--${direction}`], className),
|
|
10220
10781
|
style,
|
|
10221
10782
|
"aria-label": ariaLabel,
|
|
10222
10783
|
children: [showIcon && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Icon, { direction }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -10259,6 +10820,7 @@ exports.buildCalendarHeatmapData = buildCalendarHeatmapData;
|
|
|
10259
10820
|
exports.defaultTheme = defaultTheme;
|
|
10260
10821
|
exports.formatMetricValue = formatMetricValue;
|
|
10261
10822
|
exports.formatPercentage = formatPercentage;
|
|
10823
|
+
exports.getBucketInfo = getBucketInfo;
|
|
10262
10824
|
exports.getColorDistance = getColorDistance;
|
|
10263
10825
|
exports.hexToRgba = hexToRgba;
|
|
10264
10826
|
exports.isValidHexColor = isValidHexColor;
|
|
@@ -10268,10 +10830,10 @@ exports.mixHexColors = mixHexColors;
|
|
|
10268
10830
|
exports.normalizeColorToHex = normalizeColorToHex;
|
|
10269
10831
|
exports.parseAsLocalDate = parseAsLocalDate;
|
|
10270
10832
|
exports.parseHslString = parseHslString;
|
|
10271
|
-
exports.parseRgbString = parseRgbString;
|
|
10272
10833
|
exports.prefersLightText = prefersLightText;
|
|
10273
10834
|
exports.relativeLuminance = relativeLuminance;
|
|
10274
10835
|
exports.resolveCssVariable = resolveCssVariable;
|
|
10836
|
+
exports.useChartFormatting = useChartFormatting;
|
|
10275
10837
|
exports.useChartLegendItems = useChartLegendItems;
|
|
10276
10838
|
exports.useChartRegistration = useChartRegistration;
|
|
10277
10839
|
exports.useChartScopeElement = useChartScopeElement;
|