@automattic/charts 3.2.0 → 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 +29 -0
- package/TOKENS.md +53 -58
- package/dist/index.cjs +1012 -542
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +72 -29
- package/dist/index.d.cts +151 -179
- package/dist/index.d.ts +151 -179
- package/dist/index.js +1013 -544
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- 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 +2 -1
- 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-list-chart/bar-list-chart.tsx +5 -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 +93 -24
- 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 +27 -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/test/sparkline.test.tsx +29 -56
- package/src/charts/sparkline/types.ts +1 -1
- package/src/components/legend/private/base-legend.module.scss +9 -5
- package/src/components/tooltip/accessible-tooltip.tsx +13 -15
- 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 +2 -3
- 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.test.tsx +16 -3
- package/src/hooks/use-xychart-theme.ts +25 -9
- package/src/index.ts +4 -0
- package/src/providers/chart-context/global-charts-provider.tsx +37 -38
- 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 +3 -13
- package/src/providers/chart-context/test/{sparse-theme.test.ts → catalog-pointers.test.ts} +22 -10
- 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 -25
- package/src/providers/chart-context/themes.ts +7 -52
- package/src/providers/chart-context/types.ts +3 -0
- package/src/styles/chart-scope.scss +39 -62
- package/src/styles/test/chart-scope.test.ts +19 -47
- package/src/test-utils/series-fixtures.ts +31 -0
- package/src/types.ts +79 -166
- 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/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 -131
- package/src/providers/chart-context/private/with-catalog-pointers.ts +0 -93
- 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 -183
- package/src/providers/chart-context/test/with-catalog-pointers.test.ts +0 -104
- package/src/styles/test/wpds-fallbacks.test.ts +0 -131
package/dist/index.cjs
CHANGED
|
@@ -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.
|
|
@@ -386,20 +420,6 @@ const parseHslString = (hslString) => {
|
|
|
386
420
|
];
|
|
387
421
|
};
|
|
388
422
|
/**
|
|
389
|
-
* Parse an RGB string like 'rgb(255, 0, 0)' into a hex color.
|
|
390
|
-
*
|
|
391
|
-
* @deprecated Use normalizeColorToHex() instead, which handles all color formats including rgb() and rgba().
|
|
392
|
-
* @param rgbString - RGB color string (not RGBA)
|
|
393
|
-
* @return hex color string or null if invalid
|
|
394
|
-
*/
|
|
395
|
-
const parseRgbString = (rgbString) => {
|
|
396
|
-
const lower = rgbString.toLowerCase().trim();
|
|
397
|
-
if (!lower.startsWith("rgb(") || lower.startsWith("rgba(")) return null;
|
|
398
|
-
const parsed = (0, _visx_vendor_d3_color.color)(lower);
|
|
399
|
-
if (!parsed) return null;
|
|
400
|
-
return parsed.formatHex();
|
|
401
|
-
};
|
|
402
|
-
/**
|
|
403
423
|
* Normalize any CSS color value to a hex color string.
|
|
404
424
|
* Handles hex, HSL, HSLA, RGB, RGBA, named CSS colors, and CSS variables.
|
|
405
425
|
*
|
|
@@ -627,6 +647,112 @@ const resolveFontSize = (val) => {
|
|
|
627
647
|
}
|
|
628
648
|
};
|
|
629
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
|
|
630
756
|
//#region src/providers/chart-scope/chart-scope-context.ts
|
|
631
757
|
/**
|
|
632
758
|
* The nearest chart element, published so JS token resolution reads the same CSS cascade that paints the chart's own colours.
|
|
@@ -774,150 +900,29 @@ const SERIES_SLOT_1_FALLBACK = "#3858e9";
|
|
|
774
900
|
/** The catalog pointer for every slot, in slot order. */
|
|
775
901
|
const SERIES_PALETTE_POINTERS = Array.from({ length: 5 }, (_, index) => index === 0 ? `var(${seriesRole(1)}, ${SERIES_SLOT_1_FALLBACK})` : `var(${seriesRole(index + 1)})`);
|
|
776
902
|
//#endregion
|
|
777
|
-
//#region src/providers/chart-context/private/theme-override-vars.ts
|
|
778
|
-
const ROLE_FOR_FIELD = [
|
|
779
|
-
["--a8c-charts-color-background", (theme) => theme.backgroundColor],
|
|
780
|
-
["--a8c-charts-color-grid", (theme) => theme.gridStyles?.stroke],
|
|
781
|
-
["--a8c-charts-color-axis", (theme) => theme.xAxisLineStyles?.stroke],
|
|
782
|
-
["--a8c-charts-color-tick", (theme) => theme.xTickLineStyles?.stroke],
|
|
783
|
-
["--a8c-charts-color-label-axis", (theme) => theme.svgLabelSmall?.fill],
|
|
784
|
-
["--a8c-charts-color-label-background", (theme) => theme.labelBackgroundColor],
|
|
785
|
-
["--a8c-charts-color-label-on-fill", (theme) => theme.labelTextColor],
|
|
786
|
-
...Array.from({ length: 5 }, (_, index) => [seriesRole(index + 1), (theme) => theme.colors?.[index]])
|
|
787
|
-
];
|
|
788
|
-
let warnedAboutExtraColors = false;
|
|
789
|
-
/**
|
|
790
|
-
* Warns once when a consumer passes more colors than there are slots to publish them into.
|
|
791
|
-
*
|
|
792
|
-
* @param count - How many entries `theme.colors` holds.
|
|
793
|
-
*/
|
|
794
|
-
function warnOnceAboutExtraColors(count) {
|
|
795
|
-
if (warnedAboutExtraColors || process.env.NODE_ENV === "production") return;
|
|
796
|
-
warnedAboutExtraColors = true;
|
|
797
|
-
console.warn(`[Charts] theme.colors holds ${count} colors and the palette has 5 slots, so entries past the 5th are ignored. Set a per-series color with \`options.stroke\` instead.`);
|
|
798
|
-
}
|
|
799
|
-
/**
|
|
800
|
-
* The variable a `theme` prop override is published as, one layer outside the role itself.
|
|
801
|
-
*
|
|
802
|
-
* `chart-scope.scss` declares each of these roles as `var(<role>-theme, <catalog default>)`, so an override that is invalid at computed-value time — a fallback-less `var()` naming a token the host never set — only invalidates this variable, and the role still resolves its mapped `--wpds-*` token. Published as the role directly, such a value took the role and every bare `var(<role>)` read site down with it.
|
|
803
|
-
*
|
|
804
|
-
* @param role - The catalog role being overridden.
|
|
805
|
-
* @return The custom property carrying the consumer's value.
|
|
806
|
-
*/
|
|
807
|
-
const themeLayerVar = (role) => `${role}-theme`;
|
|
808
|
-
ROLE_FOR_FIELD.map(([role]) => role);
|
|
809
|
-
/**
|
|
810
|
-
* Whether a value reads the role it is being published for, which would make the catalog entry depend on itself.
|
|
811
|
-
*
|
|
812
|
-
* 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 color. Verified in Chrome: `--role-theme: var(--role, blue); --role: var(--role-theme, green)` leaves `--role` empty, not `green`.
|
|
813
|
-
*
|
|
814
|
-
* Three things this has to get right, none of which a plain substring test gets:
|
|
815
|
-
*
|
|
816
|
-
* `var()` permits whitespace after the opening paren, so testing for `var(<role>` misses `var( --a8c-charts-color-grid, … )`.
|
|
817
|
-
*
|
|
818
|
-
* 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.
|
|
819
|
-
*
|
|
820
|
-
* `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.
|
|
821
|
-
*
|
|
822
|
-
* @param value - The consumer's value for the field.
|
|
823
|
-
* @param role - The catalog role this value would override.
|
|
824
|
-
* @return True when the value reads `role`, so it must not be published.
|
|
825
|
-
*/
|
|
826
|
-
const readsOwnRole = (value, role) => value.trim() === role || new RegExp(`var\\(\\s*${role.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(?![\\w-])`).test(value);
|
|
827
|
-
/**
|
|
828
|
-
* Maps a sparse consumer theme onto the theme-layer variables its overridden catalog roles read, so CSS-painted and JS-resolved colors read one source.
|
|
829
|
-
*
|
|
830
|
-
* 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.
|
|
831
|
-
*
|
|
832
|
-
* `theme.colors` publishes through the same mechanism, one slot per entry, so a CSS declaration of `--a8c-charts-color-series-N` still beats it and a short array leaves the later slots unset rather than blank.
|
|
833
|
-
*
|
|
834
|
-
* @param theme - The consumer's `theme` prop, before merging with the default theme.
|
|
835
|
-
* @return The wrapper's custom properties, and the roles the consumer overrode.
|
|
836
|
-
*/
|
|
837
|
-
const themeOverrideVars = (theme) => {
|
|
838
|
-
if (!theme) return {
|
|
839
|
-
vars: {},
|
|
840
|
-
roles: []
|
|
841
|
-
};
|
|
842
|
-
if (Array.isArray(theme.colors) && theme.colors.length > 5) warnOnceAboutExtraColors(theme.colors.length);
|
|
843
|
-
const vars = {};
|
|
844
|
-
const roles = [];
|
|
845
|
-
for (const [role, read] of ROLE_FOR_FIELD) {
|
|
846
|
-
const value = read(theme);
|
|
847
|
-
if (typeof value !== "string" || value === "") continue;
|
|
848
|
-
roles.push(role);
|
|
849
|
-
if (!readsOwnRole(value, role)) vars[themeLayerVar(role)] = value;
|
|
850
|
-
}
|
|
851
|
-
return {
|
|
852
|
-
vars,
|
|
853
|
-
roles
|
|
854
|
-
};
|
|
855
|
-
};
|
|
856
|
-
//#endregion
|
|
857
903
|
//#region src/providers/chart-context/themes.ts
|
|
858
904
|
/**
|
|
859
|
-
* 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`.
|
|
860
909
|
*/
|
|
861
910
|
const defaultTheme = {
|
|
862
|
-
|
|
863
|
-
labelBackgroundColor: "var(--a8c-charts-color-label-background, transparent)",
|
|
864
|
-
labelTextColor: "var(--a8c-charts-color-label-on-fill, #FFFFFF)",
|
|
865
|
-
colors: [...SERIES_PALETTE_POINTERS],
|
|
866
|
-
gridStyles: {
|
|
867
|
-
stroke: "var(--a8c-charts-color-grid, #dbdbdb)",
|
|
868
|
-
strokeWidth: 1
|
|
869
|
-
},
|
|
911
|
+
gridStyles: { strokeWidth: 1 },
|
|
870
912
|
tickLength: 4,
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
xTickLineStyles: {
|
|
874
|
-
stroke: "var(--a8c-charts-color-tick, #dbdbdb)",
|
|
875
|
-
strokeWidth: 1
|
|
876
|
-
},
|
|
877
|
-
xAxisLineStyles: {
|
|
878
|
-
stroke: "var(--a8c-charts-color-axis, #dbdbdb)",
|
|
879
|
-
strokeWidth: 1
|
|
880
|
-
},
|
|
913
|
+
xTickLineStyles: { strokeWidth: 1 },
|
|
914
|
+
xAxisLineStyles: { strokeWidth: 1 },
|
|
881
915
|
legend: {
|
|
882
|
-
labelStyles: {
|
|
916
|
+
labelStyles: {},
|
|
883
917
|
containerStyles: {},
|
|
884
918
|
shapeStyles: []
|
|
885
919
|
},
|
|
886
920
|
seriesLineStyles: [],
|
|
887
921
|
glyphs: [],
|
|
888
|
-
svgLabelSmall: {
|
|
889
|
-
fill: "var(--a8c-charts-color-label-axis, #1e1e1e)",
|
|
890
|
-
fontFamily: "inherit"
|
|
891
|
-
},
|
|
922
|
+
svgLabelSmall: { fontFamily: "inherit" },
|
|
892
923
|
svgLabelBig: { fontFamily: "inherit" },
|
|
893
|
-
annotationStyles: {
|
|
894
|
-
|
|
895
|
-
anchorLineStroke: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
896
|
-
backgroundFill: "var(--a8c-charts-color-surface, #fff)"
|
|
897
|
-
},
|
|
898
|
-
connector: { stroke: "var(--a8c-charts-color-annotation, #1e1e1e)" },
|
|
899
|
-
circleSubject: {
|
|
900
|
-
stroke: "transparent",
|
|
901
|
-
fill: "var(--a8c-charts-color-annotation, #1e1e1e)",
|
|
902
|
-
radius: 5
|
|
903
|
-
}
|
|
904
|
-
},
|
|
905
|
-
geoChart: { featureFillColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)" },
|
|
906
|
-
leaderboardChart: {
|
|
907
|
-
rowGap: 12,
|
|
908
|
-
columnGap: 4,
|
|
909
|
-
labelSpacing: "xs",
|
|
910
|
-
deltaColors: [
|
|
911
|
-
"var(--a8c-charts-color-trend-down, #cc1818)",
|
|
912
|
-
"var(--a8c-charts-color-trend-neutral, #707070)",
|
|
913
|
-
"var(--a8c-charts-color-trend-up, #008030)"
|
|
914
|
-
]
|
|
915
|
-
},
|
|
916
|
-
conversionFunnelChart: {
|
|
917
|
-
backgroundColor: "var(--a8c-charts-color-surface-secondary, #f4f4f4)",
|
|
918
|
-
positiveChangeColor: "var(--a8c-charts-color-trend-up, #008030)",
|
|
919
|
-
negativeChangeColor: "var(--a8c-charts-color-trend-down, #cc1818)"
|
|
920
|
-
},
|
|
924
|
+
annotationStyles: {},
|
|
925
|
+
leaderboardChart: { labelSpacing: "xs" },
|
|
921
926
|
lineChart: { lineStyles: { comparison: {
|
|
922
927
|
strokeDasharray: "4 4",
|
|
923
928
|
strokeLinecap: "square"
|
|
@@ -941,70 +946,9 @@ const defaultTheme = {
|
|
|
941
946
|
}
|
|
942
947
|
};
|
|
943
948
|
//#endregion
|
|
944
|
-
//#region src/providers/chart-context/private/with-catalog-pointers.ts
|
|
945
|
-
/**
|
|
946
|
-
* The pointer one palette slot is restored to.
|
|
947
|
-
*
|
|
948
|
-
* Unlike the other roles, this keeps the consumer's own color as the pointer's terminal literal instead of the catalog's. The literal is only ever reached where `getComputedStyle` resolves nothing — SSR and jsdom — and there the palette is the one field where falling back to the catalog default would be visible: every series would paint the same seeded blue. In a browser the slot resolves first, so a CSS declaration of it still outranks the consumer's `theme.colors`.
|
|
949
|
-
*
|
|
950
|
-
* @param index - The slot's zero-based index in `colors`.
|
|
951
|
-
* @param value - The merged theme's entry for it.
|
|
952
|
-
* @return The catalog pointer for that slot.
|
|
953
|
-
*/
|
|
954
|
-
const seriesPointer = (index, value) => {
|
|
955
|
-
const role = seriesRole(index + 1);
|
|
956
|
-
if (typeof value === "string" && value.startsWith(`var(${role}`)) return value;
|
|
957
|
-
if (typeof value !== "string" || value === "") return SERIES_PALETTE_POINTERS[index];
|
|
958
|
-
return `var(${role}, ${value})`;
|
|
959
|
-
};
|
|
960
|
-
const CATALOG_RESTORE_FOR_ROLE = {
|
|
961
|
-
...Object.fromEntries(Array.from({ length: 5 }, (_, index) => [seriesRole(index + 1), (theme) => ({ colors: SERIES_PALETTE_POINTERS.map((_pointer, slot) => seriesPointer(slot, theme.colors?.[slot])) })])),
|
|
962
|
-
"--a8c-charts-color-background": () => ({ backgroundColor: defaultTheme.backgroundColor }),
|
|
963
|
-
"--a8c-charts-color-grid": (theme) => ({ gridStyles: {
|
|
964
|
-
...theme.gridStyles,
|
|
965
|
-
stroke: defaultTheme.gridStyles.stroke
|
|
966
|
-
} }),
|
|
967
|
-
"--a8c-charts-color-axis": (theme) => ({ xAxisLineStyles: {
|
|
968
|
-
...theme.xAxisLineStyles,
|
|
969
|
-
stroke: defaultTheme.xAxisLineStyles.stroke
|
|
970
|
-
} }),
|
|
971
|
-
"--a8c-charts-color-tick": (theme) => ({ xTickLineStyles: {
|
|
972
|
-
...theme.xTickLineStyles,
|
|
973
|
-
stroke: defaultTheme.xTickLineStyles.stroke
|
|
974
|
-
} }),
|
|
975
|
-
"--a8c-charts-color-label-axis": (theme) => ({ svgLabelSmall: {
|
|
976
|
-
...theme.svgLabelSmall,
|
|
977
|
-
fill: defaultTheme.svgLabelSmall.fill
|
|
978
|
-
} }),
|
|
979
|
-
"--a8c-charts-color-label-background": () => ({ labelBackgroundColor: defaultTheme.labelBackgroundColor }),
|
|
980
|
-
"--a8c-charts-color-label-on-fill": () => ({ labelTextColor: defaultTheme.labelTextColor })
|
|
981
|
-
};
|
|
982
|
-
/**
|
|
983
|
-
* 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.
|
|
984
|
-
*
|
|
985
|
-
* 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`.
|
|
986
|
-
*
|
|
987
|
-
* Every field outside the 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.
|
|
988
|
-
*
|
|
989
|
-
* @param merged - The consumer theme merged onto `defaultTheme` (`mergeThemes` output).
|
|
990
|
-
* @param overriddenRoles - The catalog roles the consumer overrode, from `themeOverrideVars`.
|
|
991
|
-
* @return A new theme object; `merged` is not mutated.
|
|
992
|
-
*/
|
|
993
|
-
const withCatalogPointers = (merged, overriddenRoles) => {
|
|
994
|
-
let result = merged;
|
|
995
|
-
for (const role of overriddenRoles) {
|
|
996
|
-
const restore = CATALOG_RESTORE_FOR_ROLE[role];
|
|
997
|
-
if (restore) result = {
|
|
998
|
-
...result,
|
|
999
|
-
...restore(result)
|
|
1000
|
-
};
|
|
1001
|
-
}
|
|
1002
|
-
return result;
|
|
1003
|
-
};
|
|
1004
|
-
//#endregion
|
|
1005
949
|
//#region src/providers/chart-context/global-charts-provider.tsx
|
|
1006
950
|
const GlobalChartsContext = (0, react.createContext)(null);
|
|
1007
|
-
const GlobalChartsProvider = ({ children, theme }) => {
|
|
951
|
+
const GlobalChartsProvider = ({ children, theme, locale, timeZone }) => {
|
|
1008
952
|
const [charts, setCharts] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
1009
953
|
const [hiddenSeries, setHiddenSeries] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
1010
954
|
const seededCharts = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
@@ -1014,11 +958,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1014
958
|
wrapperRef.current = node;
|
|
1015
959
|
setScopeNode(node);
|
|
1016
960
|
}, []);
|
|
1017
|
-
const
|
|
1018
|
-
const providerTheme = (0, react.useMemo)(() => {
|
|
1019
|
-
if (!theme) return defaultTheme;
|
|
1020
|
-
return withCatalogPointers(mergeThemes(defaultTheme, theme), overriddenRoles);
|
|
1021
|
-
}, [theme, overriddenRoles]);
|
|
961
|
+
const providerTheme = (0, react.useMemo)(() => theme ? mergeThemes(defaultTheme, theme) : defaultTheme, [theme]);
|
|
1022
962
|
const [colorCache, setColorCache] = (0, react.useState)(() => ({
|
|
1023
963
|
colors: [],
|
|
1024
964
|
hues: [],
|
|
@@ -1034,7 +974,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1034
974
|
const existingHslColors = [];
|
|
1035
975
|
let minHue = 360;
|
|
1036
976
|
let maxHue = 0;
|
|
1037
|
-
for (const color of
|
|
977
|
+
for (const color of SERIES_PALETTE_POINTERS) {
|
|
1038
978
|
const normalizedColor = normalizeColorToHex(color, wrapperRef.current, resolveCssVariable);
|
|
1039
979
|
if (normalizedColor.startsWith("#")) {
|
|
1040
980
|
resolvedColors.push(normalizedColor);
|
|
@@ -1059,7 +999,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1059
999
|
minHue,
|
|
1060
1000
|
maxHue
|
|
1061
1001
|
});
|
|
1062
|
-
}, [
|
|
1002
|
+
}, []);
|
|
1063
1003
|
(0, react.useEffect)(() => {
|
|
1064
1004
|
if (colorCache.colors.length > 0) setIsColorPaletteResolved(true);
|
|
1065
1005
|
}, [colorCache]);
|
|
@@ -1151,12 +1091,17 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1151
1091
|
const set = hiddenSeries.get(chartId);
|
|
1152
1092
|
return set ? new Set(set) : /* @__PURE__ */ new Set();
|
|
1153
1093
|
}, [hiddenSeries]);
|
|
1094
|
+
const formatting = (0, react.useMemo)(() => sanitizeFormatting({
|
|
1095
|
+
locale,
|
|
1096
|
+
timeZone
|
|
1097
|
+
}), [locale, timeZone]);
|
|
1154
1098
|
const value = (0, react.useMemo)(() => ({
|
|
1155
1099
|
charts,
|
|
1156
1100
|
registerChart,
|
|
1157
1101
|
unregisterChart,
|
|
1158
1102
|
getChartData,
|
|
1159
1103
|
theme: providerTheme,
|
|
1104
|
+
formatting,
|
|
1160
1105
|
getElementStyles,
|
|
1161
1106
|
toggleSeriesVisibility,
|
|
1162
1107
|
setSeriesVisibility,
|
|
@@ -1172,6 +1117,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1172
1117
|
unregisterChart,
|
|
1173
1118
|
getChartData,
|
|
1174
1119
|
providerTheme,
|
|
1120
|
+
formatting,
|
|
1175
1121
|
getElementStyles,
|
|
1176
1122
|
toggleSeriesVisibility,
|
|
1177
1123
|
setSeriesVisibility,
|
|
@@ -1187,10 +1133,7 @@ const GlobalChartsProvider = ({ children, theme }) => {
|
|
|
1187
1133
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1188
1134
|
ref: setWrapperNode,
|
|
1189
1135
|
className: CHART_SCOPE_CLASS,
|
|
1190
|
-
style: {
|
|
1191
|
-
display: "contents",
|
|
1192
|
-
...overrideVars
|
|
1193
|
-
},
|
|
1136
|
+
style: { display: "contents" },
|
|
1194
1137
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartScopeContext.Provider, {
|
|
1195
1138
|
value: scopeNode,
|
|
1196
1139
|
children
|
|
@@ -1254,6 +1197,39 @@ const useDeepMemo = (value) => {
|
|
|
1254
1197
|
return ref.current;
|
|
1255
1198
|
};
|
|
1256
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
|
|
1257
1233
|
//#region src/providers/chart-scope/use-chart-scope-element.ts
|
|
1258
1234
|
/**
|
|
1259
1235
|
* Returns the nearest chart scope element, or `null` when rendered outside any scope (and during SSR, before the ref is attached).
|
|
@@ -1280,13 +1256,34 @@ const useXYChartTheme = (data) => {
|
|
|
1280
1256
|
return (0, react.useMemo)(() => {
|
|
1281
1257
|
const resolve = createCssVariableResolver(scopeElement);
|
|
1282
1258
|
const resolveColor = (value) => value ? resolve(value) ?? value : value;
|
|
1283
|
-
const paletteColors = [...JSON.parse(seriesColorKey), ...
|
|
1284
|
-
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;
|
|
1285
1262
|
return (0, _visx_xychart.buildChartTheme)({
|
|
1286
1263
|
...theme,
|
|
1264
|
+
gridColor: "",
|
|
1265
|
+
gridColorDark: "",
|
|
1287
1266
|
colors: paletteColors,
|
|
1288
|
-
backgroundColor: resolveColor(
|
|
1289
|
-
htmlLabel: htmlLabelColor ? { color: htmlLabelColor } : void 0
|
|
1267
|
+
backgroundColor: resolveColor(CATALOG_POINTERS.background),
|
|
1268
|
+
htmlLabel: htmlLabelColor ? { color: htmlLabelColor } : void 0,
|
|
1269
|
+
gridStyles: {
|
|
1270
|
+
...theme.gridStyles,
|
|
1271
|
+
stroke: CATALOG_POINTERS.grid
|
|
1272
|
+
},
|
|
1273
|
+
xAxisLineStyles: {
|
|
1274
|
+
...theme.xAxisLineStyles,
|
|
1275
|
+
stroke: CATALOG_POINTERS.axisX
|
|
1276
|
+
},
|
|
1277
|
+
xTickLineStyles: {
|
|
1278
|
+
...theme.xTickLineStyles,
|
|
1279
|
+
stroke: CATALOG_POINTERS.tickX
|
|
1280
|
+
},
|
|
1281
|
+
yAxisLineStyles: { stroke: CATALOG_POINTERS.axisY },
|
|
1282
|
+
yTickLineStyles: { stroke: CATALOG_POINTERS.tickY },
|
|
1283
|
+
svgLabelSmall: {
|
|
1284
|
+
...theme.svgLabelSmall,
|
|
1285
|
+
fill: CATALOG_POINTERS.labelAxis
|
|
1286
|
+
}
|
|
1290
1287
|
});
|
|
1291
1288
|
}, [
|
|
1292
1289
|
theme,
|
|
@@ -1691,6 +1688,21 @@ const useGlobalChartsTheme = () => {
|
|
|
1691
1688
|
return (0, react.useContext)(GlobalChartsContext)?.theme ?? defaultTheme;
|
|
1692
1689
|
};
|
|
1693
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
|
|
1694
1706
|
//#region src/components/legend/utils/value-or-identity.ts
|
|
1695
1707
|
/**
|
|
1696
1708
|
* Returns an object's value if defined, or the object.
|
|
@@ -2128,15 +2140,311 @@ const BaseTooltip = ({ data, top, left, component: Component = DefaultTooltipCon
|
|
|
2128
2140
|
});
|
|
2129
2141
|
};
|
|
2130
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
|
|
2131
2439
|
//#region src/components/tooltip/accessible-tooltip.tsx
|
|
2132
2440
|
const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardFocusedClassName, series = [], mode = "group", verticalCrosshairStyle, horizontalCrosshairStyle, ...props }) => {
|
|
2133
2441
|
const tooltipContext = (0, react.useContext)(_visx_xychart.TooltipContext);
|
|
2134
2442
|
const scopeElement = useChartScopeElement();
|
|
2135
|
-
const gridStroke = useGlobalChartsTheme().gridStyles?.stroke;
|
|
2136
2443
|
const crosshairStroke = (0, react.useMemo)(() => {
|
|
2137
|
-
const stroke =
|
|
2444
|
+
const stroke = resolveCssVariable(CATALOG_POINTERS.grid, scopeElement);
|
|
2138
2445
|
return stroke ? { stroke } : void 0;
|
|
2139
|
-
}, [
|
|
2446
|
+
}, [scopeElement]);
|
|
2447
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
2140
2448
|
const tooltipData = (0, react.useMemo)(() => {
|
|
2141
2449
|
if (mode !== "individual") return [];
|
|
2142
2450
|
if (series.length === 0) return [];
|
|
@@ -2197,11 +2505,11 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2197
2505
|
tabIndex: -1,
|
|
2198
2506
|
role: "tooltip",
|
|
2199
2507
|
"aria-atomic": "true",
|
|
2200
|
-
className: (0, clsx.default)(
|
|
2508
|
+
className: (0, clsx.default)(standaloneScopeClass, keyboardFocusedClassName),
|
|
2201
2509
|
children: tooltipContent
|
|
2202
2510
|
}, `chart-tooltip-${selectedIndex}`);
|
|
2203
2511
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2204
|
-
className:
|
|
2512
|
+
className: standaloneScopeClass,
|
|
2205
2513
|
role: "tooltip",
|
|
2206
2514
|
"aria-live": "polite",
|
|
2207
2515
|
children: tooltipContent
|
|
@@ -2211,9 +2519,10 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2211
2519
|
renderTooltip,
|
|
2212
2520
|
selectedIndex,
|
|
2213
2521
|
tooltipRef,
|
|
2214
|
-
keyboardFocusedClassName
|
|
2522
|
+
keyboardFocusedClassName,
|
|
2523
|
+
standaloneScopeClass
|
|
2215
2524
|
]);
|
|
2216
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
2525
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(XyChartTooltip, {
|
|
2217
2526
|
...props,
|
|
2218
2527
|
verticalCrosshairStyle: {
|
|
2219
2528
|
...crosshairStroke,
|
|
@@ -2561,72 +2870,90 @@ const getCurveType = (type, smoothing) => {
|
|
|
2561
2870
|
default: return _visx_curve.curveLinear;
|
|
2562
2871
|
}
|
|
2563
2872
|
};
|
|
2564
|
-
const
|
|
2565
|
-
|
|
2566
|
-
return (timestamp) => {
|
|
2567
|
-
if (!Number.isFinite(Number(timestamp))) return new Date(timestamp).toLocaleDateString();
|
|
2568
|
-
formatter = formatter ?? new Intl.DateTimeFormat(void 0, options);
|
|
2569
|
-
return formatter.format(timestamp);
|
|
2570
|
-
};
|
|
2571
|
-
};
|
|
2572
|
-
const formatYearTick = dateTimeFormat({ year: "numeric" });
|
|
2573
|
-
const formatDateTick = dateTimeFormat({
|
|
2873
|
+
const YEAR_TICK = { year: "numeric" };
|
|
2874
|
+
const DATE_TICK = {
|
|
2574
2875
|
month: "short",
|
|
2575
2876
|
day: "numeric"
|
|
2576
|
-
}
|
|
2577
|
-
const
|
|
2578
|
-
|
|
2579
|
-
hour12: true
|
|
2580
|
-
});
|
|
2581
|
-
const formatMonthTick = dateTimeFormat({ month: "short" });
|
|
2877
|
+
};
|
|
2878
|
+
const HOUR_TICK = { hour: "numeric" };
|
|
2879
|
+
const MONTH_TICK = { month: "short" };
|
|
2582
2880
|
const boundaryFormat = (isAnchor, atBoundary, between) => {
|
|
2583
2881
|
const format = (timestamp) => isAnchor(new Date(timestamp)) ? atBoundary(timestamp) : between(timestamp);
|
|
2584
2882
|
format.isAnchor = isAnchor;
|
|
2585
2883
|
return format;
|
|
2586
2884
|
};
|
|
2587
|
-
const
|
|
2588
|
-
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
|
+
};
|
|
2589
2901
|
const getSpan = (sortedData) => {
|
|
2590
|
-
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)));
|
|
2591
2903
|
if (!bounds.length) return null;
|
|
2592
2904
|
return {
|
|
2593
2905
|
minX: Math.min(...bounds.map(([first]) => Number(first))),
|
|
2594
2906
|
maxX: Math.max(...bounds.map(([, last]) => Number(last)))
|
|
2595
2907
|
};
|
|
2596
2908
|
};
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
const
|
|
2607
|
-
|
|
2608
|
-
const spacingInHours = getPointSpacingInHours(sortedData);
|
|
2609
|
-
if (spacingInHours < SUB_DAILY_SPACING_HOURS) return "hour";
|
|
2610
|
-
if (!Number.isFinite(spacingInHours) || spacingInHours < MONTHLY_SPACING_HOURS) return "day";
|
|
2611
|
-
return spacingInHours < 12 * MONTHLY_SPACING_HOURS ? "month" : "year";
|
|
2612
|
-
};
|
|
2613
|
-
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);
|
|
2614
2920
|
const resolution = getBucketResolution(sortedData, tickResolution);
|
|
2615
|
-
if (resolution === "year") return
|
|
2616
|
-
if (resolution === "month") return
|
|
2617
|
-
const span =
|
|
2618
|
-
|
|
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;
|
|
2619
2928
|
const diffInHours = Math.abs((0, date_fns.differenceInHours)(span.maxX, span.minX));
|
|
2620
2929
|
if (resolution === "hour") {
|
|
2621
|
-
if (diffInHours
|
|
2622
|
-
if (diffInHours <= 168) return
|
|
2930
|
+
if (diffInHours < 24) return format.hour;
|
|
2931
|
+
if (diffInHours <= 168) return format.dateOrHour;
|
|
2623
2932
|
}
|
|
2624
|
-
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
|
+
}, []);
|
|
2625
2956
|
};
|
|
2626
|
-
const getAnchorIndices = (domain, isAnchor) => domain.reduce((indices, date, index) => {
|
|
2627
|
-
if (isAnchor(date)) indices.push(index);
|
|
2628
|
-
return indices;
|
|
2629
|
-
}, []);
|
|
2630
2957
|
const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
2631
2958
|
const steps = /* @__PURE__ */ new Set();
|
|
2632
2959
|
for (let count = maxTicks; count > 1; count--) {
|
|
@@ -2641,26 +2968,25 @@ const getCandidateSteps = (length, maxTicks, anchorSpacing) => {
|
|
|
2641
2968
|
return steps;
|
|
2642
2969
|
};
|
|
2643
2970
|
/**
|
|
2644
|
-
* 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.
|
|
2645
2973
|
*
|
|
2646
|
-
* visx samples
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2650
|
-
*
|
|
2651
|
-
*
|
|
2652
|
-
* 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.
|
|
2653
2980
|
*
|
|
2654
|
-
* @param domain -
|
|
2981
|
+
* @param domain - Buckets in axis order.
|
|
2655
2982
|
* @param tickFormatter - Formatter the axis will render these values with.
|
|
2656
2983
|
* @param maxTicks - Most ticks the axis should carry.
|
|
2657
2984
|
* @return Values to hand the axis as `tickValues`.
|
|
2658
2985
|
*/
|
|
2659
2986
|
const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
2660
2987
|
if (!domain.length) return [];
|
|
2661
|
-
const { isAnchor } = tickFormatter;
|
|
2662
|
-
const anchorIndices = isAnchor ? getAnchorIndices(domain, isAnchor) : [];
|
|
2663
2988
|
const domainLabels = domain.map((date) => tickFormatter(date.getTime()));
|
|
2989
|
+
const anchorIndices = getAnchorIndices(domain, tickFormatter, domainLabels);
|
|
2664
2990
|
const candidates = [];
|
|
2665
2991
|
const consider = (indices) => {
|
|
2666
2992
|
if (!indices.length || indices.length > maxTicks) return;
|
|
@@ -2672,15 +2998,108 @@ const getBandTickValues = (domain, tickFormatter, maxTicks) => {
|
|
|
2672
2998
|
for (let index = offset; index < domain.length; index += step) indices.push(index);
|
|
2673
2999
|
consider(indices);
|
|
2674
3000
|
}
|
|
2675
|
-
|
|
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
|
+
}
|
|
2676
3007
|
if (!candidates.length) return [domain[0]];
|
|
2677
3008
|
const densest = candidates.reduce((most, indices) => Math.max(most, indices.length), 0);
|
|
2678
|
-
const
|
|
3009
|
+
const anchorIndexSet = new Set(anchorIndices);
|
|
3010
|
+
const anchorsIn = (indices) => indices.filter((index) => anchorIndexSet.has(index)).length;
|
|
2679
3011
|
return candidates.filter((indices) => indices.length >= densest - 1).reduce((chosen, indices) => {
|
|
2680
3012
|
const gain = anchorsIn(indices) - anchorsIn(chosen);
|
|
2681
3013
|
return gain > 0 || gain === 0 && indices.length > chosen.length ? indices : chosen;
|
|
2682
3014
|
}).map((index) => domain[index]);
|
|
2683
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
|
+
};
|
|
2684
3103
|
const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
2685
3104
|
const span = getSpan(data);
|
|
2686
3105
|
if (!span) return 1;
|
|
@@ -2695,7 +3114,43 @@ const guessOptimalNumTicks = (data, chartWidth, tickFormatter) => {
|
|
|
2695
3114
|
if (ticks.some((tick, idx) => idx > 0 && tick === ticks[idx - 1])) continue;
|
|
2696
3115
|
return ticks.length;
|
|
2697
3116
|
}
|
|
2698
|
-
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
|
+
};
|
|
2699
3154
|
};
|
|
2700
3155
|
//#endregion
|
|
2701
3156
|
//#region src/charts/private/with-responsive/with-responsive.module.scss
|
|
@@ -2976,6 +3431,9 @@ function ZoomResetButton({ onClick }) {
|
|
|
2976
3431
|
});
|
|
2977
3432
|
}
|
|
2978
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
|
|
2979
3437
|
//#region src/charts/line-chart/line-chart.module.scss
|
|
2980
3438
|
var line_chart_module_default = {
|
|
2981
3439
|
"line-chart": "a8ccharts-inuQka-line-chart",
|
|
@@ -3216,12 +3674,14 @@ const getVerticalAnchor = (subjectType, isFlippedVertically, y, yMax, height) =>
|
|
|
3216
3674
|
};
|
|
3217
3675
|
const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", styles: datumStyles, testId, renderLabel, renderLabelPopover }) => {
|
|
3218
3676
|
const providerTheme = useGlobalChartsTheme();
|
|
3219
|
-
const scopeElement = useChartScopeElement();
|
|
3220
3677
|
const { xScale, yScale } = (0, react.useContext)(_visx_xychart.DataContext) || {};
|
|
3221
3678
|
const labelRef = (0, react.useRef)(null);
|
|
3222
3679
|
const [height, setHeight] = (0, react.useState)(null);
|
|
3223
|
-
const styles = (0,
|
|
3224
|
-
|
|
3680
|
+
const styles = (0, react.useMemo)(() => deepmerge.default.all([
|
|
3681
|
+
ANNOTATION_POINTERS,
|
|
3682
|
+
providerTheme.annotationStyles ?? {},
|
|
3683
|
+
datumStyles ?? {}
|
|
3684
|
+
]), [providerTheme.annotationStyles, datumStyles]);
|
|
3225
3685
|
(0, react.useEffect)(() => {
|
|
3226
3686
|
if (labelRef.current?.getBBox) {
|
|
3227
3687
|
const bbox = labelRef.current.getBBox();
|
|
@@ -3307,15 +3767,8 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3307
3767
|
dx,
|
|
3308
3768
|
dy,
|
|
3309
3769
|
children: [
|
|
3310
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.Connector, {
|
|
3311
|
-
|
|
3312
|
-
stroke: resolveColor(styles?.connector?.stroke)
|
|
3313
|
-
}),
|
|
3314
|
-
subjectType === "circle" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.CircleSubject, {
|
|
3315
|
-
...styles?.circleSubject,
|
|
3316
|
-
fill: resolveColor(styles?.circleSubject?.fill),
|
|
3317
|
-
stroke: resolveColor(styles?.circleSubject?.stroke)
|
|
3318
|
-
}),
|
|
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 }),
|
|
3319
3772
|
subjectType === "line-vertical" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_annotation.LineSubject, {
|
|
3320
3773
|
min: yMax,
|
|
3321
3774
|
max: yMin,
|
|
@@ -3349,8 +3802,6 @@ const LineChartAnnotation = ({ datum, title, subtitle, subjectType = "circle", s
|
|
|
3349
3802
|
title,
|
|
3350
3803
|
subtitle,
|
|
3351
3804
|
...styles?.label,
|
|
3352
|
-
anchorLineStroke: resolveColor(styles?.label?.anchorLineStroke),
|
|
3353
|
-
backgroundFill: resolveColor(styles?.label?.backgroundFill),
|
|
3354
3805
|
...labelPosition,
|
|
3355
3806
|
horizontalAnchor: getHorizontalAnchor(subjectType, isFlippedHorizontally),
|
|
3356
3807
|
verticalAnchor: getVerticalAnchor(subjectType, isFlippedVertically, y, yMax, height ?? ANNOTATION_INIT_HEIGHT)
|
|
@@ -3398,16 +3849,33 @@ const toNumber = (val) => {
|
|
|
3398
3849
|
const num = typeof val === "number" ? val : parseFloat(val);
|
|
3399
3850
|
return isNaN(num) ? void 0 : num;
|
|
3400
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
|
+
};
|
|
3401
3869
|
/**
|
|
3402
3870
|
* Default visx-tooltip render that prints the hovered date as a heading and
|
|
3403
3871
|
* one row per visible series (label + formatted value), sorted descending by
|
|
3404
3872
|
* value. Reused by AreaChart, which has the same multi-series shape.
|
|
3405
3873
|
*
|
|
3406
|
-
* @param params - visx `RenderTooltipParams< DataPointDate
|
|
3874
|
+
* @param params - visx `RenderTooltipParams< DataPointDate >`, plus the chart's optional `bucketInfo`.
|
|
3407
3875
|
* @return Tooltip JSX, or `null` when no datum is hovered.
|
|
3408
3876
|
*/
|
|
3409
3877
|
const renderDefaultTooltip = (params) => {
|
|
3410
|
-
const { tooltipData } = params;
|
|
3878
|
+
const { tooltipData, bucketInfo } = params;
|
|
3411
3879
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
3412
3880
|
if (!nearestDatum) return null;
|
|
3413
3881
|
const tooltipPoints = Object.entries(tooltipData?.datumByKey || {}).map(([key, { datum }]) => ({
|
|
@@ -3418,7 +3886,10 @@ const renderDefaultTooltip = (params) => {
|
|
|
3418
3886
|
className: line_chart_module_default["line-chart__tooltip"],
|
|
3419
3887
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3420
3888
|
className: line_chart_module_default["line-chart__tooltip-date"],
|
|
3421
|
-
children:
|
|
3889
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipDate, {
|
|
3890
|
+
date: nearestDatum.date,
|
|
3891
|
+
displayResolution: bucketInfo?.displayResolution ?? "day"
|
|
3892
|
+
})
|
|
3422
3893
|
}), tooltipPoints.map((point) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
3423
3894
|
direction: "row",
|
|
3424
3895
|
align: "center",
|
|
@@ -3467,9 +3938,9 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3467
3938
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
3468
3939
|
const legendShape = legend.shape ?? "line";
|
|
3469
3940
|
const legendPosition = legend.position ?? "bottom";
|
|
3470
|
-
const
|
|
3941
|
+
const formatting = useChartFormatting();
|
|
3471
3942
|
const theme = useXYChartTheme(data);
|
|
3472
|
-
const resolvedBackgroundColor = theme.backgroundColor
|
|
3943
|
+
const resolvedBackgroundColor = theme.backgroundColor;
|
|
3473
3944
|
const chartId = useChartId(providedChartId);
|
|
3474
3945
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
3475
3946
|
const isSeriesVisible = (0, react.useCallback)((seriesLabel) => !hiddenSeries.has(seriesLabel), [hiddenSeries]);
|
|
@@ -3543,17 +4014,17 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3543
4014
|
onActivate: activateSelectedPoint
|
|
3544
4015
|
});
|
|
3545
4016
|
const chartOptions = (0, react.useMemo)(() => {
|
|
3546
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
3547
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
3548
4017
|
return {
|
|
3549
4018
|
axis: {
|
|
3550
|
-
x: {
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
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
|
+
}),
|
|
3557
4028
|
y: {
|
|
3558
4029
|
orientation: "left",
|
|
3559
4030
|
numTicks: 4,
|
|
@@ -3580,7 +4051,14 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3580
4051
|
dataSorted,
|
|
3581
4052
|
width,
|
|
3582
4053
|
zoom.domain,
|
|
3583
|
-
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
|
|
3584
4062
|
]);
|
|
3585
4063
|
const tooltipRenderGlyph = (0, react.useMemo)(() => {
|
|
3586
4064
|
return (props) => {
|
|
@@ -3642,6 +4120,10 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3642
4120
|
xAccessor: (d) => d?.date,
|
|
3643
4121
|
yAccessor: (d) => d?.value
|
|
3644
4122
|
};
|
|
4123
|
+
const tooltipRenderer = (0, react.useMemo)(() => (params) => renderTooltip({
|
|
4124
|
+
...params,
|
|
4125
|
+
bucketInfo
|
|
4126
|
+
}), [renderTooltip, bucketInfo]);
|
|
3645
4127
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3646
4128
|
className: (0, clsx.default)("line-chart", line_chart_module_default["line-chart"]),
|
|
3647
4129
|
children: error
|
|
@@ -3690,7 +4172,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3690
4172
|
onBlur: onChartBlur,
|
|
3691
4173
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3692
4174
|
ref: chartRef,
|
|
3693
|
-
|
|
4175
|
+
className: xy_plot_module_default["xy-plot"],
|
|
3694
4176
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
3695
4177
|
theme,
|
|
3696
4178
|
width,
|
|
@@ -3782,7 +4264,7 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3782
4264
|
snapTooltipToDatumX: true,
|
|
3783
4265
|
snapTooltipToDatumY: true,
|
|
3784
4266
|
showSeriesGlyphs: true,
|
|
3785
|
-
renderTooltip,
|
|
4267
|
+
renderTooltip: tooltipRenderer,
|
|
3786
4268
|
renderGlyph: tooltipRenderGlyph,
|
|
3787
4269
|
glyphStyle,
|
|
3788
4270
|
showVerticalCrosshair: withTooltipCrosshairs?.showVertical,
|
|
@@ -3920,12 +4402,11 @@ const HoverGlyphs = ({ visibleSeries, stacked, stackOffset, getElementStyles, st
|
|
|
3920
4402
|
};
|
|
3921
4403
|
//#endregion
|
|
3922
4404
|
//#region src/charts/area-chart/area-chart.tsx
|
|
3923
|
-
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) => {
|
|
3924
4406
|
const legendInteractive = legend.interactive ?? false;
|
|
3925
4407
|
const legendShape = legend.shape ?? "rect";
|
|
3926
4408
|
const legendPosition = legend.position ?? "bottom";
|
|
3927
|
-
const
|
|
3928
|
-
const providerTheme = useGlobalChartsTheme();
|
|
4409
|
+
const formatting = useChartFormatting();
|
|
3929
4410
|
const theme = useXYChartTheme(data);
|
|
3930
4411
|
const chartId = useChartId(providedChartId);
|
|
3931
4412
|
const hiddenSeries = useDefaultHiddenSeries(chartId, defaultHiddenSeries);
|
|
@@ -3975,7 +4456,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
3975
4456
|
totalPoints: dataSorted[0]?.data.length || 0
|
|
3976
4457
|
});
|
|
3977
4458
|
const fixedYDomain = (0, react.useMemo)(() => {
|
|
3978
|
-
if (
|
|
4459
|
+
if (rescaleYOnVisibilityChange || !dataSorted.length || !dataSorted[0].data.length || stacked && stackOffset !== "none") return;
|
|
3979
4460
|
if (stacked) {
|
|
3980
4461
|
const numPoints = Math.max(...dataSorted.map((s) => s.data.length));
|
|
3981
4462
|
let posMax = 0;
|
|
@@ -4009,20 +4490,19 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4009
4490
|
dataSorted,
|
|
4010
4491
|
stacked,
|
|
4011
4492
|
stackOffset,
|
|
4012
|
-
|
|
4493
|
+
rescaleYOnVisibilityChange
|
|
4013
4494
|
]);
|
|
4014
4495
|
const chartOptions = (0, react.useMemo)(() => {
|
|
4015
|
-
const { tickResolution, tickFormat, ...xAxisOptions } = options?.axis?.x ?? {};
|
|
4016
|
-
const formatter = tickFormat || getFormatter(dataSorted, tickResolution);
|
|
4017
4496
|
return {
|
|
4018
4497
|
axis: {
|
|
4019
|
-
x: {
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4498
|
+
x: buildTimeAxisOptions({
|
|
4499
|
+
dataSorted,
|
|
4500
|
+
width,
|
|
4501
|
+
axisOptions: options?.axis?.x,
|
|
4502
|
+
scaleDomain: options?.xScale?.domain,
|
|
4503
|
+
zoomDomain: zoom.domain,
|
|
4504
|
+
formatting
|
|
4505
|
+
}),
|
|
4026
4506
|
y: {
|
|
4027
4507
|
orientation: "left",
|
|
4028
4508
|
numTicks: 4,
|
|
@@ -4050,7 +4530,8 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4050
4530
|
width,
|
|
4051
4531
|
stacked,
|
|
4052
4532
|
fixedYDomain,
|
|
4053
|
-
zoom.domain
|
|
4533
|
+
zoom.domain,
|
|
4534
|
+
formatting
|
|
4054
4535
|
]);
|
|
4055
4536
|
const defaultMargin = useChartMargin(height, chartOptions, dataSorted, theme);
|
|
4056
4537
|
const error = validateData$3(dataSorted);
|
|
@@ -4086,9 +4567,17 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4086
4567
|
};
|
|
4087
4568
|
const zeroYAccessor = (0, react.useCallback)(() => 0, []);
|
|
4088
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
|
+
]);
|
|
4089
4575
|
const filteredRenderTooltip = (0, react.useCallback)((params) => {
|
|
4090
4576
|
const datumByKey = params?.tooltipData?.datumByKey;
|
|
4091
|
-
if (!datumByKey) return renderTooltip(
|
|
4577
|
+
if (!datumByKey) return renderTooltip({
|
|
4578
|
+
...params,
|
|
4579
|
+
bucketInfo
|
|
4580
|
+
});
|
|
4092
4581
|
const filtered = Object.fromEntries(Object.entries(datumByKey).filter(([key]) => visibleLabels.has(key)));
|
|
4093
4582
|
if (Object.keys(filtered).length === 0) return null;
|
|
4094
4583
|
const nearestDatum = params?.tooltipData?.nearestDatum;
|
|
@@ -4098,13 +4587,18 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4098
4587
|
};
|
|
4099
4588
|
return renderTooltip({
|
|
4100
4589
|
...params,
|
|
4590
|
+
bucketInfo,
|
|
4101
4591
|
tooltipData: {
|
|
4102
4592
|
...params.tooltipData,
|
|
4103
4593
|
datumByKey: filtered,
|
|
4104
4594
|
nearestDatum: nextNearest
|
|
4105
4595
|
}
|
|
4106
4596
|
});
|
|
4107
|
-
}, [
|
|
4597
|
+
}, [
|
|
4598
|
+
renderTooltip,
|
|
4599
|
+
visibleLabels,
|
|
4600
|
+
bucketInfo
|
|
4601
|
+
]);
|
|
4108
4602
|
const resolvedFillOpacity = fillOpacity ?? (stacked ? .85 : .4);
|
|
4109
4603
|
const resolvedWithStroke = withStroke ?? !stacked;
|
|
4110
4604
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -4179,7 +4673,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4179
4673
|
onBlur: onChartBlur,
|
|
4180
4674
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4181
4675
|
ref: chartRef,
|
|
4182
|
-
|
|
4676
|
+
className: xy_plot_module_default["xy-plot"],
|
|
4183
4677
|
children: [zoomable && zoom.domain && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZoomResetButton, { onClick: zoom.reset }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
4184
4678
|
theme,
|
|
4185
4679
|
width,
|
|
@@ -4235,7 +4729,7 @@ const AreaChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4235
4729
|
stacked,
|
|
4236
4730
|
stackOffset,
|
|
4237
4731
|
getElementStyles,
|
|
4238
|
-
strokeColor: theme.backgroundColor
|
|
4732
|
+
strokeColor: theme.backgroundColor
|
|
4239
4733
|
})] }),
|
|
4240
4734
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AreaChartScalesRef, {
|
|
4241
4735
|
chartRef: internalChartRef,
|
|
@@ -4403,8 +4897,7 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4403
4897
|
year: "numeric",
|
|
4404
4898
|
month: "long",
|
|
4405
4899
|
day: "numeric",
|
|
4406
|
-
hour: "numeric"
|
|
4407
|
-
hour12: true
|
|
4900
|
+
hour: "numeric"
|
|
4408
4901
|
},
|
|
4409
4902
|
day: {
|
|
4410
4903
|
year: "numeric",
|
|
@@ -4423,16 +4916,16 @@ const TOOLTIP_FORMAT_BY_RESOLUTION = {
|
|
|
4423
4916
|
*
|
|
4424
4917
|
* @param data - Date-based series, already parsed and sorted by `useChartDataTransform`.
|
|
4425
4918
|
* @param tickResolution - Caller-declared bucket resolution, when known.
|
|
4919
|
+
* @param formatting - Host locale and time zone.
|
|
4426
4920
|
* @return Tooltip label formatter.
|
|
4427
4921
|
*/
|
|
4428
|
-
const getTooltipFormatter = (data, tickResolution) => {
|
|
4429
|
-
if (tickResolution === "week")
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
}));
|
|
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
|
+
}
|
|
4434
4927
|
const format = TOOLTIP_FORMAT_BY_RESOLUTION[getBucketResolution(data, tickResolution)] ?? TOOLTIP_FORMAT_BY_RESOLUTION.day;
|
|
4435
|
-
return (
|
|
4928
|
+
return createDateFormatter(format, formatting);
|
|
4436
4929
|
};
|
|
4437
4930
|
const identity = (label) => label;
|
|
4438
4931
|
const byBucket = (format) => (bucket) => typeof bucket === "string" ? bucket : format(Number(bucket));
|
|
@@ -4483,6 +4976,7 @@ const getGroupPadding = (scale) => {
|
|
|
4483
4976
|
*/
|
|
4484
4977
|
function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = ALL_RENDERED) {
|
|
4485
4978
|
const stableOptions = useDeepMemo(options);
|
|
4979
|
+
const formatting = useChartFormatting();
|
|
4486
4980
|
const axisConfig = (0, react.useMemo)(() => {
|
|
4487
4981
|
const { labelOverflow: xLabelOverflow, tickResolution: xTickResolution, tickFormat: xTickFormat, ...xAxisOptions } = stableOptions.axis?.x || {};
|
|
4488
4982
|
const { labelOverflow: yLabelOverflow, tickResolution: yTickResolution, tickFormat: yTickFormat, ...yAxisOptions } = stableOptions.axis?.y || {};
|
|
@@ -4509,9 +5003,9 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4509
5003
|
zero: false
|
|
4510
5004
|
};
|
|
4511
5005
|
const hasLabels = Boolean(data?.[0]?.data?.[0]?.label);
|
|
4512
|
-
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution);
|
|
5006
|
+
const timeTickFormatter = hasLabels ? null : getFormatter(data, tickResolution, formatting);
|
|
4513
5007
|
const labelFormatter = timeTickFormatter ? byBucket(timeTickFormatter) : identity;
|
|
4514
|
-
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution));
|
|
5008
|
+
const tooltipDatumFormatter = hasLabels ? labelFormatter : byBucket(getTooltipFormatter(data, tickResolution, formatting));
|
|
4515
5009
|
const valueFormatter = _automattic_number_formatters.formatNumberCompact;
|
|
4516
5010
|
const bandDomain = timeTickFormatter ? getBandDomain(data, isSeriesRendered) : null;
|
|
4517
5011
|
const valueAccessor = (d) => {
|
|
@@ -4547,7 +5041,8 @@ function useBarChartOptions(data, horizontal, options = {}, isSeriesRendered = A
|
|
|
4547
5041
|
}, [
|
|
4548
5042
|
data,
|
|
4549
5043
|
tickResolution,
|
|
4550
|
-
isSeriesRendered
|
|
5044
|
+
isSeriesRendered,
|
|
5045
|
+
formatting
|
|
4551
5046
|
]);
|
|
4552
5047
|
return (0, react.useMemo)(() => {
|
|
4553
5048
|
const { xTickFormat: defaultXTickFormat, yTickFormat: defaultYTickFormat, tooltipLabelFormatter: defaultTooltipLabelFormatter, xAccessor, yAccessor, gridVisibility, xScale: baseXScale, yScale: baseYScale } = defaultOptions[horizontal ? "horizontal" : "vertical"];
|
|
@@ -5056,6 +5551,7 @@ const BarChartInternal = ({ data, chartId: providedChartId, width, height, class
|
|
|
5056
5551
|
onBlur: onChartBlur,
|
|
5057
5552
|
children: chartHeight > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5058
5553
|
ref: chartRef,
|
|
5554
|
+
className: xy_plot_module_default["xy-plot"],
|
|
5059
5555
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_xychart.XYChart, {
|
|
5060
5556
|
theme,
|
|
5061
5557
|
width,
|
|
@@ -5223,7 +5719,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5223
5719
|
right: 20,
|
|
5224
5720
|
bottom: 0,
|
|
5225
5721
|
top: 0
|
|
5226
|
-
}, ...rest }) => {
|
|
5722
|
+
}, className, ...rest }) => {
|
|
5227
5723
|
const { getElementStyles } = useGlobalChartsContext();
|
|
5228
5724
|
const tintedData = (0, react.useMemo)(() => {
|
|
5229
5725
|
if (data.length > 1) return data;
|
|
@@ -5275,6 +5771,7 @@ const BarListChartInternal = ({ data, width, height, options = {}, margin = {
|
|
|
5275
5771
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BarChart, {
|
|
5276
5772
|
orientation: "horizontal",
|
|
5277
5773
|
gridVisibility: "none",
|
|
5774
|
+
className: (0, clsx.default)("bar-list-chart", className),
|
|
5278
5775
|
data: tintedData,
|
|
5279
5776
|
width,
|
|
5280
5777
|
height,
|
|
@@ -5311,6 +5808,9 @@ const BarListChartResponsive = withResponsive(BarListChart);
|
|
|
5311
5808
|
var conversion_funnel_chart_module_default = {
|
|
5312
5809
|
"bar-container": "a8ccharts-mGEVca-bar-container",
|
|
5313
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",
|
|
5314
5814
|
"conversion-funnel-chart--loading": "a8ccharts-mGEVca-conversion-funnel-chart--loading",
|
|
5315
5815
|
"empty-state": "a8ccharts-mGEVca-empty-state",
|
|
5316
5816
|
"funnel-bar": "a8ccharts-mGEVca-funnel-bar",
|
|
@@ -5391,23 +5891,14 @@ const useFunnelSelection = (hideTooltip) => {
|
|
|
5391
5891
|
*/
|
|
5392
5892
|
const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loading = false, animation, className, chartId: providedChartId, height, style, renderStepLabel, renderStepRate, renderMainMetric, renderTooltip }) => {
|
|
5393
5893
|
const chartId = useChartId(providedChartId);
|
|
5394
|
-
const { conversionFunnelChart: conversionFunnelChartSettings } = useGlobalChartsTheme();
|
|
5395
5894
|
const { getElementStyles, isColorPaletteResolved } = useGlobalChartsContext();
|
|
5396
5895
|
const chartRef = (0, react.useRef)(null);
|
|
5397
5896
|
const selectedBarRef = (0, react.useRef)(null);
|
|
5398
5897
|
const [scopeNode, setScopeNode] = (0, react.useState)(null);
|
|
5399
5898
|
const { tooltipData, tooltipLeft, tooltipTop, tooltipOpen, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
5400
5899
|
const { handleBarClick, handleBarKeyDown, clearSelection, getStepState } = useFunnelSelection(hideTooltip);
|
|
5401
|
-
const
|
|
5402
|
-
detectBounds: true,
|
|
5403
|
-
scroll: true
|
|
5404
|
-
});
|
|
5405
|
-
const portalContainerRefRef = (0, react.useRef)(portalContainerRef);
|
|
5406
|
-
(0, react.useEffect)(() => {
|
|
5407
|
-
portalContainerRefRef.current = portalContainerRef;
|
|
5408
|
-
}, [portalContainerRef]);
|
|
5900
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
5409
5901
|
const setChartRef = (0, react.useCallback)((node) => {
|
|
5410
|
-
portalContainerRefRef.current(node);
|
|
5411
5902
|
chartRef.current = node;
|
|
5412
5903
|
setScopeNode(node);
|
|
5413
5904
|
}, []);
|
|
@@ -5424,30 +5915,22 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5424
5915
|
});
|
|
5425
5916
|
}, [showTooltip]);
|
|
5426
5917
|
const getMouseTooltipCoords = (0, react.useCallback)((event) => {
|
|
5427
|
-
|
|
5918
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5919
|
+
if (!bounds) return null;
|
|
5428
5920
|
return {
|
|
5429
|
-
x: event.clientX -
|
|
5430
|
-
y: event.clientY -
|
|
5921
|
+
x: event.clientX - bounds.left,
|
|
5922
|
+
y: event.clientY - bounds.top
|
|
5431
5923
|
};
|
|
5432
|
-
}, [
|
|
5433
|
-
containerBounds.width,
|
|
5434
|
-
containerBounds.height,
|
|
5435
|
-
containerBounds.left,
|
|
5436
|
-
containerBounds.top
|
|
5437
|
-
]);
|
|
5924
|
+
}, []);
|
|
5438
5925
|
const getKeyboardTooltipCoords = (0, react.useCallback)((event) => {
|
|
5439
|
-
|
|
5926
|
+
const bounds = chartRef.current?.getBoundingClientRect();
|
|
5927
|
+
if (!bounds) return null;
|
|
5440
5928
|
const rect = event.currentTarget.getBoundingClientRect();
|
|
5441
5929
|
return {
|
|
5442
|
-
x: rect.left + rect.width / 2 -
|
|
5443
|
-
y: rect.top -
|
|
5930
|
+
x: rect.left + rect.width / 2 - bounds.left,
|
|
5931
|
+
y: rect.top - bounds.top
|
|
5444
5932
|
};
|
|
5445
|
-
}, [
|
|
5446
|
-
containerBounds.width,
|
|
5447
|
-
containerBounds.height,
|
|
5448
|
-
containerBounds.left,
|
|
5449
|
-
containerBounds.top
|
|
5450
|
-
]);
|
|
5933
|
+
}, []);
|
|
5451
5934
|
const handleStepInteraction = (0, react.useCallback)((step, event, interactionType) => {
|
|
5452
5935
|
selectedBarRef.current = event.currentTarget;
|
|
5453
5936
|
const { isClicked } = getStepState(step.id);
|
|
@@ -5508,19 +5991,14 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5508
5991
|
};
|
|
5509
5992
|
}, [clearSelectionAndRef]);
|
|
5510
5993
|
const resolvedHeight = height ?? style?.height ?? "100%";
|
|
5511
|
-
const {
|
|
5512
|
-
const
|
|
5513
|
-
|
|
5514
|
-
overrideColor: primaryColor
|
|
5515
|
-
}) : { color: primaryColor || "#000000" };
|
|
5516
|
-
const changeColor = changeIndicator?.startsWith("+") ? positiveChangeColor : negativeChangeColor;
|
|
5517
|
-
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;
|
|
5518
5997
|
const renderDefaultMainMetric = () => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5519
5998
|
className: conversion_funnel_chart_module_default["main-rate"],
|
|
5520
5999
|
children: formatPercentage(mainRate)
|
|
5521
6000
|
}), changeIndicator && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5522
|
-
className: conversion_funnel_chart_module_default["change-indicator"],
|
|
5523
|
-
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"]),
|
|
5524
6002
|
children: changeIndicator
|
|
5525
6003
|
})] });
|
|
5526
6004
|
const renderDefaultTooltip = (step) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
@@ -5558,7 +6036,7 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5558
6036
|
align: "center",
|
|
5559
6037
|
justify: "center",
|
|
5560
6038
|
ref: setScopeNode,
|
|
5561
|
-
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),
|
|
5562
6040
|
style: {
|
|
5563
6041
|
...style,
|
|
5564
6042
|
height: resolvedHeight
|
|
@@ -5569,16 +6047,16 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5569
6047
|
})
|
|
5570
6048
|
});
|
|
5571
6049
|
const maxRate = Math.max(...steps.map((step) => step.rate));
|
|
5572
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(
|
|
6050
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Stack, {
|
|
5573
6051
|
direction: "column",
|
|
5574
6052
|
gap: "xl",
|
|
5575
6053
|
ref: setChartRef,
|
|
5576
|
-
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),
|
|
5577
6055
|
style: {
|
|
5578
6056
|
...style,
|
|
5579
6057
|
height: resolvedHeight
|
|
5580
6058
|
},
|
|
5581
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ChartScopeContext.Provider, {
|
|
6059
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(ChartScopeContext.Provider, {
|
|
5582
6060
|
value: scopeNode,
|
|
5583
6061
|
children: [renderMainMetric ? renderMainMetric({
|
|
5584
6062
|
mainRate,
|
|
@@ -5630,7 +6108,6 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5630
6108
|
role: "button",
|
|
5631
6109
|
tabIndex: isBlurred ? -1 : 0,
|
|
5632
6110
|
"aria-label": step.label,
|
|
5633
|
-
style: { backgroundColor: barBackgroundColor },
|
|
5634
6111
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5635
6112
|
className: (0, clsx.default)(conversion_funnel_chart_module_default["funnel-bar"], { [conversion_funnel_chart_module_default["funnel-bar--animated"]]: animation && !loading && !prefersReducedMotion }),
|
|
5636
6113
|
style: {
|
|
@@ -5642,23 +6119,23 @@ const ConversionFunnelChartInternal = ({ mainRate, changeIndicator, steps, loadi
|
|
|
5642
6119
|
}, step.id);
|
|
5643
6120
|
})
|
|
5644
6121
|
})]
|
|
5645
|
-
})
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5659
|
-
|
|
5660
|
-
}
|
|
5661
|
-
})
|
|
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
|
+
});
|
|
5662
6139
|
};
|
|
5663
6140
|
/**
|
|
5664
6141
|
* ConversionFunnelChart component with provider wrapper
|
|
@@ -5804,7 +6281,7 @@ function normalizeGeoChartError(eventArgs) {
|
|
|
5804
6281
|
* @return A React component displaying an interactive map with data visualization
|
|
5805
6282
|
*/
|
|
5806
6283
|
const GeoChartInternal = ({ className, data, width, height, region = "world", resolution = "countries", onError, renderPlaceholder }) => {
|
|
5807
|
-
const { getElementStyles
|
|
6284
|
+
const { getElementStyles } = useGlobalChartsContext();
|
|
5808
6285
|
const scopeElement = useChartScopeElement();
|
|
5809
6286
|
const containerRef = (0, react.useRef)(null);
|
|
5810
6287
|
const reportedErrorIdsRef = (0, react.useRef)(/* @__PURE__ */ new Set());
|
|
@@ -5838,8 +6315,8 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5838
6315
|
});
|
|
5839
6316
|
const fullColorHex = getElementStyles({ index: 0 }).color;
|
|
5840
6317
|
const lightColorHex = lightenHexColor(fullColorHex, .8);
|
|
5841
|
-
const backgroundColorHex = normalizeColorToHex(
|
|
5842
|
-
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;
|
|
5843
6320
|
const sanitizedData = (0, react.useMemo)(() => {
|
|
5844
6321
|
if (data.length === 0) return {
|
|
5845
6322
|
data,
|
|
@@ -5900,8 +6377,7 @@ const GeoChartInternal = ({ className, data, width, height, region = "world", re
|
|
|
5900
6377
|
className: (0, clsx.default)("geo-chart", geo_chart_module_default.container, className),
|
|
5901
6378
|
style: {
|
|
5902
6379
|
width,
|
|
5903
|
-
height
|
|
5904
|
-
backgroundColor
|
|
6380
|
+
height
|
|
5905
6381
|
},
|
|
5906
6382
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_google_charts.Chart, {
|
|
5907
6383
|
chartType: "GeoChart",
|
|
@@ -5951,6 +6427,7 @@ var heatmap_chart_module_default = {
|
|
|
5951
6427
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
5952
6428
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
5953
6429
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
6430
|
+
"heatmap-chart__legend-label": "a8ccharts-O3YMOW-heatmap-chart__legend-label",
|
|
5954
6431
|
"heatmap-chart__legend-swatch": "a8ccharts-O3YMOW-heatmap-chart__legend-swatch",
|
|
5955
6432
|
"heatmap-chart__row": "a8ccharts-O3YMOW-heatmap-chart__row",
|
|
5956
6433
|
"heatmap-chart__row-label": "a8ccharts-O3YMOW-heatmap-chart__row-label",
|
|
@@ -6093,7 +6570,7 @@ const HeatmapContext = (0, react.createContext)(null);
|
|
|
6093
6570
|
//#region src/charts/heatmap-chart/private/heatmap-legend.tsx
|
|
6094
6571
|
const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
6095
6572
|
const context = (0, react.useContext)(HeatmapContext);
|
|
6096
|
-
const { legend
|
|
6573
|
+
const { legend } = useGlobalChartsTheme();
|
|
6097
6574
|
if (!context) return null;
|
|
6098
6575
|
const { primaryColorHex } = context;
|
|
6099
6576
|
const labelStyle = legend.labelStyles;
|
|
@@ -6104,6 +6581,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6104
6581
|
children: [
|
|
6105
6582
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6106
6583
|
variant: "body-sm",
|
|
6584
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6107
6585
|
style: labelStyle,
|
|
6108
6586
|
children: lessLabel ?? (0, _wordpress_i18n.__)("Less", "jetpack-charts")
|
|
6109
6587
|
}),
|
|
@@ -6117,7 +6595,6 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6117
6595
|
className: heatmap_chart_module_default["heatmap-chart__legend-swatch"],
|
|
6118
6596
|
style: {
|
|
6119
6597
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6120
|
-
"--a8c-charts-color-heatmap-background": backgroundColor,
|
|
6121
6598
|
"--a8c-charts-heatmap-cell-intensity": intensity
|
|
6122
6599
|
}
|
|
6123
6600
|
}, index);
|
|
@@ -6125,6 +6602,7 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6125
6602
|
}),
|
|
6126
6603
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
6127
6604
|
variant: "body-sm",
|
|
6605
|
+
className: heatmap_chart_module_default["heatmap-chart__legend-label"],
|
|
6128
6606
|
style: labelStyle,
|
|
6129
6607
|
children: moreLabel ?? (0, _wordpress_i18n.__)("More", "jetpack-charts")
|
|
6130
6608
|
})
|
|
@@ -6142,17 +6620,14 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6142
6620
|
const { nonLegendChildren } = useChartChildren(children, "HeatmapChart");
|
|
6143
6621
|
const [selectedIndex, setSelectedIndex] = (0, react.useState)();
|
|
6144
6622
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, showTooltip, hideTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
6145
|
-
const
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
});
|
|
6149
|
-
const containerBoundsRef = (0, react.useRef)(containerBounds);
|
|
6150
|
-
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]);
|
|
6151
6626
|
const { color: primaryColorHex } = getElementStyles({
|
|
6152
6627
|
index: 0,
|
|
6153
|
-
overrideColor: primaryColor
|
|
6628
|
+
overrideColor: primaryColor
|
|
6154
6629
|
});
|
|
6155
|
-
const chartBackgroundHex = normalizeColorToHex(
|
|
6630
|
+
const chartBackgroundHex = normalizeColorToHex(CATALOG_POINTERS.background, scopeElement, resolveCssVariable);
|
|
6156
6631
|
const primaryHex = normalizeColorToHex(primaryColorHex);
|
|
6157
6632
|
const cellHasLightText = (intensity) => isValidHexColor(primaryHex) && isValidHexColor(chartBackgroundHex) && prefersLightText(mixHexColors(primaryHex, chartBackgroundHex, 1 - (CELL_MIX_FLOOR + .85 * intensity)));
|
|
6158
6633
|
const extent = (0, react.useMemo)(() => getValueExtent(data), [data]);
|
|
@@ -6228,19 +6703,21 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6228
6703
|
]);
|
|
6229
6704
|
const handleCellMouseMove = (0, react.useCallback)((event) => {
|
|
6230
6705
|
if (!withTooltips) return;
|
|
6706
|
+
const origin = getTooltipOrigin();
|
|
6707
|
+
if (!origin) return;
|
|
6231
6708
|
const target = event.currentTarget;
|
|
6232
6709
|
const columnIndex = Number(target.dataset.column);
|
|
6233
6710
|
const rowIndex = Number(target.dataset.row);
|
|
6234
|
-
const bounds = containerBoundsRef.current;
|
|
6235
6711
|
showTooltip({
|
|
6236
|
-
tooltipLeft: event.clientX -
|
|
6237
|
-
tooltipTop: event.clientY -
|
|
6712
|
+
tooltipLeft: event.clientX - origin.left,
|
|
6713
|
+
tooltipTop: event.clientY - origin.top,
|
|
6238
6714
|
tooltipData: buildTooltipData(columnIndex, rowIndex)
|
|
6239
6715
|
});
|
|
6240
6716
|
}, [
|
|
6241
6717
|
withTooltips,
|
|
6242
6718
|
showTooltip,
|
|
6243
|
-
buildTooltipData
|
|
6719
|
+
buildTooltipData,
|
|
6720
|
+
getTooltipOrigin
|
|
6244
6721
|
]);
|
|
6245
6722
|
const handleCellMouseLeave = (0, react.useCallback)(() => {
|
|
6246
6723
|
if (withTooltips && selectedIndex === void 0) hideTooltip();
|
|
@@ -6251,13 +6728,14 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6251
6728
|
]);
|
|
6252
6729
|
(0, react.useEffect)(() => {
|
|
6253
6730
|
if (!withTooltips || selectedIndex === void 0) return;
|
|
6731
|
+
const origin = getTooltipOrigin();
|
|
6732
|
+
if (!origin) return;
|
|
6254
6733
|
const col = Math.floor(selectedIndex / rows);
|
|
6255
6734
|
const row = selectedIndex % rows;
|
|
6256
6735
|
const rect = (typeof document !== "undefined" ? document.getElementById(`${chartId}-cell-${col}-${row}`) : null)?.getBoundingClientRect();
|
|
6257
|
-
const bounds = containerBoundsRef.current;
|
|
6258
6736
|
showTooltip({
|
|
6259
|
-
tooltipLeft: rect ? rect.left + rect.width / 2 -
|
|
6260
|
-
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,
|
|
6261
6739
|
tooltipData: buildTooltipData(col, row)
|
|
6262
6740
|
});
|
|
6263
6741
|
}, [
|
|
@@ -6266,7 +6744,8 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6266
6744
|
rows,
|
|
6267
6745
|
chartId,
|
|
6268
6746
|
buildTooltipData,
|
|
6269
|
-
showTooltip
|
|
6747
|
+
showTooltip,
|
|
6748
|
+
getTooltipOrigin
|
|
6270
6749
|
]);
|
|
6271
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) })] }), []);
|
|
6272
6751
|
if (!columns || !rows) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Center, {
|
|
@@ -6284,7 +6763,6 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6284
6763
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
6285
6764
|
const gridStyle = {
|
|
6286
6765
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6287
|
-
"--a8c-charts-color-heatmap-background": theme.backgroundColor,
|
|
6288
6766
|
gridTemplateColumns: `auto repeat(${columns}, ${columnTrack})`,
|
|
6289
6767
|
gridTemplateRows: `auto repeat(${rows}, ${rowTrack})`
|
|
6290
6768
|
};
|
|
@@ -6382,11 +6860,11 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6382
6860
|
})]
|
|
6383
6861
|
}, `row-${rowIndex}`);
|
|
6384
6862
|
})]
|
|
6385
|
-
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
6863
|
+
}), withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BoundedTooltip, {
|
|
6386
6864
|
top: tooltipTop,
|
|
6387
6865
|
left: tooltipLeft,
|
|
6388
6866
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6389
|
-
className:
|
|
6867
|
+
className: standaloneScopeClass,
|
|
6390
6868
|
role: "tooltip",
|
|
6391
6869
|
tabIndex: -1,
|
|
6392
6870
|
children: (renderTooltip ?? defaultRenderTooltip)(tooltipData)
|
|
@@ -6410,7 +6888,7 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ (0, react_jsx_run
|
|
|
6410
6888
|
HeatmapChartResponsiveInner.displayName = "HeatmapChart";
|
|
6411
6889
|
const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
|
|
6412
6890
|
//#endregion
|
|
6413
|
-
//#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
|
|
6414
6892
|
/*!
|
|
6415
6893
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
6416
6894
|
*
|
|
@@ -6773,7 +7251,7 @@ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6773
7251
|
tslib_1.__exportStar(require_dist$1(), exports);
|
|
6774
7252
|
}));
|
|
6775
7253
|
//#endregion
|
|
6776
|
-
//#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
|
|
6777
7255
|
function useUpdateEffect(effect, deps) {
|
|
6778
7256
|
const mountedRef = (0, react.useRef)(false);
|
|
6779
7257
|
(0, react.useEffect)(() => {
|
|
@@ -8411,7 +8889,7 @@ _createEmotion.css;
|
|
|
8411
8889
|
_createEmotion.sheet;
|
|
8412
8890
|
_createEmotion.cache;
|
|
8413
8891
|
//#endregion
|
|
8414
|
-
//#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
|
|
8415
8893
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
8416
8894
|
var useCx = () => {
|
|
8417
8895
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -8518,7 +8996,7 @@ function memize(fn, options) {
|
|
|
8518
8996
|
return memoized;
|
|
8519
8997
|
}
|
|
8520
8998
|
//#endregion
|
|
8521
|
-
//#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
|
|
8522
9000
|
var white = "#fff";
|
|
8523
9001
|
var GRAY = {
|
|
8524
9002
|
900: "#1e1e1e",
|
|
@@ -8597,7 +9075,7 @@ var COLORS = Object.freeze({
|
|
|
8597
9075
|
ui: UI
|
|
8598
9076
|
});
|
|
8599
9077
|
//#endregion
|
|
8600
|
-
//#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
|
|
8601
9079
|
var CONTROL_HEIGHT = "36px";
|
|
8602
9080
|
var CONTROL_PROPS = {
|
|
8603
9081
|
controlPaddingX: 12,
|
|
@@ -8612,9 +9090,6 @@ var CONTROL_PROPS = {
|
|
|
8612
9090
|
};
|
|
8613
9091
|
var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
8614
9092
|
colorDivider: "rgba(0, 0, 0, 0.1)",
|
|
8615
|
-
colorScrollbarThumb: "rgba(0, 0, 0, 0.2)",
|
|
8616
|
-
colorScrollbarThumbHover: "rgba(0, 0, 0, 0.5)",
|
|
8617
|
-
colorScrollbarTrack: "rgba(0, 0, 0, 0.04)",
|
|
8618
9093
|
elevationIntensity: 1,
|
|
8619
9094
|
radiusXSmall: "1px",
|
|
8620
9095
|
radiusSmall: "2px",
|
|
@@ -8625,7 +9100,6 @@ var config_values_default = Object.assign({}, CONTROL_PROPS, {
|
|
|
8625
9100
|
borderWidth: "1px",
|
|
8626
9101
|
borderWidthFocus: "1.5px",
|
|
8627
9102
|
borderWidthTab: "4px",
|
|
8628
|
-
spinnerSize: 16,
|
|
8629
9103
|
fontSize: "13px",
|
|
8630
9104
|
fontSizeH1: "calc(2.44 * 13px)",
|
|
8631
9105
|
fontSizeH2: "calc(1.95 * 13px)",
|
|
@@ -8702,10 +9176,10 @@ var require_es6 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
8702
9176
|
};
|
|
8703
9177
|
}));
|
|
8704
9178
|
//#endregion
|
|
8705
|
-
//#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
|
|
8706
9180
|
var logged = /* @__PURE__ */ new Set();
|
|
8707
9181
|
//#endregion
|
|
8708
|
-
//#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
|
|
8709
9183
|
function isDev() {
|
|
8710
9184
|
return globalThis.SCRIPT_DEBUG === true;
|
|
8711
9185
|
}
|
|
@@ -8719,7 +9193,7 @@ function warning(message) {
|
|
|
8719
9193
|
logged.add(message);
|
|
8720
9194
|
}
|
|
8721
9195
|
//#endregion
|
|
8722
|
-
//#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
|
|
8723
9197
|
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
8724
9198
|
var ComponentsContext = (0, react.createContext)(
|
|
8725
9199
|
/** @type {Record<string, any>} */
|
|
@@ -8746,19 +9220,19 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
8746
9220
|
};
|
|
8747
9221
|
(0, react.memo)(BaseContextSystemProvider);
|
|
8748
9222
|
//#endregion
|
|
8749
|
-
//#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
|
|
8750
9224
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
8751
9225
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
8752
9226
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
8753
9227
|
//#endregion
|
|
8754
|
-
//#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
|
|
8755
9229
|
var import_dist = require_dist();
|
|
8756
9230
|
function getStyledClassName(namespace) {
|
|
8757
9231
|
return `components-${(0, import_dist.paramCase)(namespace)}`;
|
|
8758
9232
|
}
|
|
8759
9233
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
8760
9234
|
//#endregion
|
|
8761
|
-
//#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
|
|
8762
9236
|
function contextConnect(Component, namespace) {
|
|
8763
9237
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
8764
9238
|
}
|
|
@@ -8775,7 +9249,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
8775
9249
|
});
|
|
8776
9250
|
}
|
|
8777
9251
|
//#endregion
|
|
8778
|
-
//#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
|
|
8779
9253
|
function getNamespace(componentName) {
|
|
8780
9254
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
8781
9255
|
}
|
|
@@ -8783,7 +9257,7 @@ function getConnectedNamespace() {
|
|
|
8783
9257
|
return { [CONNECTED_NAMESPACE]: true };
|
|
8784
9258
|
}
|
|
8785
9259
|
//#endregion
|
|
8786
|
-
//#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
|
|
8787
9261
|
function useContextSystem(props, namespace) {
|
|
8788
9262
|
const contextSystemProps = useComponentsContext();
|
|
8789
9263
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -8803,7 +9277,7 @@ function useContextSystem(props, namespace) {
|
|
|
8803
9277
|
return finalComponentProps;
|
|
8804
9278
|
}
|
|
8805
9279
|
//#endregion
|
|
8806
|
-
//#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
|
|
8807
9281
|
var visuallyHidden = {
|
|
8808
9282
|
border: 0,
|
|
8809
9283
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -8819,7 +9293,7 @@ var visuallyHidden = {
|
|
|
8819
9293
|
wordBreak: "normal"
|
|
8820
9294
|
};
|
|
8821
9295
|
//#endregion
|
|
8822
|
-
//#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
|
|
8823
9297
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
8824
9298
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
8825
9299
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -8909,7 +9383,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
|
8909
9383
|
}
|
|
8910
9384
|
var PolymorphicElement = (0, react.forwardRef)(UnforwardedPolymorphicElement);
|
|
8911
9385
|
//#endregion
|
|
8912
|
-
//#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
|
|
8913
9387
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
8914
9388
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PolymorphicElement, {
|
|
8915
9389
|
ref,
|
|
@@ -8918,7 +9392,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
8918
9392
|
}
|
|
8919
9393
|
var component_default$2 = Object.assign((0, react.forwardRef)(UnforwardedView), { selector: ".components-view" });
|
|
8920
9394
|
//#endregion
|
|
8921
|
-
//#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
|
|
8922
9396
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
8923
9397
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
8924
9398
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
@@ -8933,7 +9407,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
8933
9407
|
}
|
|
8934
9408
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
8935
9409
|
//#endregion
|
|
8936
|
-
//#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
|
|
8937
9411
|
var breakpoints = [
|
|
8938
9412
|
"40em",
|
|
8939
9413
|
"52em",
|
|
@@ -8967,7 +9441,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
8967
9441
|
return array[index >= array.length ? array.length - 1 : index];
|
|
8968
9442
|
}
|
|
8969
9443
|
//#endregion
|
|
8970
|
-
//#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
|
|
8971
9445
|
var ALIGNMENTS = {
|
|
8972
9446
|
bottom: {
|
|
8973
9447
|
alignItems: "flex-end",
|
|
@@ -9015,7 +9489,7 @@ function getAlignmentProps(alignment) {
|
|
|
9015
9489
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
9016
9490
|
}
|
|
9017
9491
|
//#endregion
|
|
9018
|
-
//#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
|
|
9019
9493
|
function useGrid(props) {
|
|
9020
9494
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
9021
9495
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -9036,7 +9510,7 @@ function useGrid(props) {
|
|
|
9036
9510
|
justifyContent: justify,
|
|
9037
9511
|
verticalAlign: isInline ? "middle" : void 0,
|
|
9038
9512
|
...alignmentProps
|
|
9039
|
-
}, 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== */");
|
|
9040
9514
|
return cx(gridClasses, className);
|
|
9041
9515
|
}, [
|
|
9042
9516
|
align,
|
|
@@ -9057,7 +9531,7 @@ function useGrid(props) {
|
|
|
9057
9531
|
};
|
|
9058
9532
|
}
|
|
9059
9533
|
//#endregion
|
|
9060
|
-
//#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
|
|
9061
9535
|
function UnconnectedGrid(props, forwardedRef) {
|
|
9062
9536
|
const gridProps = useGrid(props);
|
|
9063
9537
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
@@ -9080,8 +9554,8 @@ const SUBPIXEL_TOLERANCE = .5;
|
|
|
9080
9554
|
* Counts how many leading rows fit inside the content container.
|
|
9081
9555
|
*
|
|
9082
9556
|
* Rows are read from the DOM rather than derived from constants: row height
|
|
9083
|
-
* depends on
|
|
9084
|
-
* 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.
|
|
9085
9559
|
*
|
|
9086
9560
|
* Every row is a direct grid child marked with `data-row-index`; interactive rows
|
|
9087
9561
|
* use a button wrapper and non-interactive rows use a div wrapper.
|
|
@@ -9166,14 +9640,13 @@ function useFittedRowCount(enabled, rowCount, data) {
|
|
|
9166
9640
|
* @return Array of legend items for the leaderboard chart
|
|
9167
9641
|
*/
|
|
9168
9642
|
function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withComparison = false, withOverlayLabel = false, legendLabels }) {
|
|
9169
|
-
const { leaderboardChart: leaderboardChartSettings } = useGlobalChartsTheme();
|
|
9170
9643
|
const { getElementStyles } = useGlobalChartsContext();
|
|
9171
9644
|
return (0, react.useMemo)(() => {
|
|
9172
9645
|
if (!data || data.length === 0) return [];
|
|
9173
9646
|
const items = [];
|
|
9174
9647
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
9175
9648
|
index: 0,
|
|
9176
|
-
overrideColor: primaryColor
|
|
9649
|
+
overrideColor: primaryColor
|
|
9177
9650
|
});
|
|
9178
9651
|
items.push({
|
|
9179
9652
|
label: legendLabels?.primary || (0, _wordpress_i18n.__)("Current period", "jetpack-charts"),
|
|
@@ -9182,7 +9655,7 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
9182
9655
|
if (withComparison && !withOverlayLabel) {
|
|
9183
9656
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
9184
9657
|
index: 1,
|
|
9185
|
-
overrideColor: secondaryColor
|
|
9658
|
+
overrideColor: secondaryColor
|
|
9186
9659
|
});
|
|
9187
9660
|
items.push({
|
|
9188
9661
|
label: legendLabels?.comparison || (0, _wordpress_i18n.__)("Previous period", "jetpack-charts"),
|
|
@@ -9196,7 +9669,6 @@ function useLeaderboardLegendItems({ data, primaryColor, secondaryColor, withCom
|
|
|
9196
9669
|
secondaryColor,
|
|
9197
9670
|
withComparison,
|
|
9198
9671
|
legendLabels,
|
|
9199
|
-
leaderboardChartSettings,
|
|
9200
9672
|
getElementStyles,
|
|
9201
9673
|
withOverlayLabel
|
|
9202
9674
|
]);
|
|
@@ -9210,6 +9682,9 @@ var leaderboard_chart_module_default = {
|
|
|
9210
9682
|
"chevron": "a8ccharts-GovfoW-chevron",
|
|
9211
9683
|
"deltaPlaceholder": "a8ccharts-GovfoW-deltaPlaceholder",
|
|
9212
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",
|
|
9213
9688
|
"emptyState": "a8ccharts-GovfoW-emptyState",
|
|
9214
9689
|
"fitEmptyState": "a8ccharts-GovfoW-fitEmptyState",
|
|
9215
9690
|
"interactiveRow": "a8ccharts-GovfoW-interactiveRow",
|
|
@@ -9228,6 +9703,14 @@ var leaderboard_chart_module_default = {
|
|
|
9228
9703
|
};
|
|
9229
9704
|
//#endregion
|
|
9230
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
|
+
];
|
|
9231
9714
|
/**
|
|
9232
9715
|
* Default value formatter using formatMetricValue
|
|
9233
9716
|
*
|
|
@@ -9330,15 +9813,15 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9330
9813
|
...legend.shapeStyles
|
|
9331
9814
|
};
|
|
9332
9815
|
const { legendChildren, nonLegendChildren } = useChartChildren(children, "LeaderboardChart");
|
|
9333
|
-
const { labelSpacing
|
|
9816
|
+
const { labelSpacing } = leaderboardChartSettings;
|
|
9334
9817
|
const { getElementStyles, isSeriesVisible } = useGlobalChartsContext();
|
|
9335
9818
|
const { color: resolvedPrimaryColor } = getElementStyles({
|
|
9336
9819
|
index: 0,
|
|
9337
|
-
overrideColor: primaryColor
|
|
9820
|
+
overrideColor: primaryColor
|
|
9338
9821
|
});
|
|
9339
9822
|
const { color: resolvedSecondaryColor } = getElementStyles({
|
|
9340
9823
|
index: 1,
|
|
9341
|
-
overrideColor: secondaryColor
|
|
9824
|
+
overrideColor: secondaryColor
|
|
9342
9825
|
});
|
|
9343
9826
|
const legendItems = useLeaderboardLegendItems({
|
|
9344
9827
|
data: data || [],
|
|
@@ -9394,7 +9877,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9394
9877
|
legendPosition,
|
|
9395
9878
|
legendElement: false,
|
|
9396
9879
|
legendChildren,
|
|
9397
|
-
className: (0, clsx.default)(leaderboard_chart_module_default.leaderboardChart, {
|
|
9880
|
+
className: (0, clsx.default)("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
9398
9881
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
9399
9882
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
9400
9883
|
}, className),
|
|
@@ -9429,7 +9912,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9429
9912
|
legendPosition,
|
|
9430
9913
|
legendElement,
|
|
9431
9914
|
legendChildren,
|
|
9432
|
-
className: (0, clsx.default)(leaderboard_chart_module_default.leaderboardChart, {
|
|
9915
|
+
className: (0, clsx.default)("leaderboard-chart", leaderboard_chart_module_default.leaderboardChart, {
|
|
9433
9916
|
[leaderboard_chart_module_default["leaderboardChart--responsive"]]: !propWidth && !propHeight,
|
|
9434
9917
|
[leaderboard_chart_module_default["leaderboardChart--loading"]]: loading
|
|
9435
9918
|
}, className),
|
|
@@ -9451,8 +9934,8 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9451
9934
|
children: getAllHiddenMessage(legendInteractive, "series")
|
|
9452
9935
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default, {
|
|
9453
9936
|
templateColumns: "minmax(0, 1fr) auto",
|
|
9454
|
-
rowGap,
|
|
9455
|
-
columnGap,
|
|
9937
|
+
rowGap: ROW_GAP,
|
|
9938
|
+
columnGap: COLUMN_GAP,
|
|
9456
9939
|
"data-leaderboard-grid": true,
|
|
9457
9940
|
children: data.map((entry, rowIndex) => {
|
|
9458
9941
|
const rowStyle = shouldFitRows && rowIndex >= fittedCount ? { visibility: "hidden" } : void 0;
|
|
@@ -9461,8 +9944,7 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9461
9944
|
const hasDelta = hasDeltaValue(entry);
|
|
9462
9945
|
const showComparisonValue = showComparisonColumn && hasDelta;
|
|
9463
9946
|
const showComparisonPlaceholder = showComparisonColumn && !hasDelta;
|
|
9464
|
-
const
|
|
9465
|
-
const deltaColor = deltaColors[colorIndex];
|
|
9947
|
+
const deltaTrendClass = leaderboard_chart_module_default[DELTA_TREND_CLASS[showComparisonValue ? Math.sign(entry.delta) + 1 : 1]];
|
|
9466
9948
|
const rowCells = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Stack, {
|
|
9467
9949
|
direction: "column",
|
|
9468
9950
|
gap: labelSpacing,
|
|
@@ -9483,13 +9965,11 @@ const LeaderboardChartInternal = ({ data, chartId: providedChartId, width: propW
|
|
|
9483
9965
|
children: [
|
|
9484
9966
|
isPrimaryVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, { children: valueFormatter(entry.currentValue) }),
|
|
9485
9967
|
showComparisonValue && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_wordpress_ui.Text, {
|
|
9486
|
-
className: leaderboard_chart_module_default.deltaValue,
|
|
9487
|
-
style: { color: deltaColor },
|
|
9968
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.deltaValue, deltaTrendClass),
|
|
9488
9969
|
children: deltaFormatter(entry.delta)
|
|
9489
9970
|
}),
|
|
9490
9971
|
showComparisonPlaceholder && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_wordpress_ui.Text, {
|
|
9491
|
-
className: (0, clsx.default)(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder),
|
|
9492
|
-
style: { color: deltaColor },
|
|
9972
|
+
className: (0, clsx.default)(leaderboard_chart_module_default.deltaValue, leaderboard_chart_module_default.deltaPlaceholder, deltaTrendClass),
|
|
9493
9973
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9494
9974
|
"aria-hidden": "true",
|
|
9495
9975
|
children: "—"
|
|
@@ -9573,7 +10053,9 @@ function RadialWipeAnimation({ id, radius, innerRadius = 0, durationMs = 1e3, wi
|
|
|
9573
10053
|
//#endregion
|
|
9574
10054
|
//#region src/charts/pie-chart/pie-chart.module.scss
|
|
9575
10055
|
var pie_chart_module_default = {
|
|
9576
|
-
"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",
|
|
9577
10059
|
"pie-chart--responsive": "a8ccharts-gnszbG-pie-chart--responsive"
|
|
9578
10060
|
};
|
|
9579
10061
|
//#endregion
|
|
@@ -9628,11 +10110,8 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9628
10110
|
const providerTheme = useGlobalChartsTheme();
|
|
9629
10111
|
const chartId = useChartId(providedChartId);
|
|
9630
10112
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
9631
|
-
const
|
|
9632
|
-
|
|
9633
|
-
scroll: true,
|
|
9634
|
-
debounce: 0
|
|
9635
|
-
});
|
|
10113
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
10114
|
+
const containerRef = (0, react.useRef)(null);
|
|
9636
10115
|
const onMouseLeave = (0, react.useCallback)(() => {
|
|
9637
10116
|
if (!withTooltips) return;
|
|
9638
10117
|
hideTooltip();
|
|
@@ -9715,19 +10194,7 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9715
10194
|
width: propWidth || void 0,
|
|
9716
10195
|
height: propHeight || void 0
|
|
9717
10196
|
},
|
|
9718
|
-
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
9719
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipInPortal, {
|
|
9720
|
-
top: tooltipTop || 0,
|
|
9721
|
-
left: tooltipLeft || 0,
|
|
9722
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9723
|
-
className: "a8c-charts-scope",
|
|
9724
|
-
role: "tooltip",
|
|
9725
|
-
children: renderTooltip({ tooltipData })
|
|
9726
|
-
})
|
|
9727
|
-
}),
|
|
9728
|
-
htmlChildren,
|
|
9729
|
-
otherChildren
|
|
9730
|
-
] }),
|
|
10197
|
+
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [htmlChildren, otherChildren] }),
|
|
9731
10198
|
children: ({ contentWidth, contentHeight }) => {
|
|
9732
10199
|
const availableSize = Math.min(contentWidth > 0 ? contentWidth : 300, contentHeight > 0 ? contentHeight : 300);
|
|
9733
10200
|
const actualSize = size ? Math.min(size, availableSize) : availableSize;
|
|
@@ -9740,9 +10207,10 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9740
10207
|
const innerRadius = thickness === 0 ? 0 : outerRadius * (1 - thickness);
|
|
9741
10208
|
const maxCornerRadius = (outerRadius - innerRadius) / 2;
|
|
9742
10209
|
const cornerRadius = cornerScale ? Math.min(cornerScale * outerRadius, maxCornerRadius) : 0;
|
|
9743
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
10210
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
9744
10211
|
ref: containerRef,
|
|
9745
|
-
|
|
10212
|
+
className: pie_chart_module_default["pie-chart__plot"],
|
|
10213
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
9746
10214
|
viewBox: `0 0 ${width} ${height}`,
|
|
9747
10215
|
preserveAspectRatio: "xMidYMid meet",
|
|
9748
10216
|
width,
|
|
@@ -9774,11 +10242,12 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9774
10242
|
const hasSpaceForLabel = arc.endAngle - arc.startAngle >= .25;
|
|
9775
10243
|
const handleMouseMove = (event) => {
|
|
9776
10244
|
if (!withTooltips) return;
|
|
9777
|
-
|
|
10245
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
10246
|
+
if (!bounds) return;
|
|
9778
10247
|
showTooltip({
|
|
9779
10248
|
tooltipData: arc.data,
|
|
9780
|
-
tooltipLeft: event.clientX -
|
|
9781
|
-
tooltipTop: event.clientY -
|
|
10249
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
10250
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9782
10251
|
});
|
|
9783
10252
|
};
|
|
9784
10253
|
const pathProps = {
|
|
@@ -9801,20 +10270,20 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9801
10270
|
const backgroundHeight = fontSize + 12;
|
|
9802
10271
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
9803
10272
|
...groupProps,
|
|
9804
|
-
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"],
|
|
9805
10275
|
x: centroidX - backgroundWidth / 2,
|
|
9806
10276
|
y: centroidY - backgroundHeight / 2,
|
|
9807
10277
|
width: backgroundWidth,
|
|
9808
10278
|
height: backgroundHeight,
|
|
9809
|
-
fill: providerTheme.labelBackgroundColor,
|
|
9810
10279
|
rx: 4,
|
|
9811
10280
|
ry: 4,
|
|
9812
10281
|
pointerEvents: "none"
|
|
9813
10282
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
|
|
10283
|
+
className: pie_chart_module_default["pie-chart__label-text"],
|
|
9814
10284
|
x: centroidX,
|
|
9815
10285
|
y: centroidY,
|
|
9816
10286
|
dy: ".33em",
|
|
9817
|
-
fill: providerTheme.labelTextColor || "#333",
|
|
9818
10287
|
fontSize,
|
|
9819
10288
|
textAnchor: "middle",
|
|
9820
10289
|
pointerEvents: "none",
|
|
@@ -9825,7 +10294,15 @@ const PieChartInternal = ({ data, chartId: providedChartId, withTooltips = false
|
|
|
9825
10294
|
}
|
|
9826
10295
|
}), !allSegmentsHidden && svgChildren]
|
|
9827
10296
|
})]
|
|
9828
|
-
})
|
|
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
|
+
})]
|
|
9829
10306
|
});
|
|
9830
10307
|
}
|
|
9831
10308
|
})
|
|
@@ -9852,6 +10329,7 @@ var pie_semi_circle_chart_module_default = {
|
|
|
9852
10329
|
"label": "a8ccharts-YtTOxW-label",
|
|
9853
10330
|
"note": "a8ccharts-YtTOxW-note",
|
|
9854
10331
|
"pie-semi-circle-chart": "a8ccharts-YtTOxW-pie-semi-circle-chart",
|
|
10332
|
+
"pie-semi-circle-chart__plot": "a8ccharts-YtTOxW-pie-semi-circle-chart__plot",
|
|
9855
10333
|
"pie-semi-circle-chart--responsive": "a8ccharts-YtTOxW-pie-semi-circle-chart--responsive"
|
|
9856
10334
|
};
|
|
9857
10335
|
//#endregion
|
|
@@ -9901,23 +10379,17 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9901
10379
|
const legendPosition = legend.position ?? "bottom";
|
|
9902
10380
|
const chartId = useChartId(providedChartId);
|
|
9903
10381
|
const { tooltipOpen, tooltipLeft, tooltipTop, tooltipData, hideTooltip, showTooltip } = (0, _visx_tooltip.useTooltip)();
|
|
9904
|
-
const
|
|
9905
|
-
|
|
9906
|
-
scroll: true,
|
|
9907
|
-
debounce: 0
|
|
9908
|
-
});
|
|
10382
|
+
const standaloneScopeClass = useStandaloneScopeClass();
|
|
10383
|
+
const containerRef = (0, react.useRef)(null);
|
|
9909
10384
|
const handleMouseMove = (0, react.useCallback)((event, arc) => {
|
|
9910
|
-
|
|
10385
|
+
const bounds = containerRef.current?.getBoundingClientRect();
|
|
10386
|
+
if (!bounds) return;
|
|
9911
10387
|
showTooltip({
|
|
9912
10388
|
tooltipData: arc.data,
|
|
9913
|
-
tooltipLeft: event.clientX -
|
|
9914
|
-
tooltipTop: event.clientY -
|
|
10389
|
+
tooltipLeft: event.clientX - bounds.left + tooltipOffsetX,
|
|
10390
|
+
tooltipTop: event.clientY - bounds.top + tooltipOffsetY
|
|
9915
10391
|
});
|
|
9916
10392
|
}, [
|
|
9917
|
-
containerBounds.width,
|
|
9918
|
-
containerBounds.height,
|
|
9919
|
-
containerBounds.left,
|
|
9920
|
-
containerBounds.top,
|
|
9921
10393
|
showTooltip,
|
|
9922
10394
|
tooltipOffsetX,
|
|
9923
10395
|
tooltipOffsetY
|
|
@@ -9966,7 +10438,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
9966
10438
|
const errorWidth = propHeight ? Math.min(propWidth || propHeight * 2, propHeight * 2) : effectiveWidth;
|
|
9967
10439
|
const errorHeight = errorWidth / 2;
|
|
9968
10440
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9969
|
-
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),
|
|
9970
10442
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
9971
10443
|
width: errorWidth,
|
|
9972
10444
|
height: errorHeight,
|
|
@@ -10013,19 +10485,7 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
10013
10485
|
width: propWidth || void 0,
|
|
10014
10486
|
height: propHeight || void 0
|
|
10015
10487
|
},
|
|
10016
|
-
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
10017
|
-
withTooltips && tooltipOpen && tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipInPortal, {
|
|
10018
|
-
top: tooltipTop || 0,
|
|
10019
|
-
left: tooltipLeft || 0,
|
|
10020
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10021
|
-
className: "a8c-charts-scope",
|
|
10022
|
-
role: "tooltip",
|
|
10023
|
-
children: renderTooltip({ tooltipData })
|
|
10024
|
-
})
|
|
10025
|
-
}),
|
|
10026
|
-
htmlChildren,
|
|
10027
|
-
otherChildren
|
|
10028
|
-
] }),
|
|
10488
|
+
trailingContent: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [htmlChildren, otherChildren] }),
|
|
10029
10489
|
children: ({ contentWidth, contentHeight }) => {
|
|
10030
10490
|
const availableWidth = contentWidth > 0 ? contentWidth : effectiveWidth;
|
|
10031
10491
|
const availableHeight = contentHeight > 0 ? contentHeight : propHeight || effectiveWidth / 2;
|
|
@@ -10033,9 +10493,10 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
10033
10493
|
const height = width / 2;
|
|
10034
10494
|
const radius = height;
|
|
10035
10495
|
const innerRadius = radius * (1 - thickness);
|
|
10036
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
10496
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Center, {
|
|
10037
10497
|
ref: containerRef,
|
|
10038
|
-
|
|
10498
|
+
className: pie_semi_circle_chart_module_default["pie-semi-circle-chart__plot"],
|
|
10499
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
10039
10500
|
width,
|
|
10040
10501
|
height,
|
|
10041
10502
|
viewBox: `0 0 ${width} ${height}`,
|
|
@@ -10093,7 +10554,15 @@ const PieSemiCircleChartInternal = ({ data, chartId: providedChartId, width: pro
|
|
|
10093
10554
|
!allSegmentsHidden && svgChildren
|
|
10094
10555
|
] })
|
|
10095
10556
|
})]
|
|
10096
|
-
})
|
|
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
|
+
})]
|
|
10097
10566
|
});
|
|
10098
10567
|
}
|
|
10099
10568
|
})
|
|
@@ -10351,6 +10820,7 @@ exports.buildCalendarHeatmapData = buildCalendarHeatmapData;
|
|
|
10351
10820
|
exports.defaultTheme = defaultTheme;
|
|
10352
10821
|
exports.formatMetricValue = formatMetricValue;
|
|
10353
10822
|
exports.formatPercentage = formatPercentage;
|
|
10823
|
+
exports.getBucketInfo = getBucketInfo;
|
|
10354
10824
|
exports.getColorDistance = getColorDistance;
|
|
10355
10825
|
exports.hexToRgba = hexToRgba;
|
|
10356
10826
|
exports.isValidHexColor = isValidHexColor;
|
|
@@ -10360,10 +10830,10 @@ exports.mixHexColors = mixHexColors;
|
|
|
10360
10830
|
exports.normalizeColorToHex = normalizeColorToHex;
|
|
10361
10831
|
exports.parseAsLocalDate = parseAsLocalDate;
|
|
10362
10832
|
exports.parseHslString = parseHslString;
|
|
10363
|
-
exports.parseRgbString = parseRgbString;
|
|
10364
10833
|
exports.prefersLightText = prefersLightText;
|
|
10365
10834
|
exports.relativeLuminance = relativeLuminance;
|
|
10366
10835
|
exports.resolveCssVariable = resolveCssVariable;
|
|
10836
|
+
exports.useChartFormatting = useChartFormatting;
|
|
10367
10837
|
exports.useChartLegendItems = useChartLegendItems;
|
|
10368
10838
|
exports.useChartRegistration = useChartRegistration;
|
|
10369
10839
|
exports.useChartScopeElement = useChartScopeElement;
|