@automattic/charts 4.0.0 → 4.1.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 +18 -0
- package/SECURITY.md +1 -0
- package/TOKENS.md +1 -1
- package/dist/index.cjs +548 -199
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +21 -0
- package/dist/index.d.cts +86 -72
- package/dist/index.d.ts +86 -72
- package/dist/index.js +549 -201
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/charts/heatmap-chart/heatmap-chart.module.scss +31 -0
- package/src/charts/heatmap-chart/heatmap-chart.tsx +44 -9
- package/src/charts/heatmap-chart/index.ts +2 -1
- package/src/charts/heatmap-chart/private/build-calendar-data.ts +126 -92
- package/src/charts/heatmap-chart/private/civil-day.ts +174 -0
- package/src/charts/heatmap-chart/private/index.ts +1 -1
- package/src/charts/heatmap-chart/private/use-heatmap-colors.ts +5 -1
- package/src/charts/heatmap-chart/test/build-calendar-data.test.ts +3 -0
- package/src/charts/heatmap-chart/test/civil-day.test.ts +70 -0
- package/src/charts/heatmap-chart/test/heatmap-chart.test.tsx +91 -0
- package/src/charts/heatmap-chart/test/use-calendar-heatmap-data.test.tsx +118 -0
- package/src/charts/heatmap-chart/test/use-heatmap-colors.test.ts +8 -0
- package/src/charts/heatmap-chart/test/zoned-calendar-data.test.ts +248 -0
- package/src/charts/heatmap-chart/types.ts +6 -0
- package/src/charts/heatmap-chart/use-calendar-heatmap-data.ts +42 -0
- package/src/charts/leaderboard-chart/types.ts +2 -2
- package/src/charts/line-chart/line-chart.tsx +39 -6
- package/src/charts/line-chart/test/crosshair-style-types.test.ts +31 -0
- package/src/charts/line-chart/test/line-chart.test.tsx +147 -38
- package/src/charts/line-chart/test/zoned-date-string.test.tsx +37 -0
- package/src/charts/line-chart/types.ts +13 -2
- package/src/charts/pie-chart/test/pie-chart.test.tsx +3 -12
- package/src/components/tooltip/accessible-tooltip.tsx +8 -2
- package/src/components/tooltip/private/bounded-tooltip.tsx +71 -16
- package/src/components/tooltip/test/accessible-tooltip.test.tsx +28 -1
- package/src/components/tooltip/test/bounded-tooltip.test.tsx +102 -6
- package/src/components/tooltip/test/xy-chart-tooltip.test.tsx +100 -0
- package/src/components/tooltip/xy-chart-tooltip.tsx +51 -13
- package/src/hooks/test/use-chart-data-transform-zone.test.tsx +36 -0
- package/src/hooks/test/use-chart-margin.test.tsx +173 -3
- package/src/hooks/use-chart-data-transform.ts +10 -3
- package/src/hooks/use-chart-margin.tsx +54 -9
- package/src/index.ts +4 -0
- package/src/test-utils/zoned-parsing-suite.ts +90 -0
- package/src/types.ts +2 -2
- package/src/utils/date-formatting.ts +1 -18
- package/src/utils/date-parsing.ts +103 -52
- package/src/utils/get-edge-tick-widths.ts +33 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/test/date-parsing.auckland.test.ts +6 -0
- package/src/utils/test/date-parsing.santiago.test.ts +6 -0
- package/src/utils/test/date-parsing.test.ts +16 -1
- package/src/utils/test/get-edge-tick-widths.test.ts +55 -0
- package/src/utils/warn-once.ts +23 -0
- package/src/visx/types.ts +27 -3
package/dist/index.js
CHANGED
|
@@ -6,7 +6,8 @@ import clsx from "clsx";
|
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
import { Children, Fragment, createContext, createContext as createContext$1, createElement, forwardRef, forwardRef as forwardRef$1, isValidElement, memo, useCallback, useCallback as useCallback$1, useContext, useContext as useContext$1, useEffect, useEffect as useEffect$1, useId, useImperativeHandle, useLayoutEffect, useMemo, useMemo as useMemo$1, useRef, useRef as useRef$1, useState, useState as useState$1 } from "react";
|
|
8
8
|
import { color, hsl } from "@visx/vendor/d3-color";
|
|
9
|
-
import {
|
|
9
|
+
import { differenceInHours, differenceInYears, isValid, parse, parseISO } from "date-fns";
|
|
10
|
+
import { tzOffset } from "@date-fns/tz";
|
|
10
11
|
import { Text, getStringWidth } from "@visx/text";
|
|
11
12
|
import deepmerge from "deepmerge";
|
|
12
13
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -84,46 +85,35 @@ function attachSubComponents(Chart, subComponents) {
|
|
|
84
85
|
return Object.assign(Chart, subComponents);
|
|
85
86
|
}
|
|
86
87
|
//#endregion
|
|
87
|
-
//#region src/utils/
|
|
88
|
+
//#region src/utils/warn-once.ts
|
|
89
|
+
const warned = /* @__PURE__ */ new Set();
|
|
88
90
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* This module provides utilities for parsing various date string formats and converting
|
|
92
|
-
* them to local timezone dates using the battle-tested date-fns library. For formats
|
|
93
|
-
* without timezone info, they're treated as local. For formats with timezone info,
|
|
94
|
-
* they're converted to the equivalent local time.
|
|
91
|
+
* Warns about a host-supplied value once per process, and never in production.
|
|
95
92
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
93
|
+
* @param key - Identifies the value, so a bad prop on every point warns once.
|
|
94
|
+
* @param message - What the host got wrong and what happens instead.
|
|
95
|
+
*/
|
|
96
|
+
const warnOnce = (key, message) => {
|
|
97
|
+
if (warned.has(key) || process.env.NODE_ENV === "production") return;
|
|
98
|
+
warned.add(key);
|
|
99
|
+
console.warn(`[Charts] ${message}`);
|
|
100
|
+
};
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/utils/date-parsing.ts
|
|
103
|
+
/**
|
|
104
|
+
* @file Date parsing: a naive string is dated in a supplied IANA zone, or the runtime's own
|
|
104
105
|
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
* - YYYY-MM-DD HH:mm (treated as local)
|
|
109
|
-
* - YYYY-MM-DDTHH:mm:ss (treated as local)
|
|
110
|
-
* - YYYY-MM-DDTHH:mm:ss.SSS (treated as local)
|
|
111
|
-
* - YYYY-MM-DDTHH:mm (treated as local)
|
|
112
|
-
* - YYYY-MM-DDTHH:mm:ssZ (converted to local)
|
|
113
|
-
* - YYYY-MM-DDTHH:mm:ss±HH:mm (converted to local)
|
|
106
|
+
* A string carrying an offset is already an instant and parses the same everywhere. A string
|
|
107
|
+
* without one is only a wall-clock reading, so it means nothing until a zone is named. See
|
|
108
|
+
* `parseAsLocalDate` for the supported formats.
|
|
114
109
|
*
|
|
115
|
-
*
|
|
116
|
-
* ```typescript
|
|
117
|
-
* parseAsLocalDate("2025-01-01"); // Local timezone
|
|
118
|
-
* parseAsLocalDate("2025-01-01 14:30:00"); // Local timezone
|
|
119
|
-
* parseAsLocalDate("2025-01-01 14:30"); // Local timezone
|
|
120
|
-
* parseAsLocalDate("2025-01-01T14:30:45.123"); // Local timezone
|
|
121
|
-
* parseAsLocalDate("2025-01-01T14:30:00Z"); // UTC 14:30 → Local equivalent
|
|
122
|
-
* parseAsLocalDate("2025-01-01T14:30:00+05:00"); // +05:00 14:30 → Local equivalent
|
|
123
|
-
* ```
|
|
110
|
+
* Note: this specifically avoids date-fns's default of parsing `YYYY-MM-DD` as a UTC date.
|
|
124
111
|
*/
|
|
125
112
|
/**
|
|
126
113
|
* Checks if a date string contains timezone information
|
|
114
|
+
*
|
|
115
|
+
* The minutes are optional because ISO 8601 allows a bare `±hh`, which `parseISO` reads.
|
|
116
|
+
*
|
|
127
117
|
* @param {string} dateString - The date string to check for timezone information
|
|
128
118
|
* @return {boolean} True if the date string contains timezone information, false otherwise
|
|
129
119
|
*/
|
|
@@ -131,28 +121,57 @@ const hasTimezone = (dateString) => {
|
|
|
131
121
|
const tIndex = dateString.indexOf("T");
|
|
132
122
|
if (tIndex === -1) return false;
|
|
133
123
|
if (dateString.endsWith("Z")) return true;
|
|
134
|
-
return /[+-]\d{2}
|
|
124
|
+
return /[+-]\d{2}(?::?\d{2})?$/.test(dateString.slice(tIndex + 1));
|
|
125
|
+
};
|
|
126
|
+
const NAIVE = /^(\d{1,4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{1,3}))?)?)?$/;
|
|
127
|
+
const asUtcMs = ([, ...fields]) => {
|
|
128
|
+
const [year, month, day, hour, minute, second, ms] = fields.map((field) => Number(field ?? 0));
|
|
129
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
130
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
131
|
+
date.setUTCHours(hour, minute, second, ms);
|
|
132
|
+
return date.getTime();
|
|
135
133
|
};
|
|
136
134
|
/**
|
|
137
|
-
*
|
|
135
|
+
* The instant a wall-clock reading names in a given zone.
|
|
138
136
|
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
* local timezone equivalent.
|
|
137
|
+
* A reading a spring-forward gap deleted moves forward past the gap, and one a fall-back
|
|
138
|
+
* repeated resolves to a single instant. Neither is configurable: see CHARTS-268.
|
|
142
139
|
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
* - YYYY-MM-DD HH:mm (local)
|
|
147
|
-
* - YYYY-MM-DDTHH:mm:ss (local)
|
|
148
|
-
* - YYYY-MM-DDTHH:mm:ss.SSS (local)
|
|
149
|
-
* - YYYY-MM-DDTHH:mm (local)
|
|
150
|
-
* - YYYY-MM-DDTHH:mm:ssZ (UTC → local)
|
|
151
|
-
* - YYYY-MM-DDTHH:mm:ss±HH:mm (offset → local)
|
|
152
|
-
* @param {string} dateString - The date string to parse into a local timezone date
|
|
153
|
-
* @return {Date} A Date object representing the parsed date in local timezone, or an invalid Date if parsing fails
|
|
140
|
+
* @param wallClock - The reading, as the milliseconds it would be if it were UTC.
|
|
141
|
+
* @param timeZone - IANA zone the reading is dated in.
|
|
142
|
+
* @return The instant, or `null` where `timeZone` is not a zone Intl accepts.
|
|
154
143
|
*/
|
|
155
|
-
const
|
|
144
|
+
const wallClockToInstant = (wallClock, timeZone) => {
|
|
145
|
+
const first = tzOffset(timeZone, new Date(wallClock));
|
|
146
|
+
if (Number.isNaN(first)) {
|
|
147
|
+
warnOnce(`parse:timeZone:${timeZone}`, `timeZone ${JSON.stringify(timeZone)} is not a zone Intl accepts, so dates are read in the browser's zone. Pass an IANA name or a UTC offset such as "+05:30".`);
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
const guess = wallClock - first * 6e4;
|
|
151
|
+
const second = tzOffset(timeZone, new Date(guess));
|
|
152
|
+
if (first === second) return new Date(guess);
|
|
153
|
+
const corrected = wallClock - second * 6e4;
|
|
154
|
+
const third = tzOffset(timeZone, new Date(corrected));
|
|
155
|
+
if (second === third) return new Date(corrected);
|
|
156
|
+
return /* @__PURE__ */ new Date(wallClock - Math.min(second, third) * 6e4);
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Parses any supported date string format into an instant, dated in `timeZone` or the runtime's own
|
|
160
|
+
*
|
|
161
|
+
* Uses date-fns for robust parsing and validation. A string carrying timezone info
|
|
162
|
+
* is already an instant and is returned as one, whatever `timeZone` says. A string
|
|
163
|
+
* without it is a wall-clock reading, dated in `timeZone` when one is supplied and
|
|
164
|
+
* in the runtime's own zone when none is.
|
|
165
|
+
*
|
|
166
|
+
* A wall clock a DST gap deleted is moved forward past the gap; one a fall-back repeated
|
|
167
|
+
* resolves to a single instant. Neither policy is selectable. A zone `Intl` rejects falls
|
|
168
|
+
* back to the runtime's own, and warns once outside production.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} dateString - The date string to parse into a date
|
|
171
|
+
* @param {string} [timeZone] - IANA zone a naive string is read in; the runtime's own when absent, and ignored by a string that carries its own offset
|
|
172
|
+
* @return {Date} A Date object representing the parsed instant, or an invalid Date if parsing fails
|
|
173
|
+
*/
|
|
174
|
+
const parseAsLocalDate = (dateString, timeZone) => {
|
|
156
175
|
const trimmedString = dateString.trim();
|
|
157
176
|
if (hasTimezone(trimmedString)) {
|
|
158
177
|
const isoDate = parseISO(trimmedString);
|
|
@@ -168,7 +187,10 @@ const parseAsLocalDate = (dateString) => {
|
|
|
168
187
|
"yyyy-MM-dd'T'HH:mm"
|
|
169
188
|
]) {
|
|
170
189
|
const result = parse(trimmedString, format, /* @__PURE__ */ new Date());
|
|
171
|
-
if (isValid(result))
|
|
190
|
+
if (!isValid(result)) continue;
|
|
191
|
+
if (!timeZone) return result;
|
|
192
|
+
const fields = NAIVE.exec(trimmedString);
|
|
193
|
+
return (fields && wallClockToInstant(asUtcMs(fields), timeZone)) ?? result;
|
|
172
194
|
}
|
|
173
195
|
return /* @__PURE__ */ new Date(NaN);
|
|
174
196
|
};
|
|
@@ -273,6 +295,31 @@ const formatPercentage = (value) => {
|
|
|
273
295
|
} });
|
|
274
296
|
};
|
|
275
297
|
//#endregion
|
|
298
|
+
//#region src/utils/get-edge-tick-widths.ts
|
|
299
|
+
/**
|
|
300
|
+
* Rendered widths of the first and last tick labels on an axis.
|
|
301
|
+
*
|
|
302
|
+
* An unmeasurable label reserves nothing, which is what a width of 0 already
|
|
303
|
+
* means to every caller, so it is reported as 0 rather than as its own case.
|
|
304
|
+
*
|
|
305
|
+
* @param ticks - Tick values, in axis order.
|
|
306
|
+
* @param formatTick - Function to format a tick.
|
|
307
|
+
* @param {object} labelStyle - Style object for the label.
|
|
308
|
+
* @return {object} - Widths in pixels.
|
|
309
|
+
*/
|
|
310
|
+
const getEdgeTickWidths = (ticks, formatTick, labelStyle) => {
|
|
311
|
+
if (!ticks.length) return {
|
|
312
|
+
first: 0,
|
|
313
|
+
last: 0
|
|
314
|
+
};
|
|
315
|
+
const lastIndex = ticks.length - 1;
|
|
316
|
+
const label = (tick, index) => String(formatTick ? formatTick(tick, index, []) ?? "" : tick);
|
|
317
|
+
return {
|
|
318
|
+
first: getStringWidth(label(ticks[0], 0), labelStyle) ?? 0,
|
|
319
|
+
last: getStringWidth(label(ticks[lastIndex], lastIndex), labelStyle) ?? 0
|
|
320
|
+
};
|
|
321
|
+
};
|
|
322
|
+
//#endregion
|
|
276
323
|
//#region src/utils/get-longest-tick-width.ts
|
|
277
324
|
/**
|
|
278
325
|
* Returns the width of the longest tick.
|
|
@@ -659,12 +706,6 @@ const getFormatter$1 = (options, { locale, timeZone }) => {
|
|
|
659
706
|
}
|
|
660
707
|
return formatter;
|
|
661
708
|
};
|
|
662
|
-
const warned = /* @__PURE__ */ new Set();
|
|
663
|
-
const warnOnce = (key, message) => {
|
|
664
|
-
if (warned.has(key) || process.env.NODE_ENV === "production") return;
|
|
665
|
-
warned.add(key);
|
|
666
|
-
console.warn(`[Charts] ${message}`);
|
|
667
|
-
};
|
|
668
709
|
const isUsable = (formatting) => {
|
|
669
710
|
try {
|
|
670
711
|
Intl.DateTimeFormat(formatting.locale, { timeZone: formatting.timeZone });
|
|
@@ -1290,13 +1331,28 @@ const useXYChartTheme = (data) => {
|
|
|
1290
1331
|
]);
|
|
1291
1332
|
};
|
|
1292
1333
|
//#endregion
|
|
1334
|
+
//#region src/providers/chart-context/hooks/use-chart-formatting.ts
|
|
1335
|
+
const RUNTIME_FORMATTING = {};
|
|
1336
|
+
/**
|
|
1337
|
+
* The locale and time zone dates are rendered in, as set on `GlobalChartsProvider`.
|
|
1338
|
+
*
|
|
1339
|
+
* Falls back to the runtime's own rather than throwing: charts render outside a
|
|
1340
|
+
* provider, and a host that sets neither gets exactly the browser-default
|
|
1341
|
+
* behavior this package had before the context existed.
|
|
1342
|
+
*
|
|
1343
|
+
* @return The host's formatting context.
|
|
1344
|
+
*/
|
|
1345
|
+
const useChartFormatting = () => {
|
|
1346
|
+
return useContext(GlobalChartsContext)?.formatting ?? RUNTIME_FORMATTING;
|
|
1347
|
+
};
|
|
1348
|
+
//#endregion
|
|
1293
1349
|
//#region src/hooks/use-chart-data-transform.ts
|
|
1294
1350
|
/**
|
|
1295
1351
|
* Hook that transforms and sorts chart data, handling date parsing and sorting
|
|
1296
1352
|
*
|
|
1297
1353
|
* This hook extracts the common data transformation logic used in both line-chart
|
|
1298
1354
|
* and bar-chart components. It:
|
|
1299
|
-
* 1. Parses date strings into Date objects
|
|
1355
|
+
* 1. Parses date strings into Date objects, dated in the provider's time zone
|
|
1300
1356
|
* 2. Sorts data points by date when date properties are present
|
|
1301
1357
|
* 3. Returns the original data unchanged when no date properties are found
|
|
1302
1358
|
*
|
|
@@ -1304,6 +1360,7 @@ const useXYChartTheme = (data) => {
|
|
|
1304
1360
|
* @return {SeriesData[]} The transformed and sorted data
|
|
1305
1361
|
*/
|
|
1306
1362
|
const useChartDataTransform = (data) => {
|
|
1363
|
+
const { timeZone } = useChartFormatting();
|
|
1307
1364
|
return useMemo(() => {
|
|
1308
1365
|
const firstPoint = data?.[0]?.data?.[0];
|
|
1309
1366
|
if (!(firstPoint && ("date" in firstPoint || "dateString" in firstPoint))) return data;
|
|
@@ -1312,7 +1369,7 @@ const useChartDataTransform = (data) => {
|
|
|
1312
1369
|
data: series.data.map((point) => {
|
|
1313
1370
|
let date;
|
|
1314
1371
|
if ("date" in point && point.date) date = point.date;
|
|
1315
|
-
else if ("dateString" in point && point.dateString) date = parseAsLocalDate(point.dateString);
|
|
1372
|
+
else if ("dateString" in point && point.dateString) date = parseAsLocalDate(point.dateString, timeZone);
|
|
1316
1373
|
return {
|
|
1317
1374
|
...point,
|
|
1318
1375
|
date
|
|
@@ -1322,7 +1379,7 @@ const useChartDataTransform = (data) => {
|
|
|
1322
1379
|
return a.date.getTime() - b.date.getTime();
|
|
1323
1380
|
})
|
|
1324
1381
|
}));
|
|
1325
|
-
}, [data]);
|
|
1382
|
+
}, [data, timeZone]);
|
|
1326
1383
|
};
|
|
1327
1384
|
//#endregion
|
|
1328
1385
|
//#region src/hooks/use-chart-margin.tsx
|
|
@@ -1364,11 +1421,32 @@ const DEFAULT_TICK_LENGTH = 8;
|
|
|
1364
1421
|
* measure them via getLongestTickWidth.
|
|
1365
1422
|
*/
|
|
1366
1423
|
const DEFAULT_Y_TICK_WIDTH = 40;
|
|
1424
|
+
/**
|
|
1425
|
+
* Copy a label style with its lengths spelled out in px.
|
|
1426
|
+
*
|
|
1427
|
+
* `getStringWidth` applies the style through CSSOM. Blink resolves a bare number
|
|
1428
|
+
* on an SVG `<text>`, but that is its own leniency rather than the CSS rule, and
|
|
1429
|
+
* `buildChartTheme` hands us bare numbers.
|
|
1430
|
+
*
|
|
1431
|
+
* @param style - Raw label style from the theme.
|
|
1432
|
+
* @return The same style with px-qualified lengths.
|
|
1433
|
+
*/
|
|
1434
|
+
const toMeasurableStyle = (style) => {
|
|
1435
|
+
if (!style) return style;
|
|
1436
|
+
const fontSize = resolveFontSize(style.fontSize);
|
|
1437
|
+
const { letterSpacing } = style;
|
|
1438
|
+
return {
|
|
1439
|
+
...style,
|
|
1440
|
+
...fontSize === void 0 ? {} : { fontSize: `${fontSize}px` },
|
|
1441
|
+
...typeof letterSpacing === "number" ? { letterSpacing: `${letterSpacing}px` } : {}
|
|
1442
|
+
};
|
|
1443
|
+
};
|
|
1367
1444
|
const getXAxisLabelMetrics = (theme, orientation) => {
|
|
1368
1445
|
const xAxisStyles = orientation === "top" ? theme.axisStyles?.x?.top : theme.axisStyles?.x?.bottom;
|
|
1369
1446
|
return {
|
|
1370
1447
|
fontSize: resolveFontSize(xAxisStyles?.axisLabel?.fontSize) || resolveFontSize(theme.svgLabelSmall?.fontSize) || DEFAULT_FONT_SIZE,
|
|
1371
|
-
tickLength: xAxisStyles?.tickLength ?? DEFAULT_TICK_LENGTH
|
|
1448
|
+
tickLength: xAxisStyles?.tickLength ?? DEFAULT_TICK_LENGTH,
|
|
1449
|
+
tickLabelStyle: toMeasurableStyle(xAxisStyles?.tickLabel)
|
|
1372
1450
|
};
|
|
1373
1451
|
};
|
|
1374
1452
|
const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
@@ -1380,7 +1458,7 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1380
1458
|
const maxY = Math.max(...allDataPoints.map((d) => d.value));
|
|
1381
1459
|
const yScale = createScale({
|
|
1382
1460
|
...options.yScale,
|
|
1383
|
-
domain: [minY, maxY],
|
|
1461
|
+
domain: options.yScale?.domain ?? [minY, maxY],
|
|
1384
1462
|
range: [height, 0]
|
|
1385
1463
|
});
|
|
1386
1464
|
return getTicks(yScale, options.axis?.y?.numTicks);
|
|
@@ -1399,18 +1477,25 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1399
1477
|
};
|
|
1400
1478
|
const yAxisOrientation = options.axis?.y?.orientation;
|
|
1401
1479
|
const yAxisStyles = yAxisOrientation === "right" ? theme.axisStyles.y.right : theme.axisStyles.y.left;
|
|
1402
|
-
const yTickWidth = getLongestTickWidth(yTicks, options.axis?.y?.tickFormat, yAxisStyles.axisLabel);
|
|
1480
|
+
const yTickWidth = getLongestTickWidth(yTicks, options.axis?.y?.tickFormat, toMeasurableStyle(yAxisStyles.axisLabel));
|
|
1403
1481
|
const yTickLabelFontSize = resolveFontSize(yAxisStyles?.tickLabel?.fontSize) || DEFAULT_FONT_SIZE;
|
|
1404
1482
|
const yMarginValue = (yTickWidth ?? DEFAULT_Y_TICK_WIDTH) + (yAxisStyles?.tickLength ?? 0) + Math.ceil(yTickLabelFontSize * .25);
|
|
1405
|
-
if (
|
|
1406
|
-
|
|
1483
|
+
if (options.axis?.y?.display !== false) {
|
|
1484
|
+
if (yAxisOrientation === "right") defaultMargin.right = yMarginValue;
|
|
1485
|
+
else defaultMargin.left = yMarginValue;
|
|
1486
|
+
}
|
|
1407
1487
|
const xOrientation = options.axis?.x?.orientation === "top" ? "top" : "bottom";
|
|
1408
|
-
const { fontSize, tickLength } = getXAxisLabelMetrics(theme, xOrientation);
|
|
1488
|
+
const { fontSize, tickLength, tickLabelStyle } = getXAxisLabelMetrics(theme, xOrientation);
|
|
1409
1489
|
const computedXMargin = fontSize + tickLength;
|
|
1410
1490
|
if (xOrientation === "top") {
|
|
1411
1491
|
defaultMargin.top = Math.max(defaultMargin.top, computedXMargin);
|
|
1412
1492
|
defaultMargin.bottom = DEFAULT_BOTTOM_FOR_TOP_AXIS;
|
|
1413
1493
|
} else defaultMargin.bottom = Math.max(defaultMargin.bottom, computedXMargin);
|
|
1494
|
+
if (options.axis?.x?.display !== false) {
|
|
1495
|
+
const { first, last } = getEdgeTickWidths(options.axis?.x?.tickValues ?? [], options.axis?.x?.tickFormat, tickLabelStyle);
|
|
1496
|
+
defaultMargin.left = Math.max(defaultMargin.left, Math.ceil(first / 2));
|
|
1497
|
+
defaultMargin.right = Math.max(defaultMargin.right, Math.ceil(last / 2));
|
|
1498
|
+
}
|
|
1414
1499
|
return defaultMargin;
|
|
1415
1500
|
}, [
|
|
1416
1501
|
options,
|
|
@@ -1686,21 +1771,6 @@ const useGlobalChartsTheme = () => {
|
|
|
1686
1771
|
return useContext(GlobalChartsContext)?.theme ?? defaultTheme;
|
|
1687
1772
|
};
|
|
1688
1773
|
//#endregion
|
|
1689
|
-
//#region src/providers/chart-context/hooks/use-chart-formatting.ts
|
|
1690
|
-
const RUNTIME_FORMATTING = {};
|
|
1691
|
-
/**
|
|
1692
|
-
* The locale and time zone dates are rendered in, as set on `GlobalChartsProvider`.
|
|
1693
|
-
*
|
|
1694
|
-
* Falls back to the runtime's own rather than throwing: charts render outside a
|
|
1695
|
-
* provider, and a host that sets neither gets exactly the browser-default
|
|
1696
|
-
* behavior this package had before the context existed.
|
|
1697
|
-
*
|
|
1698
|
-
* @return The host's formatting context.
|
|
1699
|
-
*/
|
|
1700
|
-
const useChartFormatting = () => {
|
|
1701
|
-
return useContext(GlobalChartsContext)?.formatting ?? RUNTIME_FORMATTING;
|
|
1702
|
-
};
|
|
1703
|
-
//#endregion
|
|
1704
1774
|
//#region src/components/legend/utils/value-or-identity.ts
|
|
1705
1775
|
/**
|
|
1706
1776
|
* Returns an object's value if defined, or the object.
|
|
@@ -2140,6 +2210,8 @@ const BaseTooltip = ({ data, top, left, component: Component = DefaultTooltipCon
|
|
|
2140
2210
|
//#endregion
|
|
2141
2211
|
//#region src/components/tooltip/private/bounded-tooltip.tsx
|
|
2142
2212
|
const DEFAULT_OFFSET = 10;
|
|
2213
|
+
const POINTER_HEIGHT = 6;
|
|
2214
|
+
const clamp = (position, min, max, size) => Math.min(Math.max(position, min), Math.max(min, max - size));
|
|
2143
2215
|
const isClipping = (element) => {
|
|
2144
2216
|
const { overflow, overflowX, overflowY } = getComputedStyle(element);
|
|
2145
2217
|
return [
|
|
@@ -2157,33 +2229,49 @@ const findClippingAncestor = (wrapper) => {
|
|
|
2157
2229
|
return null;
|
|
2158
2230
|
};
|
|
2159
2231
|
/**
|
|
2160
|
-
* Where the box goes, in wrapper coordinates.
|
|
2161
|
-
*
|
|
2162
|
-
*
|
|
2163
|
-
* `bounds` whenever it fits at all.
|
|
2232
|
+
* Where the box goes, in wrapper coordinates. Automatic placement flips to
|
|
2233
|
+
* the side that clips less, then clamps inside `bounds`; below-axis placement
|
|
2234
|
+
* is centered on the anchor and clamped horizontally.
|
|
2164
2235
|
*
|
|
2165
|
-
*
|
|
2236
|
+
* The flip measures against the visible part of the wrapper, its intersection
|
|
2237
|
+
* with `bounds`. Only the clamp is bound by the page: a box that fits inside the
|
|
2238
|
+
* chart on one side stays there, so it does not reach past the chart into
|
|
2239
|
+
* siblings that paint over it.
|
|
2240
|
+
*
|
|
2241
|
+
* @param params - Anchor, offsets, the box size and the rects to keep inside.
|
|
2166
2242
|
* @param params.left - Anchor x, in wrapper coordinates.
|
|
2167
2243
|
* @param params.top - Anchor y, in wrapper coordinates.
|
|
2168
2244
|
* @param params.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2169
2245
|
* @param params.offsetTop - Gap between the anchor and the box, vertically.
|
|
2170
2246
|
* @param params.box - Rendered size of the box.
|
|
2247
|
+
* @param params.wrapper - The wrapper's own edges, in wrapper coordinates.
|
|
2248
|
+
* @param params.placement - Fixed below-axis placement or automatic flipping.
|
|
2171
2249
|
* @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
|
|
2172
|
-
* @return The box's top-left corner
|
|
2250
|
+
* @return The box's top-left corner; fixed placement preserves the axis's subpixel y.
|
|
2173
2251
|
*/
|
|
2174
|
-
const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) => {
|
|
2252
|
+
const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bounds, placement = "auto" }) => {
|
|
2253
|
+
if (placement === "below-axis") return {
|
|
2254
|
+
x: Math.round(clamp(left - box.width / 2, bounds.left, bounds.right, box.width)),
|
|
2255
|
+
y: top + POINTER_HEIGHT
|
|
2256
|
+
};
|
|
2257
|
+
const fit = {
|
|
2258
|
+
left: Math.max(wrapper.left, bounds.left),
|
|
2259
|
+
top: Math.max(wrapper.top, bounds.top),
|
|
2260
|
+
right: Math.min(wrapper.right, bounds.right),
|
|
2261
|
+
bottom: Math.min(wrapper.bottom, bounds.bottom)
|
|
2262
|
+
};
|
|
2175
2263
|
const rightX = left + offsetLeft;
|
|
2176
2264
|
const leftX = left - offsetLeft - box.width;
|
|
2177
|
-
const rightOverflow = rightX + box.width -
|
|
2178
|
-
const leftOverflow =
|
|
2265
|
+
const rightOverflow = rightX + box.width - fit.right;
|
|
2266
|
+
const leftOverflow = fit.left - leftX;
|
|
2179
2267
|
let x = rightOverflow > 0 && rightOverflow > leftOverflow ? leftX : rightX;
|
|
2180
2268
|
const downY = top + offsetTop;
|
|
2181
2269
|
const upY = top - offsetTop - box.height;
|
|
2182
|
-
const downOverflow = downY + box.height -
|
|
2183
|
-
const upOverflow =
|
|
2270
|
+
const downOverflow = downY + box.height - fit.bottom;
|
|
2271
|
+
const upOverflow = fit.top - upY;
|
|
2184
2272
|
let y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
|
|
2185
|
-
x =
|
|
2186
|
-
y =
|
|
2273
|
+
x = clamp(x, bounds.left, bounds.right, box.width);
|
|
2274
|
+
y = clamp(y, bounds.top, bounds.bottom, box.height);
|
|
2187
2275
|
return {
|
|
2188
2276
|
x: Math.round(x),
|
|
2189
2277
|
y: Math.round(y)
|
|
@@ -2197,7 +2285,8 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) =
|
|
|
2197
2285
|
* alone would let the box spill into an `overflow: hidden` card and be cut off.
|
|
2198
2286
|
*
|
|
2199
2287
|
* Re-measures on every render, so a box whose content changes width between
|
|
2200
|
-
* two hovers is placed for its current size.
|
|
2288
|
+
* two hovers is placed for its current size. See `getBoundedPosition` for the
|
|
2289
|
+
* below-axis exception.
|
|
2201
2290
|
*
|
|
2202
2291
|
* @param props - visx `Tooltip` props.
|
|
2203
2292
|
* @param props.left - Anchor x, in wrapper coordinates.
|
|
@@ -2207,9 +2296,10 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) =
|
|
|
2207
2296
|
* @param props.style - Box styles; visx's defaults unless `unstyled`.
|
|
2208
2297
|
* @param props.unstyled - Skip `style` and leave the box bare.
|
|
2209
2298
|
* @param props.children - Box content.
|
|
2299
|
+
* @param props.placement - Fixed below-axis placement or automatic flipping.
|
|
2210
2300
|
* @return The tooltip box.
|
|
2211
2301
|
*/
|
|
2212
|
-
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = defaultStyles, unstyled = false, children, ...rest }) => {
|
|
2302
|
+
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = defaultStyles, unstyled = false, children, placement = "auto", ...rest }) => {
|
|
2213
2303
|
const nodeRef = useRef(null);
|
|
2214
2304
|
const clipRef = useRef(null);
|
|
2215
2305
|
const [position, setPosition] = useState(null);
|
|
@@ -2234,10 +2324,17 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2234
2324
|
top,
|
|
2235
2325
|
offsetLeft,
|
|
2236
2326
|
offsetTop,
|
|
2327
|
+
placement,
|
|
2237
2328
|
box: {
|
|
2238
2329
|
width: own.width,
|
|
2239
2330
|
height: own.height
|
|
2240
2331
|
},
|
|
2332
|
+
wrapper: {
|
|
2333
|
+
left: 0,
|
|
2334
|
+
top: 0,
|
|
2335
|
+
right: wrapperRect.width,
|
|
2336
|
+
bottom: wrapperRect.height
|
|
2337
|
+
},
|
|
2241
2338
|
bounds: {
|
|
2242
2339
|
left: clipRect.left - wrapperRect.left,
|
|
2243
2340
|
top: clipRect.top - wrapperRect.top,
|
|
@@ -2251,11 +2348,12 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2251
2348
|
top,
|
|
2252
2349
|
offsetLeft,
|
|
2253
2350
|
offsetTop,
|
|
2254
|
-
children
|
|
2351
|
+
children,
|
|
2352
|
+
placement
|
|
2255
2353
|
]);
|
|
2256
2354
|
const x = position?.x ?? left + offsetLeft;
|
|
2257
|
-
const y = position?.y ?? top + offsetTop;
|
|
2258
|
-
return /* @__PURE__ */
|
|
2355
|
+
const y = position?.y ?? top + (placement === "below-axis" ? POINTER_HEIGHT : offsetTop);
|
|
2356
|
+
return /* @__PURE__ */ jsxs(Tooltip, {
|
|
2259
2357
|
ref: nodeRef,
|
|
2260
2358
|
style: {
|
|
2261
2359
|
position: "absolute",
|
|
@@ -2265,12 +2363,40 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2265
2363
|
...!unstyled && style
|
|
2266
2364
|
},
|
|
2267
2365
|
...rest,
|
|
2268
|
-
children
|
|
2366
|
+
children: [placement === "below-axis" && /* @__PURE__ */ jsx("span", {
|
|
2367
|
+
"aria-hidden": "true",
|
|
2368
|
+
style: {
|
|
2369
|
+
position: "absolute",
|
|
2370
|
+
left: left - x - POINTER_HEIGHT,
|
|
2371
|
+
top: -6,
|
|
2372
|
+
width: 12,
|
|
2373
|
+
height: POINTER_HEIGHT,
|
|
2374
|
+
background: "inherit",
|
|
2375
|
+
clipPath: "polygon(50% 0, 100% 100%, 0 100%)",
|
|
2376
|
+
pointerEvents: "none"
|
|
2377
|
+
}
|
|
2378
|
+
}), children]
|
|
2269
2379
|
});
|
|
2270
2380
|
};
|
|
2271
2381
|
//#endregion
|
|
2272
2382
|
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2273
2383
|
const CROSSHAIR_STROKE_WIDTH = 1.5;
|
|
2384
|
+
const CROSSHAIR_PAINT_PROPERTIES = /* @__PURE__ */ new Set([
|
|
2385
|
+
"stroke",
|
|
2386
|
+
"strokeWidth",
|
|
2387
|
+
"strokeOpacity",
|
|
2388
|
+
"strokeDasharray",
|
|
2389
|
+
"strokeLinecap",
|
|
2390
|
+
"opacity"
|
|
2391
|
+
]);
|
|
2392
|
+
const crosshairPaintProps = (props = {}) => {
|
|
2393
|
+
const pickPaint = (value) => Object.fromEntries(Object.entries(value).filter(([key]) => CROSSHAIR_PAINT_PROPERTIES.has(key)));
|
|
2394
|
+
return {
|
|
2395
|
+
...pickPaint(props),
|
|
2396
|
+
...props.className === void 0 ? {} : { className: props.className },
|
|
2397
|
+
...props.style === void 0 ? {} : { style: pickPaint(props.style) }
|
|
2398
|
+
};
|
|
2399
|
+
};
|
|
2274
2400
|
const DEFAULT_GLYPH_RADIUS = 4;
|
|
2275
2401
|
const FALLBACK_COLOR = "#222";
|
|
2276
2402
|
const DEFAULT_TOOLTIP_Z_INDEX = 3;
|
|
@@ -2301,7 +2427,7 @@ const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ jsx(DefaultG
|
|
|
2301
2427
|
seriesKey: key,
|
|
2302
2428
|
...props
|
|
2303
2429
|
}, key);
|
|
2304
|
-
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, zIndex = DEFAULT_TOOLTIP_Z_INDEX, ...rest }) => {
|
|
2430
|
+
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", zIndex = DEFAULT_TOOLTIP_Z_INDEX, style, ...rest }) => {
|
|
2305
2431
|
const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
|
|
2306
2432
|
const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = useContext(DataContext) || {};
|
|
2307
2433
|
const tooltipContent = renderTooltip ? renderTooltip({
|
|
@@ -2320,9 +2446,9 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2320
2446
|
};
|
|
2321
2447
|
const nearestDatum = tooltipContext.tooltipData?.nearestDatum;
|
|
2322
2448
|
let { tooltipLeft, tooltipTop } = tooltipContext;
|
|
2323
|
-
if (nearestDatum && (snapTooltipToDatumX || snapTooltipToDatumY)) {
|
|
2449
|
+
if (nearestDatum && (snapTooltipToDatumX || snapTooltipToDatumY || tooltipPlacement === "below-axis")) {
|
|
2324
2450
|
const { left, top } = getDatumLeftTop(nearestDatum.key, nearestDatum.datum);
|
|
2325
|
-
if (snapTooltipToDatumX && isValidNumber(left)) tooltipLeft = left;
|
|
2451
|
+
if ((snapTooltipToDatumX || tooltipPlacement === "below-axis") && isValidNumber(left)) tooltipLeft = left;
|
|
2326
2452
|
if (snapTooltipToDatumY && isValidNumber(top)) tooltipTop = top;
|
|
2327
2453
|
}
|
|
2328
2454
|
const glyphs = [];
|
|
@@ -2356,13 +2482,14 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2356
2482
|
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2357
2483
|
const marginTop = margin?.top ?? 0;
|
|
2358
2484
|
const marginLeft = margin?.left ?? 0;
|
|
2359
|
-
const TooltipComponent = detectBounds ? BoundedTooltip : Tooltip;
|
|
2485
|
+
const TooltipComponent = detectBounds || tooltipPlacement === "below-axis" ? BoundedTooltip : Tooltip;
|
|
2360
2486
|
const boxStyle = {
|
|
2361
2487
|
...defaultStyles,
|
|
2362
2488
|
zIndex,
|
|
2363
|
-
|
|
2489
|
+
backgroundColor: theme?.backgroundColor ?? "white",
|
|
2364
2490
|
boxShadow: `0 1px 2px ${theme?.htmlLabel?.color ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2365
|
-
...theme?.htmlLabel
|
|
2491
|
+
...theme?.htmlLabel,
|
|
2492
|
+
...style
|
|
2366
2493
|
};
|
|
2367
2494
|
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("g", {
|
|
2368
2495
|
className: "visx-tooltip-overlay",
|
|
@@ -2370,32 +2497,33 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2370
2497
|
children: [
|
|
2371
2498
|
showVerticalCrosshair && isValidNumber(tooltipLeft) && /* @__PURE__ */ jsx("line", {
|
|
2372
2499
|
className: "visx-crosshair visx-crosshair-vertical",
|
|
2500
|
+
stroke: crosshairStroke,
|
|
2501
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2502
|
+
...crosshairPaintProps(verticalCrosshairStyle),
|
|
2373
2503
|
x1: tooltipLeft,
|
|
2374
2504
|
x2: tooltipLeft,
|
|
2375
2505
|
y1: marginTop,
|
|
2376
|
-
y2: marginTop + innerHeight
|
|
2377
|
-
stroke: crosshairStroke,
|
|
2378
|
-
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2379
|
-
...verticalCrosshairStyle
|
|
2506
|
+
y2: marginTop + innerHeight
|
|
2380
2507
|
}),
|
|
2381
2508
|
showHorizontalCrosshair && isValidNumber(tooltipTop) && /* @__PURE__ */ jsx("line", {
|
|
2382
2509
|
className: "visx-crosshair visx-crosshair-horizontal",
|
|
2510
|
+
stroke: crosshairStroke,
|
|
2511
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2512
|
+
...crosshairPaintProps(horizontalCrosshairStyle),
|
|
2383
2513
|
x1: marginLeft,
|
|
2384
2514
|
x2: marginLeft + innerWidth,
|
|
2385
2515
|
y1: tooltipTop,
|
|
2386
|
-
y2: tooltipTop
|
|
2387
|
-
stroke: crosshairStroke,
|
|
2388
|
-
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2389
|
-
...horizontalCrosshairStyle
|
|
2516
|
+
y2: tooltipTop
|
|
2390
2517
|
}),
|
|
2391
2518
|
glyphs
|
|
2392
2519
|
]
|
|
2393
2520
|
}), container && createPortal(/* @__PURE__ */ jsx(TooltipComponent, {
|
|
2394
2521
|
left: tooltipLeft,
|
|
2395
|
-
top: tooltipTop,
|
|
2522
|
+
top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipTop,
|
|
2396
2523
|
style: boxStyle,
|
|
2397
2524
|
applyPositionStyle: true,
|
|
2398
2525
|
...tooltipProps,
|
|
2526
|
+
...tooltipPlacement === "below-axis" && { placement: tooltipPlacement },
|
|
2399
2527
|
children: tooltipContent
|
|
2400
2528
|
}), container)] });
|
|
2401
2529
|
};
|
|
@@ -2416,7 +2544,8 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2416
2544
|
* isolation keeps the box's `zIndex` from competing with page chrome. The box
|
|
2417
2545
|
* flips and clamps to stay inside the nearest ancestor that clips its overflow
|
|
2418
2546
|
* (or the viewport), so it may extend past the chart wrapper but is never cut
|
|
2419
|
-
* off unless that ancestor is smaller than the box itself.
|
|
2547
|
+
* off unless that ancestor is smaller than the box itself. Below-axis placement
|
|
2548
|
+
* pins it beneath the x-axis and applies horizontal bounds only.
|
|
2420
2549
|
*
|
|
2421
2550
|
* @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
|
|
2422
2551
|
* @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
|
|
@@ -2533,11 +2662,14 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2533
2662
|
renderTooltip: focusableRenderTooltip
|
|
2534
2663
|
});
|
|
2535
2664
|
};
|
|
2536
|
-
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate }) => {
|
|
2665
|
+
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false }) => {
|
|
2537
2666
|
return {
|
|
2538
2667
|
tooltipRef: useCallback((element) => {
|
|
2539
|
-
if (element && selectedIndex !== void 0)
|
|
2540
|
-
|
|
2668
|
+
if (element && selectedIndex !== void 0) {
|
|
2669
|
+
if (preventTooltipScroll) element.focus({ preventScroll: true });
|
|
2670
|
+
else element.focus();
|
|
2671
|
+
}
|
|
2672
|
+
}, [preventTooltipScroll, selectedIndex]),
|
|
2541
2673
|
onChartFocus: useCallback(() => {
|
|
2542
2674
|
if (!isNavigating && selectedIndex !== void 0) setSelectedIndex(0);
|
|
2543
2675
|
}, [
|
|
@@ -3869,10 +4001,11 @@ const TooltipDate = ({ date, displayResolution }) => {
|
|
|
3869
4001
|
* one row per visible series (label + formatted value), sorted descending by
|
|
3870
4002
|
* value. Reused by AreaChart, which has the same multi-series shape.
|
|
3871
4003
|
*
|
|
3872
|
-
* @param params
|
|
4004
|
+
* @param params - visx tooltip data and the chart's optional `bucketInfo`.
|
|
4005
|
+
* @param contentStyle - Explicit tooltip content color overrides.
|
|
3873
4006
|
* @return Tooltip JSX, or `null` when no datum is hovered.
|
|
3874
4007
|
*/
|
|
3875
|
-
const renderDefaultTooltip = (params) => {
|
|
4008
|
+
const renderDefaultTooltip = (params, contentStyle) => {
|
|
3876
4009
|
const { tooltipData, bucketInfo } = params;
|
|
3877
4010
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
3878
4011
|
if (!nearestDatum) return null;
|
|
@@ -3882,6 +4015,7 @@ const renderDefaultTooltip = (params) => {
|
|
|
3882
4015
|
})).sort((a, b) => b.value - a.value);
|
|
3883
4016
|
return /* @__PURE__ */ jsxs("div", {
|
|
3884
4017
|
className: line_chart_module_default["line-chart__tooltip"],
|
|
4018
|
+
style: contentStyle,
|
|
3885
4019
|
children: [/* @__PURE__ */ jsx("div", {
|
|
3886
4020
|
className: line_chart_module_default["line-chart__tooltip-date"],
|
|
3887
4021
|
children: /* @__PURE__ */ jsx(TooltipDate, {
|
|
@@ -3931,7 +4065,7 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
3931
4065
|
]);
|
|
3932
4066
|
return null;
|
|
3933
4067
|
};
|
|
3934
|
-
const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, onDatumActivate = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
4068
|
+
const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, tooltipPlacement, tooltipStyle, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, onDatumActivate = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
3935
4069
|
const legendInteractive = legend.interactive ?? false;
|
|
3936
4070
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
3937
4071
|
const legendShape = legend.shape ?? "line";
|
|
@@ -4009,7 +4143,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4009
4143
|
setIsNavigating,
|
|
4010
4144
|
chartRef,
|
|
4011
4145
|
totalPoints: dataSorted[0]?.data.length || 0,
|
|
4012
|
-
onActivate: activateSelectedPoint
|
|
4146
|
+
onActivate: activateSelectedPoint,
|
|
4147
|
+
preventTooltipScroll: tooltipPlacement === "below-axis"
|
|
4013
4148
|
});
|
|
4014
4149
|
const chartOptions = useMemo(() => {
|
|
4015
4150
|
return {
|
|
@@ -4118,10 +4253,29 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4118
4253
|
xAccessor: (d) => d?.date,
|
|
4119
4254
|
yAccessor: (d) => d?.value
|
|
4120
4255
|
};
|
|
4121
|
-
const
|
|
4256
|
+
const resolvedTooltipStyle = useMemo(() => {
|
|
4257
|
+
if (renderTooltip !== renderDefaultTooltip || !tooltipStyle) return tooltipStyle;
|
|
4258
|
+
if (!tooltipStyle.color || tooltipStyle.background || tooltipStyle.backgroundColor) return tooltipStyle;
|
|
4259
|
+
return {
|
|
4260
|
+
backgroundColor: "var(--a8c-charts-color-tooltip-surface, rgb(0 0 0 / 85%))",
|
|
4261
|
+
...tooltipStyle
|
|
4262
|
+
};
|
|
4263
|
+
}, [renderTooltip, tooltipStyle]);
|
|
4264
|
+
const tooltipRenderer = useMemo(() => (params) => renderTooltip === renderDefaultTooltip ? renderDefaultTooltip({
|
|
4122
4265
|
...params,
|
|
4123
4266
|
bucketInfo
|
|
4124
|
-
}
|
|
4267
|
+
}, {
|
|
4268
|
+
color: tooltipStyle?.color,
|
|
4269
|
+
background: tooltipStyle?.background,
|
|
4270
|
+
backgroundColor: tooltipStyle?.backgroundColor
|
|
4271
|
+
}) : renderTooltip({
|
|
4272
|
+
...params,
|
|
4273
|
+
bucketInfo
|
|
4274
|
+
}), [
|
|
4275
|
+
renderTooltip,
|
|
4276
|
+
bucketInfo,
|
|
4277
|
+
tooltipStyle
|
|
4278
|
+
]);
|
|
4125
4279
|
if (error) return /* @__PURE__ */ jsx("div", {
|
|
4126
4280
|
className: clsx("line-chart", line_chart_module_default["line-chart"]),
|
|
4127
4281
|
children: error
|
|
@@ -4260,6 +4414,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4260
4414
|
withTooltips && /* @__PURE__ */ jsx(AccessibleTooltip, {
|
|
4261
4415
|
detectBounds: true,
|
|
4262
4416
|
snapTooltipToDatumX: true,
|
|
4417
|
+
tooltipPlacement,
|
|
4418
|
+
style: resolvedTooltipStyle,
|
|
4263
4419
|
snapTooltipToDatumY: true,
|
|
4264
4420
|
showSeriesGlyphs: true,
|
|
4265
4421
|
renderTooltip: tooltipRenderer,
|
|
@@ -4267,6 +4423,8 @@ const LineChartInternal = forwardRef(({ data, chartId: providedChartId, width, h
|
|
|
4267
4423
|
glyphStyle,
|
|
4268
4424
|
showVerticalCrosshair: withTooltipCrosshairs?.showVertical,
|
|
4269
4425
|
showHorizontalCrosshair: withTooltipCrosshairs?.showHorizontal,
|
|
4426
|
+
verticalCrosshairStyle: withTooltipCrosshairs?.verticalStyle,
|
|
4427
|
+
horizontalCrosshairStyle: withTooltipCrosshairs?.horizontalStyle,
|
|
4270
4428
|
selectedIndex,
|
|
4271
4429
|
tooltipRef,
|
|
4272
4430
|
keyboardFocusedClassName: line_chart_module_default["line-chart__tooltip--keyboard-focused"],
|
|
@@ -6419,9 +6577,13 @@ var heatmap_chart_module_default = {
|
|
|
6419
6577
|
"heatmap-chart__cell--placeholder": "a8ccharts-O3YMOW-heatmap-chart__cell--placeholder",
|
|
6420
6578
|
"heatmap-chart__cell--selected": "a8ccharts-O3YMOW-heatmap-chart__cell--selected",
|
|
6421
6579
|
"heatmap-chart__cell--strong": "a8ccharts-O3YMOW-heatmap-chart__cell--strong",
|
|
6580
|
+
"heatmap-chart__cell--summary": "a8ccharts-O3YMOW-heatmap-chart__cell--summary",
|
|
6422
6581
|
"heatmap-chart__cell-value": "a8ccharts-O3YMOW-heatmap-chart__cell-value",
|
|
6423
6582
|
"heatmap-chart__col-label": "a8ccharts-O3YMOW-heatmap-chart__col-label",
|
|
6583
|
+
"heatmap-chart__col-label--summary": "a8ccharts-O3YMOW-heatmap-chart__col-label--summary",
|
|
6424
6584
|
"heatmap-chart__empty": "a8ccharts-O3YMOW-heatmap-chart__empty",
|
|
6585
|
+
"heatmap-chart__gap-end": "a8ccharts-O3YMOW-heatmap-chart__gap-end",
|
|
6586
|
+
"heatmap-chart__gap-start": "a8ccharts-O3YMOW-heatmap-chart__gap-start",
|
|
6425
6587
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
6426
6588
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
6427
6589
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
@@ -6435,17 +6597,21 @@ var heatmap_chart_module_default = {
|
|
|
6435
6597
|
//#region src/charts/heatmap-chart/private/use-heatmap-colors.ts
|
|
6436
6598
|
const isPresent = (value) => value !== null && value !== void 0 && !isNaN(value);
|
|
6437
6599
|
/**
|
|
6438
|
-
* Get the min and max values from heatmap data, ignoring null/NaN.
|
|
6600
|
+
* Get the min and max values from heatmap data, ignoring null/NaN. Summary
|
|
6601
|
+
* columns stay out: a roll-up on the scale would flatten every real cell.
|
|
6439
6602
|
* @param data - The heatmap columns
|
|
6440
6603
|
* @return Tuple of [min, max] values
|
|
6441
6604
|
*/
|
|
6442
6605
|
const getValueExtent = (data) => {
|
|
6443
6606
|
let min = Infinity;
|
|
6444
6607
|
let max = -Infinity;
|
|
6445
|
-
for (const column of data)
|
|
6446
|
-
if (
|
|
6447
|
-
|
|
6448
|
-
|
|
6608
|
+
for (const column of data) {
|
|
6609
|
+
if (column.summary) continue;
|
|
6610
|
+
for (const cell of column.data) {
|
|
6611
|
+
if (!isPresent(cell.value)) continue;
|
|
6612
|
+
if (cell.value < min) min = cell.value;
|
|
6613
|
+
if (cell.value > max) max = cell.value;
|
|
6614
|
+
}
|
|
6449
6615
|
}
|
|
6450
6616
|
if (min === Infinity) return [0, 0];
|
|
6451
6617
|
return [min, max];
|
|
@@ -6466,6 +6632,119 @@ const getNormalizedValue = (value, extent) => {
|
|
|
6466
6632
|
return Math.min(1, Math.max(0, (value - min) / (max - min)));
|
|
6467
6633
|
};
|
|
6468
6634
|
//#endregion
|
|
6635
|
+
//#region src/charts/heatmap-chart/private/civil-day.ts
|
|
6636
|
+
const DAY_MS = 864e5;
|
|
6637
|
+
const KEY_OPTIONS = {
|
|
6638
|
+
calendar: "gregory",
|
|
6639
|
+
numberingSystem: "latn",
|
|
6640
|
+
year: "numeric",
|
|
6641
|
+
month: "2-digit",
|
|
6642
|
+
day: "2-digit"
|
|
6643
|
+
};
|
|
6644
|
+
const DATE_PREFIX = /^(\d{4})-(\d{2})-(\d{2})/;
|
|
6645
|
+
const pad = (value, length) => String(value).padStart(length, "0");
|
|
6646
|
+
/**
|
|
6647
|
+
* The day a UTC proxy stands for.
|
|
6648
|
+
*
|
|
6649
|
+
* @param date - UTC proxy.
|
|
6650
|
+
* @return Its day key.
|
|
6651
|
+
*/
|
|
6652
|
+
const civilKey = (date) => `${pad(date.getUTCFullYear(), 4)}-${pad(date.getUTCMonth() + 1, 2)}-${pad(date.getUTCDate(), 2)}`;
|
|
6653
|
+
/**
|
|
6654
|
+
* A day key as a UTC-midnight proxy. UTC has no DST, so every step below is exactly
|
|
6655
|
+
* `DAY_MS`.
|
|
6656
|
+
*
|
|
6657
|
+
* @param key - Day key.
|
|
6658
|
+
* @return The proxy, or null when the key names no real day.
|
|
6659
|
+
*/
|
|
6660
|
+
const civilDate = (key) => {
|
|
6661
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(key);
|
|
6662
|
+
if (!match) return null;
|
|
6663
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
6664
|
+
date.setUTCFullYear(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
|
|
6665
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
6666
|
+
return civilKey(date) === key ? date : null;
|
|
6667
|
+
};
|
|
6668
|
+
/**
|
|
6669
|
+
* The day a written date names, ignoring any time and zone it carries.
|
|
6670
|
+
*
|
|
6671
|
+
* @param text - `yyyy-MM-dd`, optionally followed by a time.
|
|
6672
|
+
* @return Its day key, or null.
|
|
6673
|
+
*/
|
|
6674
|
+
const writtenDayKey = (text) => {
|
|
6675
|
+
const match = DATE_PREFIX.exec(text);
|
|
6676
|
+
if (!match) return null;
|
|
6677
|
+
const key = `${match[1]}-${match[2]}-${match[3]}`;
|
|
6678
|
+
return civilDate(key) ? key : null;
|
|
6679
|
+
};
|
|
6680
|
+
/**
|
|
6681
|
+
* Reads the day an instant falls on in a zone.
|
|
6682
|
+
*
|
|
6683
|
+
* @param timeZone - IANA zone name; absent leaves the runtime's own.
|
|
6684
|
+
* @return Reader taking a `Date`, null for a day no key can hold.
|
|
6685
|
+
*/
|
|
6686
|
+
const instantDayReader = (timeZone) => {
|
|
6687
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
6688
|
+
...KEY_OPTIONS,
|
|
6689
|
+
timeZone
|
|
6690
|
+
});
|
|
6691
|
+
return (date) => {
|
|
6692
|
+
const parts = formatter.formatToParts(date);
|
|
6693
|
+
const read = (type) => parts.find((part) => part.type === type)?.value ?? "";
|
|
6694
|
+
const key = `${pad(Number(read("year")), 4)}-${read("month")}-${read("day")}`;
|
|
6695
|
+
return civilDate(key) ? key : null;
|
|
6696
|
+
};
|
|
6697
|
+
};
|
|
6698
|
+
/**
|
|
6699
|
+
* The day a series point belongs to.
|
|
6700
|
+
*
|
|
6701
|
+
* A `Date`, or a string carrying `Z` or an offset, is an instant read in the host's
|
|
6702
|
+
* zone. Anything else is a wall clock the host wrote, so its date part is the day.
|
|
6703
|
+
*
|
|
6704
|
+
* @param point - Series point.
|
|
6705
|
+
* @param readInstant - Reader from `instantDayReader`.
|
|
6706
|
+
* @return Its day key, or null when the point carries no usable date.
|
|
6707
|
+
*/
|
|
6708
|
+
const pointDayKey = (point, readInstant) => {
|
|
6709
|
+
if (point.date instanceof Date && !isNaN(point.date.getTime())) {
|
|
6710
|
+
const key = readInstant(point.date);
|
|
6711
|
+
if (key) return key;
|
|
6712
|
+
}
|
|
6713
|
+
const text = point.dateString;
|
|
6714
|
+
if (!text) return null;
|
|
6715
|
+
if (!hasTimezone(text)) return writtenDayKey(text);
|
|
6716
|
+
const parsed = parseISO(text);
|
|
6717
|
+
return isNaN(parsed.getTime()) ? null : readInstant(parsed);
|
|
6718
|
+
};
|
|
6719
|
+
/**
|
|
6720
|
+
* Steps a proxy by whole days.
|
|
6721
|
+
*
|
|
6722
|
+
* @param date - UTC proxy.
|
|
6723
|
+
* @param days - Days to add; may be negative.
|
|
6724
|
+
* @return The shifted proxy.
|
|
6725
|
+
*/
|
|
6726
|
+
const addCivilDays = (date, days) => new Date(date.getTime() + days * DAY_MS);
|
|
6727
|
+
/**
|
|
6728
|
+
* Rounds a proxy down to its week.
|
|
6729
|
+
*
|
|
6730
|
+
* @param date - UTC proxy.
|
|
6731
|
+
* @param weekStartsOn - 0 for Sunday, 1 for Monday.
|
|
6732
|
+
* @return The proxy for that week's first day.
|
|
6733
|
+
*/
|
|
6734
|
+
const startOfCivilWeek = (date, weekStartsOn) => {
|
|
6735
|
+
const daysSinceWeekStart = (date.getUTCDay() - weekStartsOn + 7) % 7;
|
|
6736
|
+
return addCivilDays(date, -daysSinceWeekStart);
|
|
6737
|
+
};
|
|
6738
|
+
/**
|
|
6739
|
+
* Counts the columns a span needs.
|
|
6740
|
+
*
|
|
6741
|
+
* @param from - Earlier UTC proxy.
|
|
6742
|
+
* @param to - Later UTC proxy.
|
|
6743
|
+
* @param weekStartsOn - 0 for Sunday, 1 for Monday.
|
|
6744
|
+
* @return Columns needed to cover the span, inclusive.
|
|
6745
|
+
*/
|
|
6746
|
+
const civilWeekSpan = (from, to, weekStartsOn) => Math.floor((startOfCivilWeek(to, weekStartsOn).getTime() - startOfCivilWeek(from, weekStartsOn).getTime()) / (7 * DAY_MS)) + 1;
|
|
6747
|
+
//#endregion
|
|
6469
6748
|
//#region src/charts/heatmap-chart/private/build-calendar-data.ts
|
|
6470
6749
|
/** Rows that get a weekday label (Mon, Wed, Fri with a Monday week start). */
|
|
6471
6750
|
const LABELLED_ROWS = [
|
|
@@ -6480,69 +6759,88 @@ const LABELLED_ROWS = [
|
|
|
6480
6759
|
* @param bound - Requested bound as `yyyy-MM-dd`, if any.
|
|
6481
6760
|
* @param fallback - The series' own bound on this side.
|
|
6482
6761
|
* @param direction - Which way the bound is allowed to move.
|
|
6483
|
-
* @return The
|
|
6762
|
+
* @return The day key to draw to.
|
|
6484
6763
|
*/
|
|
6485
6764
|
const widenTo = (bound, fallback, direction) => {
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
return parsed > fallback ? parsed : fallback;
|
|
6491
|
-
};
|
|
6492
|
-
const toDate = (point) => {
|
|
6493
|
-
if (point.date instanceof Date && !isNaN(point.date.getTime())) return point.date;
|
|
6494
|
-
if (point.dateString) {
|
|
6495
|
-
const parsed = parseISO(point.dateString);
|
|
6496
|
-
if (!isNaN(parsed.getTime())) return parsed;
|
|
6765
|
+
const key = bound ? writtenDayKey(bound) : null;
|
|
6766
|
+
if (!key) {
|
|
6767
|
+
if (bound) warnOnce(`heatmap:gridSpan:${bound}`, `gridSpan.${direction === "earlier" ? "start" : "end"} ${JSON.stringify(bound)} is not a \`yyyy-MM-dd\` day, so the grid is drawn over the series' own span.`);
|
|
6768
|
+
return fallback;
|
|
6497
6769
|
}
|
|
6498
|
-
return
|
|
6770
|
+
if (direction === "earlier") return key < fallback ? key : fallback;
|
|
6771
|
+
return key > fallback ? key : fallback;
|
|
6499
6772
|
};
|
|
6773
|
+
/**
|
|
6774
|
+
* Lay a day-bucketed series out as calendar columns.
|
|
6775
|
+
*
|
|
6776
|
+
* @param series - Points to bucket.
|
|
6777
|
+
* @param options - Grid shape, plus the locale and zone to read days in.
|
|
6778
|
+
* @return Columns and row labels for `HeatmapChart`.
|
|
6779
|
+
*/
|
|
6500
6780
|
const buildCalendarHeatmapData = (series, options = {}) => {
|
|
6501
6781
|
const weekStartsOn = options.weekStartsOn ?? 1;
|
|
6502
6782
|
const hideOutOfRangeDays = options.hideOutOfRangeDays ?? true;
|
|
6503
|
-
const
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
})
|
|
6507
|
-
|
|
6783
|
+
const { locale, timeZone } = sanitizeFormatting({
|
|
6784
|
+
locale: options.locale,
|
|
6785
|
+
timeZone: options.timeZone
|
|
6786
|
+
});
|
|
6787
|
+
const readInstant = instantDayReader(timeZone);
|
|
6788
|
+
const valueByDay = /* @__PURE__ */ new Map();
|
|
6789
|
+
let minDayKey;
|
|
6790
|
+
let maxDayKey;
|
|
6791
|
+
for (const point of series) {
|
|
6792
|
+
const key = pointDayKey(point, readInstant);
|
|
6793
|
+
if (!key) {
|
|
6794
|
+
const offending = point.dateString ?? (point.date && String(point.date));
|
|
6795
|
+
warnOnce(`heatmap:unreadableDate:${offending}`, offending ? `${JSON.stringify(offending)} is not a day this can read, so its point is left out of the calendar. A \`dateString\` must start \`yyyy-MM-dd\`.` : "A point carries neither `date` nor `dateString`, so it is left out of the calendar.");
|
|
6796
|
+
continue;
|
|
6797
|
+
}
|
|
6798
|
+
valueByDay.set(key, point.value);
|
|
6799
|
+
if (!minDayKey || key < minDayKey) minDayKey = key;
|
|
6800
|
+
if (!maxDayKey || key > maxDayKey) maxDayKey = key;
|
|
6801
|
+
}
|
|
6802
|
+
if (!minDayKey || !maxDayKey) return {
|
|
6508
6803
|
data: [],
|
|
6509
6804
|
rowLabels: []
|
|
6510
6805
|
};
|
|
6511
|
-
const
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
}
|
|
6519
|
-
const
|
|
6520
|
-
const
|
|
6521
|
-
const
|
|
6522
|
-
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
const
|
|
6806
|
+
const requestedMinDayKey = widenTo(options.gridSpan?.start, minDayKey, "earlier");
|
|
6807
|
+
const gridMaxDayKey = widenTo(options.gridSpan?.end, maxDayKey, "later");
|
|
6808
|
+
const requestedMinDate = civilDate(requestedMinDayKey);
|
|
6809
|
+
const gridMaxDate = civilDate(gridMaxDayKey);
|
|
6810
|
+
const labelFormatting = {
|
|
6811
|
+
locale,
|
|
6812
|
+
timeZone: "UTC"
|
|
6813
|
+
};
|
|
6814
|
+
const formatWeekday = createDateFormatter({ weekday: "short" }, labelFormatting);
|
|
6815
|
+
const formatMonth = createDateFormatter({ month: "short" }, labelFormatting);
|
|
6816
|
+
const formatDay = createDateFormatter({
|
|
6817
|
+
weekday: "short",
|
|
6818
|
+
month: "short",
|
|
6819
|
+
day: "numeric",
|
|
6820
|
+
year: "numeric"
|
|
6821
|
+
}, labelFormatting);
|
|
6822
|
+
const gridStart = startOfCivilWeek(requestedMinDate, weekStartsOn);
|
|
6823
|
+
const gridMinDayKey = requestedMinDayKey < minDayKey ? civilKey(gridStart) : requestedMinDayKey;
|
|
6824
|
+
const weekCount = civilWeekSpan(gridStart, gridMaxDate, weekStartsOn);
|
|
6825
|
+
const rowLabels = Array.from({ length: 7 }, (_, row) => LABELLED_ROWS.includes(row) ? formatWeekday(addCivilDays(gridStart, row)) : "");
|
|
6528
6826
|
const MIN_FIRST_MONTH_WEEKS = 2;
|
|
6529
|
-
const firstMonth = gridStart.
|
|
6827
|
+
const firstMonth = gridStart.getUTCMonth();
|
|
6530
6828
|
let firstMonthWeeks = 0;
|
|
6531
|
-
while (firstMonthWeeks < weekCount &&
|
|
6829
|
+
while (firstMonthWeeks < weekCount && addCivilDays(gridStart, firstMonthWeeks * 7).getUTCMonth() === firstMonth) firstMonthWeeks++;
|
|
6532
6830
|
const showFirstMonthLabel = !(firstMonthWeeks < weekCount) || firstMonthWeeks >= MIN_FIRST_MONTH_WEEKS;
|
|
6533
6831
|
const data = [];
|
|
6534
6832
|
let previousMonth = -1;
|
|
6535
6833
|
for (let week = 0; week < weekCount; week++) {
|
|
6536
|
-
const columnStart =
|
|
6537
|
-
const month = columnStart.
|
|
6538
|
-
const label = month !== previousMonth && (week !== 0 || showFirstMonthLabel) ?
|
|
6834
|
+
const columnStart = addCivilDays(gridStart, week * 7);
|
|
6835
|
+
const month = columnStart.getUTCMonth();
|
|
6836
|
+
const label = month !== previousMonth && (week !== 0 || showFirstMonthLabel) ? formatMonth(columnStart) : "";
|
|
6539
6837
|
previousMonth = month;
|
|
6540
6838
|
const cells = [];
|
|
6541
6839
|
for (let row = 0; row < 7; row++) {
|
|
6542
|
-
const day =
|
|
6543
|
-
const key =
|
|
6840
|
+
const day = addCivilDays(gridStart, week * 7 + row);
|
|
6841
|
+
const key = civilKey(day);
|
|
6544
6842
|
const cell = {
|
|
6545
|
-
label:
|
|
6843
|
+
label: formatDay(day),
|
|
6546
6844
|
value: valueByDay.has(key) ? valueByDay.get(key) : null
|
|
6547
6845
|
};
|
|
6548
6846
|
if (key < gridMinDayKey || key > gridMaxDayKey) {
|
|
@@ -6610,7 +6908,8 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6610
6908
|
//#endregion
|
|
6611
6909
|
//#region src/charts/heatmap-chart/heatmap-chart.tsx
|
|
6612
6910
|
const CELL_MIX_FLOOR = .15;
|
|
6613
|
-
const
|
|
6911
|
+
const NO_ROW_LABELS = [];
|
|
6912
|
+
const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, height = 0, className, compact = false, showValues, maxCellWidth, maxCellHeight, minCellWidth, minCellHeight, rowLabels = NO_ROW_LABELS, primaryColor, gap = "md", withTooltips = false, renderTooltip, children }) => {
|
|
6614
6913
|
const chartId = useChartId(providedChartId);
|
|
6615
6914
|
const { getElementStyles, theme } = useGlobalChartsContext();
|
|
6616
6915
|
const scopeElement = useChartScopeElement();
|
|
@@ -6761,13 +7060,20 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6761
7060
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
6762
7061
|
const gridStyle = {
|
|
6763
7062
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6764
|
-
gridTemplateColumns: `auto repeat(${columns}, ${columnTrack})`,
|
|
7063
|
+
gridTemplateColumns: `auto ${data.some((column) => column.summary) ? data.map((column) => column.summary ? "minmax(auto, max-content)" : columnTrack).join(" ") : `repeat(${columns}, ${columnTrack})`}`,
|
|
6765
7064
|
gridTemplateRows: `auto repeat(${rows}, ${rowTrack})`
|
|
6766
7065
|
};
|
|
6767
7066
|
if (compact) {
|
|
6768
7067
|
gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
|
|
6769
7068
|
gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${compactCellSize}px`;
|
|
6770
7069
|
}
|
|
7070
|
+
const summaryGaps = (columnIndex) => {
|
|
7071
|
+
if (!data[columnIndex]?.summary) return {};
|
|
7072
|
+
return {
|
|
7073
|
+
[heatmap_chart_module_default["heatmap-chart__gap-start"]]: columnIndex > 0 && !data[columnIndex - 1]?.summary,
|
|
7074
|
+
[heatmap_chart_module_default["heatmap-chart__gap-end"]]: columnIndex < columns - 1 && !data[columnIndex + 1]?.summary
|
|
7075
|
+
};
|
|
7076
|
+
};
|
|
6771
7077
|
const activeDescendant = selectedIndex !== void 0 ? `${chartId}-cell-${Math.floor(selectedIndex / rows)}-${selectedIndex % rows}` : void 0;
|
|
6772
7078
|
const heightCapped = !compact && Boolean(maxCellHeight);
|
|
6773
7079
|
return /* @__PURE__ */ jsx(HeatmapContext.Provider, {
|
|
@@ -6805,7 +7111,10 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6805
7111
|
"aria-hidden": "true",
|
|
6806
7112
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
6807
7113
|
children: [/* @__PURE__ */ jsx("span", {}), data.map((column, columnIndex) => /* @__PURE__ */ jsx("span", {
|
|
6808
|
-
className: heatmap_chart_module_default["heatmap-chart__col-label"],
|
|
7114
|
+
className: clsx(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
7115
|
+
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
7116
|
+
...summaryGaps(columnIndex)
|
|
7117
|
+
}),
|
|
6809
7118
|
children: column.label
|
|
6810
7119
|
}, `col-${columnIndex}`))]
|
|
6811
7120
|
}), Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
@@ -6830,7 +7139,8 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6830
7139
|
}, `cell-${columnIndex}-${rowIndex}`);
|
|
6831
7140
|
const value = cell?.value ?? null;
|
|
6832
7141
|
const present = isPresent(value);
|
|
6833
|
-
const
|
|
7142
|
+
const filled = present && !column.summary;
|
|
7143
|
+
const normalized = filled ? getNormalizedValue(value, extent) : 0;
|
|
6834
7144
|
const flatIndex = columnIndex * rows + rowIndex;
|
|
6835
7145
|
const info = buildTooltipData(columnIndex, rowIndex);
|
|
6836
7146
|
const accessibleLabel = `${info.cellLabel || `${info.columnLabel ?? ""} ${info.rowLabel ?? ""}`.trim()}: ${info.value === null ? __("No data", "jetpack-charts") : formatNumber(info.value)}`;
|
|
@@ -6843,14 +7153,16 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6843
7153
|
"data-column": columnIndex,
|
|
6844
7154
|
"data-row": rowIndex,
|
|
6845
7155
|
className: clsx(heatmap_chart_module_default["heatmap-chart__cell"], {
|
|
6846
|
-
[heatmap_chart_module_default["heatmap-chart__cell--filled"]]:
|
|
6847
|
-
[heatmap_chart_module_default["heatmap-chart__cell--strong"]]:
|
|
7156
|
+
[heatmap_chart_module_default["heatmap-chart__cell--filled"]]: filled,
|
|
7157
|
+
[heatmap_chart_module_default["heatmap-chart__cell--strong"]]: filled && cellHasLightText(normalized),
|
|
7158
|
+
[heatmap_chart_module_default["heatmap-chart__cell--summary"]]: column.summary,
|
|
7159
|
+
...summaryGaps(columnIndex),
|
|
6848
7160
|
[heatmap_chart_module_default["heatmap-chart__cell--selected"]]: selectedIndex === flatIndex
|
|
6849
7161
|
}),
|
|
6850
|
-
style:
|
|
7162
|
+
style: filled ? { "--a8c-charts-heatmap-cell-intensity": normalized } : void 0,
|
|
6851
7163
|
onMouseMove: handleCellMouseMove,
|
|
6852
7164
|
onMouseLeave: handleCellMouseLeave,
|
|
6853
|
-
children: drawValues && present && /* @__PURE__ */ jsx("span", {
|
|
7165
|
+
children: (drawValues || column.summary) && present && /* @__PURE__ */ jsx("span", {
|
|
6854
7166
|
className: heatmap_chart_module_default["heatmap-chart__cell-value"],
|
|
6855
7167
|
children: formatNumberCompact(value)
|
|
6856
7168
|
})
|
|
@@ -6886,6 +7198,42 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ jsx(HeatmapChartW
|
|
|
6886
7198
|
HeatmapChartResponsiveInner.displayName = "HeatmapChart";
|
|
6887
7199
|
const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
|
|
6888
7200
|
//#endregion
|
|
7201
|
+
//#region src/charts/heatmap-chart/use-calendar-heatmap-data.ts
|
|
7202
|
+
/**
|
|
7203
|
+
* `buildCalendarHeatmapData` with the locale and zone taken from
|
|
7204
|
+
* `GlobalChartsProvider` where the caller names neither.
|
|
7205
|
+
*
|
|
7206
|
+
* @param series - Points to bucket. Held by reference, so a caller that rebuilds it each render defeats the memo.
|
|
7207
|
+
* @param options - As for `buildCalendarHeatmapData`; `locale` and `timeZone` win over the provider.
|
|
7208
|
+
* @return Columns and row labels for `HeatmapChart`.
|
|
7209
|
+
*/
|
|
7210
|
+
const useCalendarHeatmapData = (series, options = {}) => {
|
|
7211
|
+
const formatting = useChartFormatting();
|
|
7212
|
+
const locale = options.locale ?? formatting.locale;
|
|
7213
|
+
const timeZone = options.timeZone ?? formatting.timeZone;
|
|
7214
|
+
const { weekStartsOn, hideOutOfRangeDays } = options;
|
|
7215
|
+
const gridStart = options.gridSpan?.start;
|
|
7216
|
+
const gridEnd = options.gridSpan?.end;
|
|
7217
|
+
return useMemo(() => buildCalendarHeatmapData(series, {
|
|
7218
|
+
locale,
|
|
7219
|
+
timeZone,
|
|
7220
|
+
weekStartsOn,
|
|
7221
|
+
hideOutOfRangeDays,
|
|
7222
|
+
gridSpan: {
|
|
7223
|
+
start: gridStart,
|
|
7224
|
+
end: gridEnd
|
|
7225
|
+
}
|
|
7226
|
+
}), [
|
|
7227
|
+
series,
|
|
7228
|
+
locale,
|
|
7229
|
+
timeZone,
|
|
7230
|
+
weekStartsOn,
|
|
7231
|
+
hideOutOfRangeDays,
|
|
7232
|
+
gridStart,
|
|
7233
|
+
gridEnd
|
|
7234
|
+
]);
|
|
7235
|
+
};
|
|
7236
|
+
//#endregion
|
|
6889
7237
|
//#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
|
|
6890
7238
|
/*!
|
|
6891
7239
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
@@ -6953,7 +7301,7 @@ function paramCase(input, options) {
|
|
|
6953
7301
|
return dotCase(input, __assign({ delimiter: "-" }, options));
|
|
6954
7302
|
}
|
|
6955
7303
|
//#endregion
|
|
6956
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
7304
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/hooks/use-update-effect.mjs
|
|
6957
7305
|
function useUpdateEffect(effect, deps) {
|
|
6958
7306
|
const mountedRef = useRef$1(false);
|
|
6959
7307
|
useEffect$1(() => {
|
|
@@ -8523,7 +8871,7 @@ _createEmotion.css;
|
|
|
8523
8871
|
_createEmotion.sheet;
|
|
8524
8872
|
_createEmotion.cache;
|
|
8525
8873
|
//#endregion
|
|
8526
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
8874
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/hooks/use-cx.mjs
|
|
8527
8875
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
8528
8876
|
var useCx = () => {
|
|
8529
8877
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -8630,7 +8978,7 @@ function memize(fn, options) {
|
|
|
8630
8978
|
return memoized;
|
|
8631
8979
|
}
|
|
8632
8980
|
//#endregion
|
|
8633
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
8981
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/colors-values.mjs
|
|
8634
8982
|
var white = "#fff";
|
|
8635
8983
|
var GRAY = {
|
|
8636
8984
|
900: "#1e1e1e",
|
|
@@ -8709,7 +9057,7 @@ var COLORS = Object.freeze({
|
|
|
8709
9057
|
ui: UI
|
|
8710
9058
|
});
|
|
8711
9059
|
//#endregion
|
|
8712
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9060
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/config-values.mjs
|
|
8713
9061
|
var CONTROL_HEIGHT = "36px";
|
|
8714
9062
|
var CONTROL_PROPS = {
|
|
8715
9063
|
controlPaddingX: 12,
|
|
@@ -8827,7 +9175,7 @@ function warning(message) {
|
|
|
8827
9175
|
logged.add(message);
|
|
8828
9176
|
}
|
|
8829
9177
|
//#endregion
|
|
8830
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9178
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
8831
9179
|
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
8832
9180
|
var ComponentsContext = createContext$1(
|
|
8833
9181
|
/** @type {Record<string, any>} */
|
|
@@ -8854,18 +9202,18 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
8854
9202
|
};
|
|
8855
9203
|
memo(BaseContextSystemProvider);
|
|
8856
9204
|
//#endregion
|
|
8857
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9205
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/constants.mjs
|
|
8858
9206
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
8859
9207
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
8860
9208
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
8861
9209
|
//#endregion
|
|
8862
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9210
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/get-styled-class-name-from-key.mjs
|
|
8863
9211
|
function getStyledClassName(namespace) {
|
|
8864
9212
|
return `components-${paramCase(namespace)}`;
|
|
8865
9213
|
}
|
|
8866
9214
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
8867
9215
|
//#endregion
|
|
8868
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9216
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/context-connect.mjs
|
|
8869
9217
|
function contextConnect(Component, namespace) {
|
|
8870
9218
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
8871
9219
|
}
|
|
@@ -8882,7 +9230,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
8882
9230
|
});
|
|
8883
9231
|
}
|
|
8884
9232
|
//#endregion
|
|
8885
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9233
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/utils.mjs
|
|
8886
9234
|
function getNamespace(componentName) {
|
|
8887
9235
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
8888
9236
|
}
|
|
@@ -8890,7 +9238,7 @@ function getConnectedNamespace() {
|
|
|
8890
9238
|
return { [CONNECTED_NAMESPACE]: true };
|
|
8891
9239
|
}
|
|
8892
9240
|
//#endregion
|
|
8893
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9241
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/use-context-system.mjs
|
|
8894
9242
|
function useContextSystem(props, namespace) {
|
|
8895
9243
|
const contextSystemProps = useComponentsContext();
|
|
8896
9244
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -8910,7 +9258,7 @@ function useContextSystem(props, namespace) {
|
|
|
8910
9258
|
return finalComponentProps;
|
|
8911
9259
|
}
|
|
8912
9260
|
//#endregion
|
|
8913
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9261
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/visually-hidden/styles.mjs
|
|
8914
9262
|
var visuallyHidden = {
|
|
8915
9263
|
border: 0,
|
|
8916
9264
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -8926,7 +9274,7 @@ var visuallyHidden = {
|
|
|
8926
9274
|
wordBreak: "normal"
|
|
8927
9275
|
};
|
|
8928
9276
|
//#endregion
|
|
8929
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9277
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/polymorphic-element.mjs
|
|
8930
9278
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
8931
9279
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
8932
9280
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -9016,7 +9364,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
|
9016
9364
|
}
|
|
9017
9365
|
var PolymorphicElement = forwardRef$1(UnforwardedPolymorphicElement);
|
|
9018
9366
|
//#endregion
|
|
9019
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9367
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/view/component.mjs
|
|
9020
9368
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
9021
9369
|
return /* @__PURE__ */ jsx(PolymorphicElement, {
|
|
9022
9370
|
ref,
|
|
@@ -9025,7 +9373,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
9025
9373
|
}
|
|
9026
9374
|
var component_default$2 = Object.assign(forwardRef$1(UnforwardedView), { selector: ".components-view" });
|
|
9027
9375
|
//#endregion
|
|
9028
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9376
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/visually-hidden/component.mjs
|
|
9029
9377
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
9030
9378
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
9031
9379
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -9040,7 +9388,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
9040
9388
|
}
|
|
9041
9389
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
9042
9390
|
//#endregion
|
|
9043
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9391
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/utils/use-responsive-value.mjs
|
|
9044
9392
|
var breakpoints = [
|
|
9045
9393
|
"40em",
|
|
9046
9394
|
"52em",
|
|
@@ -9074,7 +9422,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
9074
9422
|
return array[index >= array.length ? array.length - 1 : index];
|
|
9075
9423
|
}
|
|
9076
9424
|
//#endregion
|
|
9077
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9425
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/grid/utils.mjs
|
|
9078
9426
|
var ALIGNMENTS = {
|
|
9079
9427
|
bottom: {
|
|
9080
9428
|
alignItems: "flex-end",
|
|
@@ -9122,7 +9470,7 @@ function getAlignmentProps(alignment) {
|
|
|
9122
9470
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
9123
9471
|
}
|
|
9124
9472
|
//#endregion
|
|
9125
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9473
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/grid/hook.mjs
|
|
9126
9474
|
function useGrid(props) {
|
|
9127
9475
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
9128
9476
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -9164,7 +9512,7 @@ function useGrid(props) {
|
|
|
9164
9512
|
};
|
|
9165
9513
|
}
|
|
9166
9514
|
//#endregion
|
|
9167
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9515
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/grid/component.mjs
|
|
9168
9516
|
function UnconnectedGrid(props, forwardedRef) {
|
|
9169
9517
|
const gridProps = useGrid(props);
|
|
9170
9518
|
return /* @__PURE__ */ jsx(component_default$2, {
|
|
@@ -10420,6 +10768,6 @@ function TrendIndicator({ direction, value, className, style, showIcon = true })
|
|
|
10420
10768
|
});
|
|
10421
10769
|
}
|
|
10422
10770
|
//#endregion
|
|
10423
|
-
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
|
|
10771
|
+
export { AccessibleTooltip, AreaChartResponsive as AreaChart, AreaChart as AreaChartUnresponsive, BarChartResponsive as BarChart, BarChart as BarChartUnresponsive, BarListChartResponsive as BarListChart, BarListChart as BarListChartUnresponsive, BaseTooltip, ConversionFunnelChartWithProvider as ConversionFunnelChart, GeoChartResponsive as GeoChart, GeoChartWithProvider as GeoChartUnresponsive, GlobalChartsContext, GlobalChartsProvider, GlobalChartsProvider as ThemeProvider, GoogleDataTableColumnRoleType, HeatmapChartResponsive as HeatmapChart, HeatmapChart as HeatmapChartUnresponsive, LeaderboardChartResponsive as LeaderboardChart, LeaderboardChart as LeaderboardChartUnresponsive, Legend, LineChartResponsive as LineChart, LineChart as LineChartUnresponsive, PieChartResponsive as PieChart, PieChart as PieChartUnresponsive, PieSemiCircleChartResponsive as PieSemiCircleChart, PieSemiCircleChart as PieSemiCircleChartUnresponsive, Sparkline, SparklineUnresponsive, TrendIndicator, buildCalendarHeatmapData, defaultTheme, formatMetricValue, formatPercentage, getBucketInfo, getColorDistance, hexToRgba, isValidHexColor, lightenHexColor, mergeThemes, mixHexColors, normalizeColorToHex, parseAsLocalDate, parseHslString, prefersLightText, relativeLuminance, resolveCssVariable, useCalendarHeatmapData, useChartFormatting, useChartLegendItems, useChartRegistration, useChartScopeElement, useGlobalChartsContext, useGlobalChartsTheme, useLeaderboardLegendItems, validateHexColor };
|
|
10424
10772
|
|
|
10425
10773
|
//# sourceMappingURL=index.js.map
|