@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.cjs
CHANGED
|
@@ -31,6 +31,7 @@ let react = require("react");
|
|
|
31
31
|
react = __toESM(react);
|
|
32
32
|
let _visx_vendor_d3_color = require("@visx/vendor/d3-color");
|
|
33
33
|
let date_fns = require("date-fns");
|
|
34
|
+
let _date_fns_tz = require("@date-fns/tz");
|
|
34
35
|
let _visx_text = require("@visx/text");
|
|
35
36
|
let deepmerge = require("deepmerge");
|
|
36
37
|
deepmerge = __toESM(deepmerge, 1);
|
|
@@ -86,46 +87,35 @@ function attachSubComponents(Chart, subComponents) {
|
|
|
86
87
|
return Object.assign(Chart, subComponents);
|
|
87
88
|
}
|
|
88
89
|
//#endregion
|
|
89
|
-
//#region src/utils/
|
|
90
|
+
//#region src/utils/warn-once.ts
|
|
91
|
+
const warned = /* @__PURE__ */ new Set();
|
|
90
92
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* This module provides utilities for parsing various date string formats and converting
|
|
94
|
-
* them to local timezone dates using the battle-tested date-fns library. For formats
|
|
95
|
-
* without timezone info, they're treated as local. For formats with timezone info,
|
|
96
|
-
* they're converted to the equivalent local time.
|
|
93
|
+
* Warns about a host-supplied value once per process, and never in production.
|
|
97
94
|
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
95
|
+
* @param key - Identifies the value, so a bad prop on every point warns once.
|
|
96
|
+
* @param message - What the host got wrong and what happens instead.
|
|
97
|
+
*/
|
|
98
|
+
const warnOnce = (key, message) => {
|
|
99
|
+
if (warned.has(key) || process.env.NODE_ENV === "production") return;
|
|
100
|
+
warned.add(key);
|
|
101
|
+
console.warn(`[Charts] ${message}`);
|
|
102
|
+
};
|
|
103
|
+
//#endregion
|
|
104
|
+
//#region src/utils/date-parsing.ts
|
|
105
|
+
/**
|
|
106
|
+
* @file Date parsing: a naive string is dated in a supplied IANA zone, or the runtime's own
|
|
106
107
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* - YYYY-MM-DD HH:mm (treated as local)
|
|
111
|
-
* - YYYY-MM-DDTHH:mm:ss (treated as local)
|
|
112
|
-
* - YYYY-MM-DDTHH:mm:ss.SSS (treated as local)
|
|
113
|
-
* - YYYY-MM-DDTHH:mm (treated as local)
|
|
114
|
-
* - YYYY-MM-DDTHH:mm:ssZ (converted to local)
|
|
115
|
-
* - YYYY-MM-DDTHH:mm:ss±HH:mm (converted to local)
|
|
108
|
+
* A string carrying an offset is already an instant and parses the same everywhere. A string
|
|
109
|
+
* without one is only a wall-clock reading, so it means nothing until a zone is named. See
|
|
110
|
+
* `parseAsLocalDate` for the supported formats.
|
|
116
111
|
*
|
|
117
|
-
*
|
|
118
|
-
* ```typescript
|
|
119
|
-
* parseAsLocalDate("2025-01-01"); // Local timezone
|
|
120
|
-
* parseAsLocalDate("2025-01-01 14:30:00"); // Local timezone
|
|
121
|
-
* parseAsLocalDate("2025-01-01 14:30"); // Local timezone
|
|
122
|
-
* parseAsLocalDate("2025-01-01T14:30:45.123"); // Local timezone
|
|
123
|
-
* parseAsLocalDate("2025-01-01T14:30:00Z"); // UTC 14:30 → Local equivalent
|
|
124
|
-
* parseAsLocalDate("2025-01-01T14:30:00+05:00"); // +05:00 14:30 → Local equivalent
|
|
125
|
-
* ```
|
|
112
|
+
* Note: this specifically avoids date-fns's default of parsing `YYYY-MM-DD` as a UTC date.
|
|
126
113
|
*/
|
|
127
114
|
/**
|
|
128
115
|
* Checks if a date string contains timezone information
|
|
116
|
+
*
|
|
117
|
+
* The minutes are optional because ISO 8601 allows a bare `±hh`, which `parseISO` reads.
|
|
118
|
+
*
|
|
129
119
|
* @param {string} dateString - The date string to check for timezone information
|
|
130
120
|
* @return {boolean} True if the date string contains timezone information, false otherwise
|
|
131
121
|
*/
|
|
@@ -133,28 +123,57 @@ const hasTimezone = (dateString) => {
|
|
|
133
123
|
const tIndex = dateString.indexOf("T");
|
|
134
124
|
if (tIndex === -1) return false;
|
|
135
125
|
if (dateString.endsWith("Z")) return true;
|
|
136
|
-
return /[+-]\d{2}
|
|
126
|
+
return /[+-]\d{2}(?::?\d{2})?$/.test(dateString.slice(tIndex + 1));
|
|
127
|
+
};
|
|
128
|
+
const NAIVE = /^(\d{1,4})-(\d{1,2})-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d{1,3}))?)?)?$/;
|
|
129
|
+
const asUtcMs = ([, ...fields]) => {
|
|
130
|
+
const [year, month, day, hour, minute, second, ms] = fields.map((field) => Number(field ?? 0));
|
|
131
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
132
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
133
|
+
date.setUTCHours(hour, minute, second, ms);
|
|
134
|
+
return date.getTime();
|
|
137
135
|
};
|
|
138
136
|
/**
|
|
139
|
-
*
|
|
137
|
+
* The instant a wall-clock reading names in a given zone.
|
|
140
138
|
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
143
|
-
* local timezone equivalent.
|
|
139
|
+
* A reading a spring-forward gap deleted moves forward past the gap, and one a fall-back
|
|
140
|
+
* repeated resolves to a single instant. Neither is configurable: see CHARTS-268.
|
|
144
141
|
*
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* - YYYY-MM-DD HH:mm (local)
|
|
149
|
-
* - YYYY-MM-DDTHH:mm:ss (local)
|
|
150
|
-
* - YYYY-MM-DDTHH:mm:ss.SSS (local)
|
|
151
|
-
* - YYYY-MM-DDTHH:mm (local)
|
|
152
|
-
* - YYYY-MM-DDTHH:mm:ssZ (UTC → local)
|
|
153
|
-
* - YYYY-MM-DDTHH:mm:ss±HH:mm (offset → local)
|
|
154
|
-
* @param {string} dateString - The date string to parse into a local timezone date
|
|
155
|
-
* @return {Date} A Date object representing the parsed date in local timezone, or an invalid Date if parsing fails
|
|
142
|
+
* @param wallClock - The reading, as the milliseconds it would be if it were UTC.
|
|
143
|
+
* @param timeZone - IANA zone the reading is dated in.
|
|
144
|
+
* @return The instant, or `null` where `timeZone` is not a zone Intl accepts.
|
|
156
145
|
*/
|
|
157
|
-
const
|
|
146
|
+
const wallClockToInstant = (wallClock, timeZone) => {
|
|
147
|
+
const first = (0, _date_fns_tz.tzOffset)(timeZone, new Date(wallClock));
|
|
148
|
+
if (Number.isNaN(first)) {
|
|
149
|
+
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".`);
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
const guess = wallClock - first * 6e4;
|
|
153
|
+
const second = (0, _date_fns_tz.tzOffset)(timeZone, new Date(guess));
|
|
154
|
+
if (first === second) return new Date(guess);
|
|
155
|
+
const corrected = wallClock - second * 6e4;
|
|
156
|
+
const third = (0, _date_fns_tz.tzOffset)(timeZone, new Date(corrected));
|
|
157
|
+
if (second === third) return new Date(corrected);
|
|
158
|
+
return /* @__PURE__ */ new Date(wallClock - Math.min(second, third) * 6e4);
|
|
159
|
+
};
|
|
160
|
+
/**
|
|
161
|
+
* Parses any supported date string format into an instant, dated in `timeZone` or the runtime's own
|
|
162
|
+
*
|
|
163
|
+
* Uses date-fns for robust parsing and validation. A string carrying timezone info
|
|
164
|
+
* is already an instant and is returned as one, whatever `timeZone` says. A string
|
|
165
|
+
* without it is a wall-clock reading, dated in `timeZone` when one is supplied and
|
|
166
|
+
* in the runtime's own zone when none is.
|
|
167
|
+
*
|
|
168
|
+
* A wall clock a DST gap deleted is moved forward past the gap; one a fall-back repeated
|
|
169
|
+
* resolves to a single instant. Neither policy is selectable. A zone `Intl` rejects falls
|
|
170
|
+
* back to the runtime's own, and warns once outside production.
|
|
171
|
+
*
|
|
172
|
+
* @param {string} dateString - The date string to parse into a date
|
|
173
|
+
* @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
|
|
174
|
+
* @return {Date} A Date object representing the parsed instant, or an invalid Date if parsing fails
|
|
175
|
+
*/
|
|
176
|
+
const parseAsLocalDate = (dateString, timeZone) => {
|
|
158
177
|
const trimmedString = dateString.trim();
|
|
159
178
|
if (hasTimezone(trimmedString)) {
|
|
160
179
|
const isoDate = (0, date_fns.parseISO)(trimmedString);
|
|
@@ -170,7 +189,10 @@ const parseAsLocalDate = (dateString) => {
|
|
|
170
189
|
"yyyy-MM-dd'T'HH:mm"
|
|
171
190
|
]) {
|
|
172
191
|
const result = (0, date_fns.parse)(trimmedString, format, /* @__PURE__ */ new Date());
|
|
173
|
-
if ((0, date_fns.isValid)(result))
|
|
192
|
+
if (!(0, date_fns.isValid)(result)) continue;
|
|
193
|
+
if (!timeZone) return result;
|
|
194
|
+
const fields = NAIVE.exec(trimmedString);
|
|
195
|
+
return (fields && wallClockToInstant(asUtcMs(fields), timeZone)) ?? result;
|
|
174
196
|
}
|
|
175
197
|
return /* @__PURE__ */ new Date(NaN);
|
|
176
198
|
};
|
|
@@ -275,6 +297,31 @@ const formatPercentage = (value) => {
|
|
|
275
297
|
} });
|
|
276
298
|
};
|
|
277
299
|
//#endregion
|
|
300
|
+
//#region src/utils/get-edge-tick-widths.ts
|
|
301
|
+
/**
|
|
302
|
+
* Rendered widths of the first and last tick labels on an axis.
|
|
303
|
+
*
|
|
304
|
+
* An unmeasurable label reserves nothing, which is what a width of 0 already
|
|
305
|
+
* means to every caller, so it is reported as 0 rather than as its own case.
|
|
306
|
+
*
|
|
307
|
+
* @param ticks - Tick values, in axis order.
|
|
308
|
+
* @param formatTick - Function to format a tick.
|
|
309
|
+
* @param {object} labelStyle - Style object for the label.
|
|
310
|
+
* @return {object} - Widths in pixels.
|
|
311
|
+
*/
|
|
312
|
+
const getEdgeTickWidths = (ticks, formatTick, labelStyle) => {
|
|
313
|
+
if (!ticks.length) return {
|
|
314
|
+
first: 0,
|
|
315
|
+
last: 0
|
|
316
|
+
};
|
|
317
|
+
const lastIndex = ticks.length - 1;
|
|
318
|
+
const label = (tick, index) => String(formatTick ? formatTick(tick, index, []) ?? "" : tick);
|
|
319
|
+
return {
|
|
320
|
+
first: (0, _visx_text.getStringWidth)(label(ticks[0], 0), labelStyle) ?? 0,
|
|
321
|
+
last: (0, _visx_text.getStringWidth)(label(ticks[lastIndex], lastIndex), labelStyle) ?? 0
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
//#endregion
|
|
278
325
|
//#region src/utils/get-longest-tick-width.ts
|
|
279
326
|
/**
|
|
280
327
|
* Returns the width of the longest tick.
|
|
@@ -661,12 +708,6 @@ const getFormatter$1 = (options, { locale, timeZone }) => {
|
|
|
661
708
|
}
|
|
662
709
|
return formatter;
|
|
663
710
|
};
|
|
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
711
|
const isUsable = (formatting) => {
|
|
671
712
|
try {
|
|
672
713
|
Intl.DateTimeFormat(formatting.locale, { timeZone: formatting.timeZone });
|
|
@@ -1292,13 +1333,28 @@ const useXYChartTheme = (data) => {
|
|
|
1292
1333
|
]);
|
|
1293
1334
|
};
|
|
1294
1335
|
//#endregion
|
|
1336
|
+
//#region src/providers/chart-context/hooks/use-chart-formatting.ts
|
|
1337
|
+
const RUNTIME_FORMATTING = {};
|
|
1338
|
+
/**
|
|
1339
|
+
* The locale and time zone dates are rendered in, as set on `GlobalChartsProvider`.
|
|
1340
|
+
*
|
|
1341
|
+
* Falls back to the runtime's own rather than throwing: charts render outside a
|
|
1342
|
+
* provider, and a host that sets neither gets exactly the browser-default
|
|
1343
|
+
* behavior this package had before the context existed.
|
|
1344
|
+
*
|
|
1345
|
+
* @return The host's formatting context.
|
|
1346
|
+
*/
|
|
1347
|
+
const useChartFormatting = () => {
|
|
1348
|
+
return (0, react.useContext)(GlobalChartsContext)?.formatting ?? RUNTIME_FORMATTING;
|
|
1349
|
+
};
|
|
1350
|
+
//#endregion
|
|
1295
1351
|
//#region src/hooks/use-chart-data-transform.ts
|
|
1296
1352
|
/**
|
|
1297
1353
|
* Hook that transforms and sorts chart data, handling date parsing and sorting
|
|
1298
1354
|
*
|
|
1299
1355
|
* This hook extracts the common data transformation logic used in both line-chart
|
|
1300
1356
|
* and bar-chart components. It:
|
|
1301
|
-
* 1. Parses date strings into Date objects
|
|
1357
|
+
* 1. Parses date strings into Date objects, dated in the provider's time zone
|
|
1302
1358
|
* 2. Sorts data points by date when date properties are present
|
|
1303
1359
|
* 3. Returns the original data unchanged when no date properties are found
|
|
1304
1360
|
*
|
|
@@ -1306,6 +1362,7 @@ const useXYChartTheme = (data) => {
|
|
|
1306
1362
|
* @return {SeriesData[]} The transformed and sorted data
|
|
1307
1363
|
*/
|
|
1308
1364
|
const useChartDataTransform = (data) => {
|
|
1365
|
+
const { timeZone } = useChartFormatting();
|
|
1309
1366
|
return (0, react.useMemo)(() => {
|
|
1310
1367
|
const firstPoint = data?.[0]?.data?.[0];
|
|
1311
1368
|
if (!(firstPoint && ("date" in firstPoint || "dateString" in firstPoint))) return data;
|
|
@@ -1314,7 +1371,7 @@ const useChartDataTransform = (data) => {
|
|
|
1314
1371
|
data: series.data.map((point) => {
|
|
1315
1372
|
let date;
|
|
1316
1373
|
if ("date" in point && point.date) date = point.date;
|
|
1317
|
-
else if ("dateString" in point && point.dateString) date = parseAsLocalDate(point.dateString);
|
|
1374
|
+
else if ("dateString" in point && point.dateString) date = parseAsLocalDate(point.dateString, timeZone);
|
|
1318
1375
|
return {
|
|
1319
1376
|
...point,
|
|
1320
1377
|
date
|
|
@@ -1324,7 +1381,7 @@ const useChartDataTransform = (data) => {
|
|
|
1324
1381
|
return a.date.getTime() - b.date.getTime();
|
|
1325
1382
|
})
|
|
1326
1383
|
}));
|
|
1327
|
-
}, [data]);
|
|
1384
|
+
}, [data, timeZone]);
|
|
1328
1385
|
};
|
|
1329
1386
|
//#endregion
|
|
1330
1387
|
//#region src/hooks/use-chart-margin.tsx
|
|
@@ -1366,11 +1423,32 @@ const DEFAULT_TICK_LENGTH = 8;
|
|
|
1366
1423
|
* measure them via getLongestTickWidth.
|
|
1367
1424
|
*/
|
|
1368
1425
|
const DEFAULT_Y_TICK_WIDTH = 40;
|
|
1426
|
+
/**
|
|
1427
|
+
* Copy a label style with its lengths spelled out in px.
|
|
1428
|
+
*
|
|
1429
|
+
* `getStringWidth` applies the style through CSSOM. Blink resolves a bare number
|
|
1430
|
+
* on an SVG `<text>`, but that is its own leniency rather than the CSS rule, and
|
|
1431
|
+
* `buildChartTheme` hands us bare numbers.
|
|
1432
|
+
*
|
|
1433
|
+
* @param style - Raw label style from the theme.
|
|
1434
|
+
* @return The same style with px-qualified lengths.
|
|
1435
|
+
*/
|
|
1436
|
+
const toMeasurableStyle = (style) => {
|
|
1437
|
+
if (!style) return style;
|
|
1438
|
+
const fontSize = resolveFontSize(style.fontSize);
|
|
1439
|
+
const { letterSpacing } = style;
|
|
1440
|
+
return {
|
|
1441
|
+
...style,
|
|
1442
|
+
...fontSize === void 0 ? {} : { fontSize: `${fontSize}px` },
|
|
1443
|
+
...typeof letterSpacing === "number" ? { letterSpacing: `${letterSpacing}px` } : {}
|
|
1444
|
+
};
|
|
1445
|
+
};
|
|
1369
1446
|
const getXAxisLabelMetrics = (theme, orientation) => {
|
|
1370
1447
|
const xAxisStyles = orientation === "top" ? theme.axisStyles?.x?.top : theme.axisStyles?.x?.bottom;
|
|
1371
1448
|
return {
|
|
1372
1449
|
fontSize: resolveFontSize(xAxisStyles?.axisLabel?.fontSize) || resolveFontSize(theme.svgLabelSmall?.fontSize) || DEFAULT_FONT_SIZE,
|
|
1373
|
-
tickLength: xAxisStyles?.tickLength ?? DEFAULT_TICK_LENGTH
|
|
1450
|
+
tickLength: xAxisStyles?.tickLength ?? DEFAULT_TICK_LENGTH,
|
|
1451
|
+
tickLabelStyle: toMeasurableStyle(xAxisStyles?.tickLabel)
|
|
1374
1452
|
};
|
|
1375
1453
|
};
|
|
1376
1454
|
const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
@@ -1382,7 +1460,7 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1382
1460
|
const maxY = Math.max(...allDataPoints.map((d) => d.value));
|
|
1383
1461
|
const yScale = (0, _visx_scale.createScale)({
|
|
1384
1462
|
...options.yScale,
|
|
1385
|
-
domain: [minY, maxY],
|
|
1463
|
+
domain: options.yScale?.domain ?? [minY, maxY],
|
|
1386
1464
|
range: [height, 0]
|
|
1387
1465
|
});
|
|
1388
1466
|
return (0, _visx_scale.getTicks)(yScale, options.axis?.y?.numTicks);
|
|
@@ -1401,18 +1479,25 @@ const useChartMargin = (height, options, data, theme, horizontal = false) => {
|
|
|
1401
1479
|
};
|
|
1402
1480
|
const yAxisOrientation = options.axis?.y?.orientation;
|
|
1403
1481
|
const yAxisStyles = yAxisOrientation === "right" ? theme.axisStyles.y.right : theme.axisStyles.y.left;
|
|
1404
|
-
const yTickWidth = getLongestTickWidth(yTicks, options.axis?.y?.tickFormat, yAxisStyles.axisLabel);
|
|
1482
|
+
const yTickWidth = getLongestTickWidth(yTicks, options.axis?.y?.tickFormat, toMeasurableStyle(yAxisStyles.axisLabel));
|
|
1405
1483
|
const yTickLabelFontSize = resolveFontSize(yAxisStyles?.tickLabel?.fontSize) || DEFAULT_FONT_SIZE;
|
|
1406
1484
|
const yMarginValue = (yTickWidth ?? DEFAULT_Y_TICK_WIDTH) + (yAxisStyles?.tickLength ?? 0) + Math.ceil(yTickLabelFontSize * .25);
|
|
1407
|
-
if (
|
|
1408
|
-
|
|
1485
|
+
if (options.axis?.y?.display !== false) {
|
|
1486
|
+
if (yAxisOrientation === "right") defaultMargin.right = yMarginValue;
|
|
1487
|
+
else defaultMargin.left = yMarginValue;
|
|
1488
|
+
}
|
|
1409
1489
|
const xOrientation = options.axis?.x?.orientation === "top" ? "top" : "bottom";
|
|
1410
|
-
const { fontSize, tickLength } = getXAxisLabelMetrics(theme, xOrientation);
|
|
1490
|
+
const { fontSize, tickLength, tickLabelStyle } = getXAxisLabelMetrics(theme, xOrientation);
|
|
1411
1491
|
const computedXMargin = fontSize + tickLength;
|
|
1412
1492
|
if (xOrientation === "top") {
|
|
1413
1493
|
defaultMargin.top = Math.max(defaultMargin.top, computedXMargin);
|
|
1414
1494
|
defaultMargin.bottom = DEFAULT_BOTTOM_FOR_TOP_AXIS;
|
|
1415
1495
|
} else defaultMargin.bottom = Math.max(defaultMargin.bottom, computedXMargin);
|
|
1496
|
+
if (options.axis?.x?.display !== false) {
|
|
1497
|
+
const { first, last } = getEdgeTickWidths(options.axis?.x?.tickValues ?? [], options.axis?.x?.tickFormat, tickLabelStyle);
|
|
1498
|
+
defaultMargin.left = Math.max(defaultMargin.left, Math.ceil(first / 2));
|
|
1499
|
+
defaultMargin.right = Math.max(defaultMargin.right, Math.ceil(last / 2));
|
|
1500
|
+
}
|
|
1416
1501
|
return defaultMargin;
|
|
1417
1502
|
}, [
|
|
1418
1503
|
options,
|
|
@@ -1688,21 +1773,6 @@ const useGlobalChartsTheme = () => {
|
|
|
1688
1773
|
return (0, react.useContext)(GlobalChartsContext)?.theme ?? defaultTheme;
|
|
1689
1774
|
};
|
|
1690
1775
|
//#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
|
|
1706
1776
|
//#region src/components/legend/utils/value-or-identity.ts
|
|
1707
1777
|
/**
|
|
1708
1778
|
* Returns an object's value if defined, or the object.
|
|
@@ -2142,6 +2212,8 @@ const BaseTooltip = ({ data, top, left, component: Component = DefaultTooltipCon
|
|
|
2142
2212
|
//#endregion
|
|
2143
2213
|
//#region src/components/tooltip/private/bounded-tooltip.tsx
|
|
2144
2214
|
const DEFAULT_OFFSET = 10;
|
|
2215
|
+
const POINTER_HEIGHT = 6;
|
|
2216
|
+
const clamp = (position, min, max, size) => Math.min(Math.max(position, min), Math.max(min, max - size));
|
|
2145
2217
|
const isClipping = (element) => {
|
|
2146
2218
|
const { overflow, overflowX, overflowY } = getComputedStyle(element);
|
|
2147
2219
|
return [
|
|
@@ -2159,33 +2231,49 @@ const findClippingAncestor = (wrapper) => {
|
|
|
2159
2231
|
return null;
|
|
2160
2232
|
};
|
|
2161
2233
|
/**
|
|
2162
|
-
* Where the box goes, in wrapper coordinates.
|
|
2163
|
-
*
|
|
2164
|
-
*
|
|
2165
|
-
* `bounds` whenever it fits at all.
|
|
2234
|
+
* Where the box goes, in wrapper coordinates. Automatic placement flips to
|
|
2235
|
+
* the side that clips less, then clamps inside `bounds`; below-axis placement
|
|
2236
|
+
* is centered on the anchor and clamped horizontally.
|
|
2166
2237
|
*
|
|
2167
|
-
*
|
|
2238
|
+
* The flip measures against the visible part of the wrapper, its intersection
|
|
2239
|
+
* with `bounds`. Only the clamp is bound by the page: a box that fits inside the
|
|
2240
|
+
* chart on one side stays there, so it does not reach past the chart into
|
|
2241
|
+
* siblings that paint over it.
|
|
2242
|
+
*
|
|
2243
|
+
* @param params - Anchor, offsets, the box size and the rects to keep inside.
|
|
2168
2244
|
* @param params.left - Anchor x, in wrapper coordinates.
|
|
2169
2245
|
* @param params.top - Anchor y, in wrapper coordinates.
|
|
2170
2246
|
* @param params.offsetLeft - Gap between the anchor and the box, horizontally.
|
|
2171
2247
|
* @param params.offsetTop - Gap between the anchor and the box, vertically.
|
|
2172
2248
|
* @param params.box - Rendered size of the box.
|
|
2249
|
+
* @param params.wrapper - The wrapper's own edges, in wrapper coordinates.
|
|
2250
|
+
* @param params.placement - Fixed below-axis placement or automatic flipping.
|
|
2173
2251
|
* @param params.bounds - Edges the box must keep inside, in wrapper coordinates.
|
|
2174
|
-
* @return The box's top-left corner
|
|
2252
|
+
* @return The box's top-left corner; fixed placement preserves the axis's subpixel y.
|
|
2175
2253
|
*/
|
|
2176
|
-
const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) => {
|
|
2254
|
+
const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, wrapper, bounds, placement = "auto" }) => {
|
|
2255
|
+
if (placement === "below-axis") return {
|
|
2256
|
+
x: Math.round(clamp(left - box.width / 2, bounds.left, bounds.right, box.width)),
|
|
2257
|
+
y: top + POINTER_HEIGHT
|
|
2258
|
+
};
|
|
2259
|
+
const fit = {
|
|
2260
|
+
left: Math.max(wrapper.left, bounds.left),
|
|
2261
|
+
top: Math.max(wrapper.top, bounds.top),
|
|
2262
|
+
right: Math.min(wrapper.right, bounds.right),
|
|
2263
|
+
bottom: Math.min(wrapper.bottom, bounds.bottom)
|
|
2264
|
+
};
|
|
2177
2265
|
const rightX = left + offsetLeft;
|
|
2178
2266
|
const leftX = left - offsetLeft - box.width;
|
|
2179
|
-
const rightOverflow = rightX + box.width -
|
|
2180
|
-
const leftOverflow =
|
|
2267
|
+
const rightOverflow = rightX + box.width - fit.right;
|
|
2268
|
+
const leftOverflow = fit.left - leftX;
|
|
2181
2269
|
let x = rightOverflow > 0 && rightOverflow > leftOverflow ? leftX : rightX;
|
|
2182
2270
|
const downY = top + offsetTop;
|
|
2183
2271
|
const upY = top - offsetTop - box.height;
|
|
2184
|
-
const downOverflow = downY + box.height -
|
|
2185
|
-
const upOverflow =
|
|
2272
|
+
const downOverflow = downY + box.height - fit.bottom;
|
|
2273
|
+
const upOverflow = fit.top - upY;
|
|
2186
2274
|
let y = downOverflow > 0 && downOverflow > upOverflow ? upY : downY;
|
|
2187
|
-
x =
|
|
2188
|
-
y =
|
|
2275
|
+
x = clamp(x, bounds.left, bounds.right, box.width);
|
|
2276
|
+
y = clamp(y, bounds.top, bounds.bottom, box.height);
|
|
2189
2277
|
return {
|
|
2190
2278
|
x: Math.round(x),
|
|
2191
2279
|
y: Math.round(y)
|
|
@@ -2199,7 +2287,8 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) =
|
|
|
2199
2287
|
* alone would let the box spill into an `overflow: hidden` card and be cut off.
|
|
2200
2288
|
*
|
|
2201
2289
|
* Re-measures on every render, so a box whose content changes width between
|
|
2202
|
-
* two hovers is placed for its current size.
|
|
2290
|
+
* two hovers is placed for its current size. See `getBoundedPosition` for the
|
|
2291
|
+
* below-axis exception.
|
|
2203
2292
|
*
|
|
2204
2293
|
* @param props - visx `Tooltip` props.
|
|
2205
2294
|
* @param props.left - Anchor x, in wrapper coordinates.
|
|
@@ -2209,9 +2298,10 @@ const getBoundedPosition = ({ left, top, offsetLeft, offsetTop, box, bounds }) =
|
|
|
2209
2298
|
* @param props.style - Box styles; visx's defaults unless `unstyled`.
|
|
2210
2299
|
* @param props.unstyled - Skip `style` and leave the box bare.
|
|
2211
2300
|
* @param props.children - Box content.
|
|
2301
|
+
* @param props.placement - Fixed below-axis placement or automatic flipping.
|
|
2212
2302
|
* @return The tooltip box.
|
|
2213
2303
|
*/
|
|
2214
|
-
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = _visx_tooltip.defaultStyles, unstyled = false, children, ...rest }) => {
|
|
2304
|
+
const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offsetTop = DEFAULT_OFFSET, style = _visx_tooltip.defaultStyles, unstyled = false, children, placement = "auto", ...rest }) => {
|
|
2215
2305
|
const nodeRef = (0, react.useRef)(null);
|
|
2216
2306
|
const clipRef = (0, react.useRef)(null);
|
|
2217
2307
|
const [position, setPosition] = (0, react.useState)(null);
|
|
@@ -2236,10 +2326,17 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2236
2326
|
top,
|
|
2237
2327
|
offsetLeft,
|
|
2238
2328
|
offsetTop,
|
|
2329
|
+
placement,
|
|
2239
2330
|
box: {
|
|
2240
2331
|
width: own.width,
|
|
2241
2332
|
height: own.height
|
|
2242
2333
|
},
|
|
2334
|
+
wrapper: {
|
|
2335
|
+
left: 0,
|
|
2336
|
+
top: 0,
|
|
2337
|
+
right: wrapperRect.width,
|
|
2338
|
+
bottom: wrapperRect.height
|
|
2339
|
+
},
|
|
2243
2340
|
bounds: {
|
|
2244
2341
|
left: clipRect.left - wrapperRect.left,
|
|
2245
2342
|
top: clipRect.top - wrapperRect.top,
|
|
@@ -2253,11 +2350,12 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2253
2350
|
top,
|
|
2254
2351
|
offsetLeft,
|
|
2255
2352
|
offsetTop,
|
|
2256
|
-
children
|
|
2353
|
+
children,
|
|
2354
|
+
placement
|
|
2257
2355
|
]);
|
|
2258
2356
|
const x = position?.x ?? left + offsetLeft;
|
|
2259
|
-
const y = position?.y ?? top + offsetTop;
|
|
2260
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
2357
|
+
const y = position?.y ?? top + (placement === "below-axis" ? POINTER_HEIGHT : offsetTop);
|
|
2358
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_visx_tooltip.Tooltip, {
|
|
2261
2359
|
ref: nodeRef,
|
|
2262
2360
|
style: {
|
|
2263
2361
|
position: "absolute",
|
|
@@ -2267,12 +2365,40 @@ const BoundedTooltip = ({ left = 0, top = 0, offsetLeft = DEFAULT_OFFSET, offset
|
|
|
2267
2365
|
...!unstyled && style
|
|
2268
2366
|
},
|
|
2269
2367
|
...rest,
|
|
2270
|
-
children
|
|
2368
|
+
children: [placement === "below-axis" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2369
|
+
"aria-hidden": "true",
|
|
2370
|
+
style: {
|
|
2371
|
+
position: "absolute",
|
|
2372
|
+
left: left - x - POINTER_HEIGHT,
|
|
2373
|
+
top: -6,
|
|
2374
|
+
width: 12,
|
|
2375
|
+
height: POINTER_HEIGHT,
|
|
2376
|
+
background: "inherit",
|
|
2377
|
+
clipPath: "polygon(50% 0, 100% 100%, 0 100%)",
|
|
2378
|
+
pointerEvents: "none"
|
|
2379
|
+
}
|
|
2380
|
+
}), children]
|
|
2271
2381
|
});
|
|
2272
2382
|
};
|
|
2273
2383
|
//#endregion
|
|
2274
2384
|
//#region src/components/tooltip/xy-chart-tooltip.tsx
|
|
2275
2385
|
const CROSSHAIR_STROKE_WIDTH = 1.5;
|
|
2386
|
+
const CROSSHAIR_PAINT_PROPERTIES = /* @__PURE__ */ new Set([
|
|
2387
|
+
"stroke",
|
|
2388
|
+
"strokeWidth",
|
|
2389
|
+
"strokeOpacity",
|
|
2390
|
+
"strokeDasharray",
|
|
2391
|
+
"strokeLinecap",
|
|
2392
|
+
"opacity"
|
|
2393
|
+
]);
|
|
2394
|
+
const crosshairPaintProps = (props = {}) => {
|
|
2395
|
+
const pickPaint = (value) => Object.fromEntries(Object.entries(value).filter(([key]) => CROSSHAIR_PAINT_PROPERTIES.has(key)));
|
|
2396
|
+
return {
|
|
2397
|
+
...pickPaint(props),
|
|
2398
|
+
...props.className === void 0 ? {} : { className: props.className },
|
|
2399
|
+
...props.style === void 0 ? {} : { style: pickPaint(props.style) }
|
|
2400
|
+
};
|
|
2401
|
+
};
|
|
2276
2402
|
const DEFAULT_GLYPH_RADIUS = 4;
|
|
2277
2403
|
const FALLBACK_COLOR = "#222";
|
|
2278
2404
|
const DEFAULT_TOOLTIP_Z_INDEX = 3;
|
|
@@ -2303,7 +2429,7 @@ const defaultRenderGlyph$1 = ({ key, ...props }) => /* @__PURE__ */ (0, react_js
|
|
|
2303
2429
|
seriesKey: key,
|
|
2304
2430
|
...props
|
|
2305
2431
|
}, 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 }) => {
|
|
2432
|
+
const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, renderGlyph = defaultRenderGlyph$1, glyphStyle, snapTooltipToDatumX = false, snapTooltipToDatumY = false, showVerticalCrosshair = false, showHorizontalCrosshair = false, showDatumGlyph = false, showSeriesGlyphs = false, verticalCrosshairStyle, horizontalCrosshairStyle, detectBounds = true, tooltipPlacement = "auto", zIndex = DEFAULT_TOOLTIP_Z_INDEX, style, ...rest }) => {
|
|
2307
2433
|
const tooltipProps = Object.fromEntries(Object.entries(rest).filter(([key]) => !PORTAL_OPTIONS.has(key)));
|
|
2308
2434
|
const { colorScale, theme, innerHeight = 0, innerWidth = 0, margin, xScale, yScale, dataRegistry } = (0, react.useContext)(_visx_xychart.DataContext) || {};
|
|
2309
2435
|
const tooltipContent = renderTooltip ? renderTooltip({
|
|
@@ -2322,9 +2448,9 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2322
2448
|
};
|
|
2323
2449
|
const nearestDatum = tooltipContext.tooltipData?.nearestDatum;
|
|
2324
2450
|
let { tooltipLeft, tooltipTop } = tooltipContext;
|
|
2325
|
-
if (nearestDatum && (snapTooltipToDatumX || snapTooltipToDatumY)) {
|
|
2451
|
+
if (nearestDatum && (snapTooltipToDatumX || snapTooltipToDatumY || tooltipPlacement === "below-axis")) {
|
|
2326
2452
|
const { left, top } = getDatumLeftTop(nearestDatum.key, nearestDatum.datum);
|
|
2327
|
-
if (snapTooltipToDatumX && isValidNumber(left)) tooltipLeft = left;
|
|
2453
|
+
if ((snapTooltipToDatumX || tooltipPlacement === "below-axis") && isValidNumber(left)) tooltipLeft = left;
|
|
2328
2454
|
if (snapTooltipToDatumY && isValidNumber(top)) tooltipTop = top;
|
|
2329
2455
|
}
|
|
2330
2456
|
const glyphs = [];
|
|
@@ -2358,13 +2484,14 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2358
2484
|
const crosshairStroke = theme?.gridStyles?.stroke ?? theme?.htmlLabel?.color ?? FALLBACK_COLOR;
|
|
2359
2485
|
const marginTop = margin?.top ?? 0;
|
|
2360
2486
|
const marginLeft = margin?.left ?? 0;
|
|
2361
|
-
const TooltipComponent = detectBounds ? BoundedTooltip : _visx_tooltip.Tooltip;
|
|
2487
|
+
const TooltipComponent = detectBounds || tooltipPlacement === "below-axis" ? BoundedTooltip : _visx_tooltip.Tooltip;
|
|
2362
2488
|
const boxStyle = {
|
|
2363
2489
|
..._visx_tooltip.defaultStyles,
|
|
2364
2490
|
zIndex,
|
|
2365
|
-
|
|
2491
|
+
backgroundColor: theme?.backgroundColor ?? "white",
|
|
2366
2492
|
boxShadow: `0 1px 2px ${theme?.htmlLabel?.color ? `${theme.htmlLabel.color}55` : "#22222255"}`,
|
|
2367
|
-
...theme?.htmlLabel
|
|
2493
|
+
...theme?.htmlLabel,
|
|
2494
|
+
...style
|
|
2368
2495
|
};
|
|
2369
2496
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
|
|
2370
2497
|
className: "visx-tooltip-overlay",
|
|
@@ -2372,32 +2499,33 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2372
2499
|
children: [
|
|
2373
2500
|
showVerticalCrosshair && isValidNumber(tooltipLeft) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
2374
2501
|
className: "visx-crosshair visx-crosshair-vertical",
|
|
2502
|
+
stroke: crosshairStroke,
|
|
2503
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2504
|
+
...crosshairPaintProps(verticalCrosshairStyle),
|
|
2375
2505
|
x1: tooltipLeft,
|
|
2376
2506
|
x2: tooltipLeft,
|
|
2377
2507
|
y1: marginTop,
|
|
2378
|
-
y2: marginTop + innerHeight
|
|
2379
|
-
stroke: crosshairStroke,
|
|
2380
|
-
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2381
|
-
...verticalCrosshairStyle
|
|
2508
|
+
y2: marginTop + innerHeight
|
|
2382
2509
|
}),
|
|
2383
2510
|
showHorizontalCrosshair && isValidNumber(tooltipTop) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
|
|
2384
2511
|
className: "visx-crosshair visx-crosshair-horizontal",
|
|
2512
|
+
stroke: crosshairStroke,
|
|
2513
|
+
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2514
|
+
...crosshairPaintProps(horizontalCrosshairStyle),
|
|
2385
2515
|
x1: marginLeft,
|
|
2386
2516
|
x2: marginLeft + innerWidth,
|
|
2387
2517
|
y1: tooltipTop,
|
|
2388
|
-
y2: tooltipTop
|
|
2389
|
-
stroke: crosshairStroke,
|
|
2390
|
-
strokeWidth: CROSSHAIR_STROKE_WIDTH,
|
|
2391
|
-
...horizontalCrosshairStyle
|
|
2518
|
+
y2: tooltipTop
|
|
2392
2519
|
}),
|
|
2393
2520
|
glyphs
|
|
2394
2521
|
]
|
|
2395
2522
|
}), container && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipComponent, {
|
|
2396
2523
|
left: tooltipLeft,
|
|
2397
|
-
top: tooltipTop,
|
|
2524
|
+
top: tooltipPlacement === "below-axis" ? marginTop + innerHeight + (margin?.bottom ?? 0) : tooltipTop,
|
|
2398
2525
|
style: boxStyle,
|
|
2399
2526
|
applyPositionStyle: true,
|
|
2400
2527
|
...tooltipProps,
|
|
2528
|
+
...tooltipPlacement === "below-axis" && { placement: tooltipPlacement },
|
|
2401
2529
|
children: tooltipContent
|
|
2402
2530
|
}), container)] });
|
|
2403
2531
|
};
|
|
@@ -2418,7 +2546,8 @@ const XyChartTooltipContent = ({ tooltipContext, container, renderTooltip, rende
|
|
|
2418
2546
|
* isolation keeps the box's `zIndex` from competing with page chrome. The box
|
|
2419
2547
|
* flips and clamps to stay inside the nearest ancestor that clips its overflow
|
|
2420
2548
|
* (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.
|
|
2549
|
+
* off unless that ancestor is smaller than the box itself. Below-axis placement
|
|
2550
|
+
* pins it beneath the x-axis and applies horizontal bounds only.
|
|
2422
2551
|
*
|
|
2423
2552
|
* @param props - visx's `Tooltip` options. `scroll`, `debounce` and `resizeObserverPolyfill` are accepted and ignored.
|
|
2424
2553
|
* @return An anchor in the SVG, plus the overlay and the tooltip box while the tooltip is open.
|
|
@@ -2535,11 +2664,14 @@ const AccessibleTooltip = ({ renderTooltip, selectedIndex, tooltipRef, keyboardF
|
|
|
2535
2664
|
renderTooltip: focusableRenderTooltip
|
|
2536
2665
|
});
|
|
2537
2666
|
};
|
|
2538
|
-
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate }) => {
|
|
2667
|
+
const useKeyboardNavigation = ({ selectedIndex, setSelectedIndex, isNavigating, setIsNavigating, chartRef, totalPoints, onActivate, preventTooltipScroll = false }) => {
|
|
2539
2668
|
return {
|
|
2540
2669
|
tooltipRef: (0, react.useCallback)((element) => {
|
|
2541
|
-
if (element && selectedIndex !== void 0)
|
|
2542
|
-
|
|
2670
|
+
if (element && selectedIndex !== void 0) {
|
|
2671
|
+
if (preventTooltipScroll) element.focus({ preventScroll: true });
|
|
2672
|
+
else element.focus();
|
|
2673
|
+
}
|
|
2674
|
+
}, [preventTooltipScroll, selectedIndex]),
|
|
2543
2675
|
onChartFocus: (0, react.useCallback)(() => {
|
|
2544
2676
|
if (!isNavigating && selectedIndex !== void 0) setSelectedIndex(0);
|
|
2545
2677
|
}, [
|
|
@@ -3871,10 +4003,11 @@ const TooltipDate = ({ date, displayResolution }) => {
|
|
|
3871
4003
|
* one row per visible series (label + formatted value), sorted descending by
|
|
3872
4004
|
* value. Reused by AreaChart, which has the same multi-series shape.
|
|
3873
4005
|
*
|
|
3874
|
-
* @param params
|
|
4006
|
+
* @param params - visx tooltip data and the chart's optional `bucketInfo`.
|
|
4007
|
+
* @param contentStyle - Explicit tooltip content color overrides.
|
|
3875
4008
|
* @return Tooltip JSX, or `null` when no datum is hovered.
|
|
3876
4009
|
*/
|
|
3877
|
-
const renderDefaultTooltip = (params) => {
|
|
4010
|
+
const renderDefaultTooltip = (params, contentStyle) => {
|
|
3878
4011
|
const { tooltipData, bucketInfo } = params;
|
|
3879
4012
|
const nearestDatum = tooltipData?.nearestDatum?.datum;
|
|
3880
4013
|
if (!nearestDatum) return null;
|
|
@@ -3884,6 +4017,7 @@ const renderDefaultTooltip = (params) => {
|
|
|
3884
4017
|
})).sort((a, b) => b.value - a.value);
|
|
3885
4018
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3886
4019
|
className: line_chart_module_default["line-chart__tooltip"],
|
|
4020
|
+
style: contentStyle,
|
|
3887
4021
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3888
4022
|
className: line_chart_module_default["line-chart__tooltip-date"],
|
|
3889
4023
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TooltipDate, {
|
|
@@ -3933,7 +4067,7 @@ const LineChartScalesRef = ({ chartRef, width, height, margin }) => {
|
|
|
3933
4067
|
]);
|
|
3934
4068
|
return null;
|
|
3935
4069
|
};
|
|
3936
|
-
const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, withStartGlyphs = false, withEndGlyphs = false, animation, options = {}, onPointerDown = void 0, onPointerUp = void 0, onPointerMove = void 0, onPointerOut = void 0, onDatumActivate = void 0, zoomable = false, rescaleYOnVisibilityChange = true, defaultHiddenSeries, children, gridVisibility, gap = "md" }, ref) => {
|
|
4070
|
+
const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartId, width, height, className, margin, withTooltips = true, withTooltipCrosshairs, showLegend = false, legend = {}, renderGlyph = defaultRenderGlyph, glyphStyle = {}, withLegendGlyph = false, withGradientFill = false, smoothing = true, curveType, renderTooltip = renderDefaultTooltip, 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) => {
|
|
3937
4071
|
const legendInteractive = legend.interactive ?? false;
|
|
3938
4072
|
const legendCollapseGroups = legend.collapseGroups ?? false;
|
|
3939
4073
|
const legendShape = legend.shape ?? "line";
|
|
@@ -4011,7 +4145,8 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4011
4145
|
setIsNavigating,
|
|
4012
4146
|
chartRef,
|
|
4013
4147
|
totalPoints: dataSorted[0]?.data.length || 0,
|
|
4014
|
-
onActivate: activateSelectedPoint
|
|
4148
|
+
onActivate: activateSelectedPoint,
|
|
4149
|
+
preventTooltipScroll: tooltipPlacement === "below-axis"
|
|
4015
4150
|
});
|
|
4016
4151
|
const chartOptions = (0, react.useMemo)(() => {
|
|
4017
4152
|
return {
|
|
@@ -4120,10 +4255,29 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4120
4255
|
xAccessor: (d) => d?.date,
|
|
4121
4256
|
yAccessor: (d) => d?.value
|
|
4122
4257
|
};
|
|
4123
|
-
const
|
|
4258
|
+
const resolvedTooltipStyle = (0, react.useMemo)(() => {
|
|
4259
|
+
if (renderTooltip !== renderDefaultTooltip || !tooltipStyle) return tooltipStyle;
|
|
4260
|
+
if (!tooltipStyle.color || tooltipStyle.background || tooltipStyle.backgroundColor) return tooltipStyle;
|
|
4261
|
+
return {
|
|
4262
|
+
backgroundColor: "var(--a8c-charts-color-tooltip-surface, rgb(0 0 0 / 85%))",
|
|
4263
|
+
...tooltipStyle
|
|
4264
|
+
};
|
|
4265
|
+
}, [renderTooltip, tooltipStyle]);
|
|
4266
|
+
const tooltipRenderer = (0, react.useMemo)(() => (params) => renderTooltip === renderDefaultTooltip ? renderDefaultTooltip({
|
|
4124
4267
|
...params,
|
|
4125
4268
|
bucketInfo
|
|
4126
|
-
}
|
|
4269
|
+
}, {
|
|
4270
|
+
color: tooltipStyle?.color,
|
|
4271
|
+
background: tooltipStyle?.background,
|
|
4272
|
+
backgroundColor: tooltipStyle?.backgroundColor
|
|
4273
|
+
}) : renderTooltip({
|
|
4274
|
+
...params,
|
|
4275
|
+
bucketInfo
|
|
4276
|
+
}), [
|
|
4277
|
+
renderTooltip,
|
|
4278
|
+
bucketInfo,
|
|
4279
|
+
tooltipStyle
|
|
4280
|
+
]);
|
|
4127
4281
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4128
4282
|
className: (0, clsx.default)("line-chart", line_chart_module_default["line-chart"]),
|
|
4129
4283
|
children: error
|
|
@@ -4262,6 +4416,8 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4262
4416
|
withTooltips && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccessibleTooltip, {
|
|
4263
4417
|
detectBounds: true,
|
|
4264
4418
|
snapTooltipToDatumX: true,
|
|
4419
|
+
tooltipPlacement,
|
|
4420
|
+
style: resolvedTooltipStyle,
|
|
4265
4421
|
snapTooltipToDatumY: true,
|
|
4266
4422
|
showSeriesGlyphs: true,
|
|
4267
4423
|
renderTooltip: tooltipRenderer,
|
|
@@ -4269,6 +4425,8 @@ const LineChartInternal = (0, react.forwardRef)(({ data, chartId: providedChartI
|
|
|
4269
4425
|
glyphStyle,
|
|
4270
4426
|
showVerticalCrosshair: withTooltipCrosshairs?.showVertical,
|
|
4271
4427
|
showHorizontalCrosshair: withTooltipCrosshairs?.showHorizontal,
|
|
4428
|
+
verticalCrosshairStyle: withTooltipCrosshairs?.verticalStyle,
|
|
4429
|
+
horizontalCrosshairStyle: withTooltipCrosshairs?.horizontalStyle,
|
|
4272
4430
|
selectedIndex,
|
|
4273
4431
|
tooltipRef,
|
|
4274
4432
|
keyboardFocusedClassName: line_chart_module_default["line-chart__tooltip--keyboard-focused"],
|
|
@@ -6421,9 +6579,13 @@ var heatmap_chart_module_default = {
|
|
|
6421
6579
|
"heatmap-chart__cell--placeholder": "a8ccharts-O3YMOW-heatmap-chart__cell--placeholder",
|
|
6422
6580
|
"heatmap-chart__cell--selected": "a8ccharts-O3YMOW-heatmap-chart__cell--selected",
|
|
6423
6581
|
"heatmap-chart__cell--strong": "a8ccharts-O3YMOW-heatmap-chart__cell--strong",
|
|
6582
|
+
"heatmap-chart__cell--summary": "a8ccharts-O3YMOW-heatmap-chart__cell--summary",
|
|
6424
6583
|
"heatmap-chart__cell-value": "a8ccharts-O3YMOW-heatmap-chart__cell-value",
|
|
6425
6584
|
"heatmap-chart__col-label": "a8ccharts-O3YMOW-heatmap-chart__col-label",
|
|
6585
|
+
"heatmap-chart__col-label--summary": "a8ccharts-O3YMOW-heatmap-chart__col-label--summary",
|
|
6426
6586
|
"heatmap-chart__empty": "a8ccharts-O3YMOW-heatmap-chart__empty",
|
|
6587
|
+
"heatmap-chart__gap-end": "a8ccharts-O3YMOW-heatmap-chart__gap-end",
|
|
6588
|
+
"heatmap-chart__gap-start": "a8ccharts-O3YMOW-heatmap-chart__gap-start",
|
|
6427
6589
|
"heatmap-chart__grid": "a8ccharts-O3YMOW-heatmap-chart__grid",
|
|
6428
6590
|
"heatmap-chart__grid--compact": "a8ccharts-O3YMOW-heatmap-chart__grid--compact",
|
|
6429
6591
|
"heatmap-chart__grid--height-capped": "a8ccharts-O3YMOW-heatmap-chart__grid--height-capped",
|
|
@@ -6437,17 +6599,21 @@ var heatmap_chart_module_default = {
|
|
|
6437
6599
|
//#region src/charts/heatmap-chart/private/use-heatmap-colors.ts
|
|
6438
6600
|
const isPresent = (value) => value !== null && value !== void 0 && !isNaN(value);
|
|
6439
6601
|
/**
|
|
6440
|
-
* Get the min and max values from heatmap data, ignoring null/NaN.
|
|
6602
|
+
* Get the min and max values from heatmap data, ignoring null/NaN. Summary
|
|
6603
|
+
* columns stay out: a roll-up on the scale would flatten every real cell.
|
|
6441
6604
|
* @param data - The heatmap columns
|
|
6442
6605
|
* @return Tuple of [min, max] values
|
|
6443
6606
|
*/
|
|
6444
6607
|
const getValueExtent = (data) => {
|
|
6445
6608
|
let min = Infinity;
|
|
6446
6609
|
let max = -Infinity;
|
|
6447
|
-
for (const column of data)
|
|
6448
|
-
if (
|
|
6449
|
-
|
|
6450
|
-
|
|
6610
|
+
for (const column of data) {
|
|
6611
|
+
if (column.summary) continue;
|
|
6612
|
+
for (const cell of column.data) {
|
|
6613
|
+
if (!isPresent(cell.value)) continue;
|
|
6614
|
+
if (cell.value < min) min = cell.value;
|
|
6615
|
+
if (cell.value > max) max = cell.value;
|
|
6616
|
+
}
|
|
6451
6617
|
}
|
|
6452
6618
|
if (min === Infinity) return [0, 0];
|
|
6453
6619
|
return [min, max];
|
|
@@ -6468,6 +6634,119 @@ const getNormalizedValue = (value, extent) => {
|
|
|
6468
6634
|
return Math.min(1, Math.max(0, (value - min) / (max - min)));
|
|
6469
6635
|
};
|
|
6470
6636
|
//#endregion
|
|
6637
|
+
//#region src/charts/heatmap-chart/private/civil-day.ts
|
|
6638
|
+
const DAY_MS = 864e5;
|
|
6639
|
+
const KEY_OPTIONS = {
|
|
6640
|
+
calendar: "gregory",
|
|
6641
|
+
numberingSystem: "latn",
|
|
6642
|
+
year: "numeric",
|
|
6643
|
+
month: "2-digit",
|
|
6644
|
+
day: "2-digit"
|
|
6645
|
+
};
|
|
6646
|
+
const DATE_PREFIX = /^(\d{4})-(\d{2})-(\d{2})/;
|
|
6647
|
+
const pad = (value, length) => String(value).padStart(length, "0");
|
|
6648
|
+
/**
|
|
6649
|
+
* The day a UTC proxy stands for.
|
|
6650
|
+
*
|
|
6651
|
+
* @param date - UTC proxy.
|
|
6652
|
+
* @return Its day key.
|
|
6653
|
+
*/
|
|
6654
|
+
const civilKey = (date) => `${pad(date.getUTCFullYear(), 4)}-${pad(date.getUTCMonth() + 1, 2)}-${pad(date.getUTCDate(), 2)}`;
|
|
6655
|
+
/**
|
|
6656
|
+
* A day key as a UTC-midnight proxy. UTC has no DST, so every step below is exactly
|
|
6657
|
+
* `DAY_MS`.
|
|
6658
|
+
*
|
|
6659
|
+
* @param key - Day key.
|
|
6660
|
+
* @return The proxy, or null when the key names no real day.
|
|
6661
|
+
*/
|
|
6662
|
+
const civilDate = (key) => {
|
|
6663
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(key);
|
|
6664
|
+
if (!match) return null;
|
|
6665
|
+
const date = /* @__PURE__ */ new Date(0);
|
|
6666
|
+
date.setUTCFullYear(Number(match[1]), Number(match[2]) - 1, Number(match[3]));
|
|
6667
|
+
date.setUTCHours(0, 0, 0, 0);
|
|
6668
|
+
return civilKey(date) === key ? date : null;
|
|
6669
|
+
};
|
|
6670
|
+
/**
|
|
6671
|
+
* The day a written date names, ignoring any time and zone it carries.
|
|
6672
|
+
*
|
|
6673
|
+
* @param text - `yyyy-MM-dd`, optionally followed by a time.
|
|
6674
|
+
* @return Its day key, or null.
|
|
6675
|
+
*/
|
|
6676
|
+
const writtenDayKey = (text) => {
|
|
6677
|
+
const match = DATE_PREFIX.exec(text);
|
|
6678
|
+
if (!match) return null;
|
|
6679
|
+
const key = `${match[1]}-${match[2]}-${match[3]}`;
|
|
6680
|
+
return civilDate(key) ? key : null;
|
|
6681
|
+
};
|
|
6682
|
+
/**
|
|
6683
|
+
* Reads the day an instant falls on in a zone.
|
|
6684
|
+
*
|
|
6685
|
+
* @param timeZone - IANA zone name; absent leaves the runtime's own.
|
|
6686
|
+
* @return Reader taking a `Date`, null for a day no key can hold.
|
|
6687
|
+
*/
|
|
6688
|
+
const instantDayReader = (timeZone) => {
|
|
6689
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
6690
|
+
...KEY_OPTIONS,
|
|
6691
|
+
timeZone
|
|
6692
|
+
});
|
|
6693
|
+
return (date) => {
|
|
6694
|
+
const parts = formatter.formatToParts(date);
|
|
6695
|
+
const read = (type) => parts.find((part) => part.type === type)?.value ?? "";
|
|
6696
|
+
const key = `${pad(Number(read("year")), 4)}-${read("month")}-${read("day")}`;
|
|
6697
|
+
return civilDate(key) ? key : null;
|
|
6698
|
+
};
|
|
6699
|
+
};
|
|
6700
|
+
/**
|
|
6701
|
+
* The day a series point belongs to.
|
|
6702
|
+
*
|
|
6703
|
+
* A `Date`, or a string carrying `Z` or an offset, is an instant read in the host's
|
|
6704
|
+
* zone. Anything else is a wall clock the host wrote, so its date part is the day.
|
|
6705
|
+
*
|
|
6706
|
+
* @param point - Series point.
|
|
6707
|
+
* @param readInstant - Reader from `instantDayReader`.
|
|
6708
|
+
* @return Its day key, or null when the point carries no usable date.
|
|
6709
|
+
*/
|
|
6710
|
+
const pointDayKey = (point, readInstant) => {
|
|
6711
|
+
if (point.date instanceof Date && !isNaN(point.date.getTime())) {
|
|
6712
|
+
const key = readInstant(point.date);
|
|
6713
|
+
if (key) return key;
|
|
6714
|
+
}
|
|
6715
|
+
const text = point.dateString;
|
|
6716
|
+
if (!text) return null;
|
|
6717
|
+
if (!hasTimezone(text)) return writtenDayKey(text);
|
|
6718
|
+
const parsed = (0, date_fns.parseISO)(text);
|
|
6719
|
+
return isNaN(parsed.getTime()) ? null : readInstant(parsed);
|
|
6720
|
+
};
|
|
6721
|
+
/**
|
|
6722
|
+
* Steps a proxy by whole days.
|
|
6723
|
+
*
|
|
6724
|
+
* @param date - UTC proxy.
|
|
6725
|
+
* @param days - Days to add; may be negative.
|
|
6726
|
+
* @return The shifted proxy.
|
|
6727
|
+
*/
|
|
6728
|
+
const addCivilDays = (date, days) => new Date(date.getTime() + days * DAY_MS);
|
|
6729
|
+
/**
|
|
6730
|
+
* Rounds a proxy down to its week.
|
|
6731
|
+
*
|
|
6732
|
+
* @param date - UTC proxy.
|
|
6733
|
+
* @param weekStartsOn - 0 for Sunday, 1 for Monday.
|
|
6734
|
+
* @return The proxy for that week's first day.
|
|
6735
|
+
*/
|
|
6736
|
+
const startOfCivilWeek = (date, weekStartsOn) => {
|
|
6737
|
+
const daysSinceWeekStart = (date.getUTCDay() - weekStartsOn + 7) % 7;
|
|
6738
|
+
return addCivilDays(date, -daysSinceWeekStart);
|
|
6739
|
+
};
|
|
6740
|
+
/**
|
|
6741
|
+
* Counts the columns a span needs.
|
|
6742
|
+
*
|
|
6743
|
+
* @param from - Earlier UTC proxy.
|
|
6744
|
+
* @param to - Later UTC proxy.
|
|
6745
|
+
* @param weekStartsOn - 0 for Sunday, 1 for Monday.
|
|
6746
|
+
* @return Columns needed to cover the span, inclusive.
|
|
6747
|
+
*/
|
|
6748
|
+
const civilWeekSpan = (from, to, weekStartsOn) => Math.floor((startOfCivilWeek(to, weekStartsOn).getTime() - startOfCivilWeek(from, weekStartsOn).getTime()) / (7 * DAY_MS)) + 1;
|
|
6749
|
+
//#endregion
|
|
6471
6750
|
//#region src/charts/heatmap-chart/private/build-calendar-data.ts
|
|
6472
6751
|
/** Rows that get a weekday label (Mon, Wed, Fri with a Monday week start). */
|
|
6473
6752
|
const LABELLED_ROWS = [
|
|
@@ -6482,69 +6761,88 @@ const LABELLED_ROWS = [
|
|
|
6482
6761
|
* @param bound - Requested bound as `yyyy-MM-dd`, if any.
|
|
6483
6762
|
* @param fallback - The series' own bound on this side.
|
|
6484
6763
|
* @param direction - Which way the bound is allowed to move.
|
|
6485
|
-
* @return The
|
|
6764
|
+
* @return The day key to draw to.
|
|
6486
6765
|
*/
|
|
6487
6766
|
const widenTo = (bound, fallback, direction) => {
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
return parsed > fallback ? parsed : fallback;
|
|
6493
|
-
};
|
|
6494
|
-
const toDate = (point) => {
|
|
6495
|
-
if (point.date instanceof Date && !isNaN(point.date.getTime())) return point.date;
|
|
6496
|
-
if (point.dateString) {
|
|
6497
|
-
const parsed = (0, date_fns.parseISO)(point.dateString);
|
|
6498
|
-
if (!isNaN(parsed.getTime())) return parsed;
|
|
6767
|
+
const key = bound ? writtenDayKey(bound) : null;
|
|
6768
|
+
if (!key) {
|
|
6769
|
+
if (bound) warnOnce(`heatmap:gridSpan:${bound}`, `gridSpan.${direction === "earlier" ? "start" : "end"} ${JSON.stringify(bound)} is not a \`yyyy-MM-dd\` day, so the grid is drawn over the series' own span.`);
|
|
6770
|
+
return fallback;
|
|
6499
6771
|
}
|
|
6500
|
-
return
|
|
6772
|
+
if (direction === "earlier") return key < fallback ? key : fallback;
|
|
6773
|
+
return key > fallback ? key : fallback;
|
|
6501
6774
|
};
|
|
6775
|
+
/**
|
|
6776
|
+
* Lay a day-bucketed series out as calendar columns.
|
|
6777
|
+
*
|
|
6778
|
+
* @param series - Points to bucket.
|
|
6779
|
+
* @param options - Grid shape, plus the locale and zone to read days in.
|
|
6780
|
+
* @return Columns and row labels for `HeatmapChart`.
|
|
6781
|
+
*/
|
|
6502
6782
|
const buildCalendarHeatmapData = (series, options = {}) => {
|
|
6503
6783
|
const weekStartsOn = options.weekStartsOn ?? 1;
|
|
6504
6784
|
const hideOutOfRangeDays = options.hideOutOfRangeDays ?? true;
|
|
6505
|
-
const
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
})
|
|
6509
|
-
|
|
6785
|
+
const { locale, timeZone } = sanitizeFormatting({
|
|
6786
|
+
locale: options.locale,
|
|
6787
|
+
timeZone: options.timeZone
|
|
6788
|
+
});
|
|
6789
|
+
const readInstant = instantDayReader(timeZone);
|
|
6790
|
+
const valueByDay = /* @__PURE__ */ new Map();
|
|
6791
|
+
let minDayKey;
|
|
6792
|
+
let maxDayKey;
|
|
6793
|
+
for (const point of series) {
|
|
6794
|
+
const key = pointDayKey(point, readInstant);
|
|
6795
|
+
if (!key) {
|
|
6796
|
+
const offending = point.dateString ?? (point.date && String(point.date));
|
|
6797
|
+
warnOnce(`heatmap:unreadableDate:${offending}`, offending ? `${JSON.stringify(offending)} is not a day this can read, so its point is left out of the calendar. A \`dateString\` must start \`yyyy-MM-dd\`.` : "A point carries neither `date` nor `dateString`, so it is left out of the calendar.");
|
|
6798
|
+
continue;
|
|
6799
|
+
}
|
|
6800
|
+
valueByDay.set(key, point.value);
|
|
6801
|
+
if (!minDayKey || key < minDayKey) minDayKey = key;
|
|
6802
|
+
if (!maxDayKey || key > maxDayKey) maxDayKey = key;
|
|
6803
|
+
}
|
|
6804
|
+
if (!minDayKey || !maxDayKey) return {
|
|
6510
6805
|
data: [],
|
|
6511
6806
|
rowLabels: []
|
|
6512
6807
|
};
|
|
6513
|
-
const
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
}
|
|
6521
|
-
const
|
|
6522
|
-
const
|
|
6523
|
-
const
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6527
|
-
|
|
6528
|
-
|
|
6529
|
-
const
|
|
6808
|
+
const requestedMinDayKey = widenTo(options.gridSpan?.start, minDayKey, "earlier");
|
|
6809
|
+
const gridMaxDayKey = widenTo(options.gridSpan?.end, maxDayKey, "later");
|
|
6810
|
+
const requestedMinDate = civilDate(requestedMinDayKey);
|
|
6811
|
+
const gridMaxDate = civilDate(gridMaxDayKey);
|
|
6812
|
+
const labelFormatting = {
|
|
6813
|
+
locale,
|
|
6814
|
+
timeZone: "UTC"
|
|
6815
|
+
};
|
|
6816
|
+
const formatWeekday = createDateFormatter({ weekday: "short" }, labelFormatting);
|
|
6817
|
+
const formatMonth = createDateFormatter({ month: "short" }, labelFormatting);
|
|
6818
|
+
const formatDay = createDateFormatter({
|
|
6819
|
+
weekday: "short",
|
|
6820
|
+
month: "short",
|
|
6821
|
+
day: "numeric",
|
|
6822
|
+
year: "numeric"
|
|
6823
|
+
}, labelFormatting);
|
|
6824
|
+
const gridStart = startOfCivilWeek(requestedMinDate, weekStartsOn);
|
|
6825
|
+
const gridMinDayKey = requestedMinDayKey < minDayKey ? civilKey(gridStart) : requestedMinDayKey;
|
|
6826
|
+
const weekCount = civilWeekSpan(gridStart, gridMaxDate, weekStartsOn);
|
|
6827
|
+
const rowLabels = Array.from({ length: 7 }, (_, row) => LABELLED_ROWS.includes(row) ? formatWeekday(addCivilDays(gridStart, row)) : "");
|
|
6530
6828
|
const MIN_FIRST_MONTH_WEEKS = 2;
|
|
6531
|
-
const firstMonth = gridStart.
|
|
6829
|
+
const firstMonth = gridStart.getUTCMonth();
|
|
6532
6830
|
let firstMonthWeeks = 0;
|
|
6533
|
-
while (firstMonthWeeks < weekCount && (
|
|
6831
|
+
while (firstMonthWeeks < weekCount && addCivilDays(gridStart, firstMonthWeeks * 7).getUTCMonth() === firstMonth) firstMonthWeeks++;
|
|
6534
6832
|
const showFirstMonthLabel = !(firstMonthWeeks < weekCount) || firstMonthWeeks >= MIN_FIRST_MONTH_WEEKS;
|
|
6535
6833
|
const data = [];
|
|
6536
6834
|
let previousMonth = -1;
|
|
6537
6835
|
for (let week = 0; week < weekCount; week++) {
|
|
6538
|
-
const columnStart = (
|
|
6539
|
-
const month = columnStart.
|
|
6540
|
-
const label = month !== previousMonth && (week !== 0 || showFirstMonthLabel) ? (
|
|
6836
|
+
const columnStart = addCivilDays(gridStart, week * 7);
|
|
6837
|
+
const month = columnStart.getUTCMonth();
|
|
6838
|
+
const label = month !== previousMonth && (week !== 0 || showFirstMonthLabel) ? formatMonth(columnStart) : "";
|
|
6541
6839
|
previousMonth = month;
|
|
6542
6840
|
const cells = [];
|
|
6543
6841
|
for (let row = 0; row < 7; row++) {
|
|
6544
|
-
const day = (
|
|
6545
|
-
const key = (
|
|
6842
|
+
const day = addCivilDays(gridStart, week * 7 + row);
|
|
6843
|
+
const key = civilKey(day);
|
|
6546
6844
|
const cell = {
|
|
6547
|
-
label: (
|
|
6845
|
+
label: formatDay(day),
|
|
6548
6846
|
value: valueByDay.has(key) ? valueByDay.get(key) : null
|
|
6549
6847
|
};
|
|
6550
6848
|
if (key < gridMinDayKey || key > gridMaxDayKey) {
|
|
@@ -6612,7 +6910,8 @@ const HeatmapLegend = ({ steps = 5, lessLabel, moreLabel }) => {
|
|
|
6612
6910
|
//#endregion
|
|
6613
6911
|
//#region src/charts/heatmap-chart/heatmap-chart.tsx
|
|
6614
6912
|
const CELL_MIX_FLOOR = .15;
|
|
6615
|
-
const
|
|
6913
|
+
const NO_ROW_LABELS = [];
|
|
6914
|
+
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 }) => {
|
|
6616
6915
|
const chartId = useChartId(providedChartId);
|
|
6617
6916
|
const { getElementStyles, theme } = useGlobalChartsContext();
|
|
6618
6917
|
const scopeElement = useChartScopeElement();
|
|
@@ -6763,13 +7062,20 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6763
7062
|
const rowTrack = compact ? "var(--a8c-charts-dimension-heatmap-cell-size)" : `minmax(${minCellHeight ?? 0}px, ${maxCellHeight ? `${maxCellHeight}px` : "1fr"})`;
|
|
6764
7063
|
const gridStyle = {
|
|
6765
7064
|
"--a8c-charts-color-heatmap-primary": primaryColorHex,
|
|
6766
|
-
gridTemplateColumns: `auto repeat(${columns}, ${columnTrack})`,
|
|
7065
|
+
gridTemplateColumns: `auto ${data.some((column) => column.summary) ? data.map((column) => column.summary ? "minmax(auto, max-content)" : columnTrack).join(" ") : `repeat(${columns}, ${columnTrack})`}`,
|
|
6767
7066
|
gridTemplateRows: `auto repeat(${rows}, ${rowTrack})`
|
|
6768
7067
|
};
|
|
6769
7068
|
if (compact) {
|
|
6770
7069
|
gridStyle["--a8c-charts-dimension-heatmap-cell-gap"] = `${compactCellGap}px`;
|
|
6771
7070
|
gridStyle["--a8c-charts-dimension-heatmap-cell-size"] = `${compactCellSize}px`;
|
|
6772
7071
|
}
|
|
7072
|
+
const summaryGaps = (columnIndex) => {
|
|
7073
|
+
if (!data[columnIndex]?.summary) return {};
|
|
7074
|
+
return {
|
|
7075
|
+
[heatmap_chart_module_default["heatmap-chart__gap-start"]]: columnIndex > 0 && !data[columnIndex - 1]?.summary,
|
|
7076
|
+
[heatmap_chart_module_default["heatmap-chart__gap-end"]]: columnIndex < columns - 1 && !data[columnIndex + 1]?.summary
|
|
7077
|
+
};
|
|
7078
|
+
};
|
|
6773
7079
|
const activeDescendant = selectedIndex !== void 0 ? `${chartId}-cell-${Math.floor(selectedIndex / rows)}-${selectedIndex % rows}` : void 0;
|
|
6774
7080
|
const heightCapped = !compact && Boolean(maxCellHeight);
|
|
6775
7081
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(HeatmapContext.Provider, {
|
|
@@ -6807,7 +7113,10 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6807
7113
|
"aria-hidden": "true",
|
|
6808
7114
|
className: heatmap_chart_module_default["heatmap-chart__row"],
|
|
6809
7115
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {}), data.map((column, columnIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6810
|
-
className: heatmap_chart_module_default["heatmap-chart__col-label"],
|
|
7116
|
+
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__col-label"], {
|
|
7117
|
+
[heatmap_chart_module_default["heatmap-chart__col-label--summary"]]: column.summary,
|
|
7118
|
+
...summaryGaps(columnIndex)
|
|
7119
|
+
}),
|
|
6811
7120
|
children: column.label
|
|
6812
7121
|
}, `col-${columnIndex}`))]
|
|
6813
7122
|
}), Array.from({ length: rows }).map((_row, rowIndex) => {
|
|
@@ -6832,7 +7141,8 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6832
7141
|
}, `cell-${columnIndex}-${rowIndex}`);
|
|
6833
7142
|
const value = cell?.value ?? null;
|
|
6834
7143
|
const present = isPresent(value);
|
|
6835
|
-
const
|
|
7144
|
+
const filled = present && !column.summary;
|
|
7145
|
+
const normalized = filled ? getNormalizedValue(value, extent) : 0;
|
|
6836
7146
|
const flatIndex = columnIndex * rows + rowIndex;
|
|
6837
7147
|
const info = buildTooltipData(columnIndex, rowIndex);
|
|
6838
7148
|
const accessibleLabel = `${info.cellLabel || `${info.columnLabel ?? ""} ${info.rowLabel ?? ""}`.trim()}: ${info.value === null ? (0, _wordpress_i18n.__)("No data", "jetpack-charts") : (0, _automattic_number_formatters.formatNumber)(info.value)}`;
|
|
@@ -6845,14 +7155,16 @@ const HeatmapChartInternal = ({ data, chartId: providedChartId, width = 0, heigh
|
|
|
6845
7155
|
"data-column": columnIndex,
|
|
6846
7156
|
"data-row": rowIndex,
|
|
6847
7157
|
className: (0, clsx.default)(heatmap_chart_module_default["heatmap-chart__cell"], {
|
|
6848
|
-
[heatmap_chart_module_default["heatmap-chart__cell--filled"]]:
|
|
6849
|
-
[heatmap_chart_module_default["heatmap-chart__cell--strong"]]:
|
|
7158
|
+
[heatmap_chart_module_default["heatmap-chart__cell--filled"]]: filled,
|
|
7159
|
+
[heatmap_chart_module_default["heatmap-chart__cell--strong"]]: filled && cellHasLightText(normalized),
|
|
7160
|
+
[heatmap_chart_module_default["heatmap-chart__cell--summary"]]: column.summary,
|
|
7161
|
+
...summaryGaps(columnIndex),
|
|
6850
7162
|
[heatmap_chart_module_default["heatmap-chart__cell--selected"]]: selectedIndex === flatIndex
|
|
6851
7163
|
}),
|
|
6852
|
-
style:
|
|
7164
|
+
style: filled ? { "--a8c-charts-heatmap-cell-intensity": normalized } : void 0,
|
|
6853
7165
|
onMouseMove: handleCellMouseMove,
|
|
6854
7166
|
onMouseLeave: handleCellMouseLeave,
|
|
6855
|
-
children: drawValues && present && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7167
|
+
children: (drawValues || column.summary) && present && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6856
7168
|
className: heatmap_chart_module_default["heatmap-chart__cell-value"],
|
|
6857
7169
|
children: (0, _automattic_number_formatters.formatNumberCompact)(value)
|
|
6858
7170
|
})
|
|
@@ -6888,6 +7200,42 @@ const HeatmapChartResponsiveInner = (props) => /* @__PURE__ */ (0, react_jsx_run
|
|
|
6888
7200
|
HeatmapChartResponsiveInner.displayName = "HeatmapChart";
|
|
6889
7201
|
const HeatmapChartResponsive = attachSubComponents(withResponsive(HeatmapChartResponsiveInner), { Legend: HeatmapLegend });
|
|
6890
7202
|
//#endregion
|
|
7203
|
+
//#region src/charts/heatmap-chart/use-calendar-heatmap-data.ts
|
|
7204
|
+
/**
|
|
7205
|
+
* `buildCalendarHeatmapData` with the locale and zone taken from
|
|
7206
|
+
* `GlobalChartsProvider` where the caller names neither.
|
|
7207
|
+
*
|
|
7208
|
+
* @param series - Points to bucket. Held by reference, so a caller that rebuilds it each render defeats the memo.
|
|
7209
|
+
* @param options - As for `buildCalendarHeatmapData`; `locale` and `timeZone` win over the provider.
|
|
7210
|
+
* @return Columns and row labels for `HeatmapChart`.
|
|
7211
|
+
*/
|
|
7212
|
+
const useCalendarHeatmapData = (series, options = {}) => {
|
|
7213
|
+
const formatting = useChartFormatting();
|
|
7214
|
+
const locale = options.locale ?? formatting.locale;
|
|
7215
|
+
const timeZone = options.timeZone ?? formatting.timeZone;
|
|
7216
|
+
const { weekStartsOn, hideOutOfRangeDays } = options;
|
|
7217
|
+
const gridStart = options.gridSpan?.start;
|
|
7218
|
+
const gridEnd = options.gridSpan?.end;
|
|
7219
|
+
return (0, react.useMemo)(() => buildCalendarHeatmapData(series, {
|
|
7220
|
+
locale,
|
|
7221
|
+
timeZone,
|
|
7222
|
+
weekStartsOn,
|
|
7223
|
+
hideOutOfRangeDays,
|
|
7224
|
+
gridSpan: {
|
|
7225
|
+
start: gridStart,
|
|
7226
|
+
end: gridEnd
|
|
7227
|
+
}
|
|
7228
|
+
}), [
|
|
7229
|
+
series,
|
|
7230
|
+
locale,
|
|
7231
|
+
timeZone,
|
|
7232
|
+
weekStartsOn,
|
|
7233
|
+
hideOutOfRangeDays,
|
|
7234
|
+
gridStart,
|
|
7235
|
+
gridEnd
|
|
7236
|
+
]);
|
|
7237
|
+
};
|
|
7238
|
+
//#endregion
|
|
6891
7239
|
//#region ../../../node_modules/.pnpm/is-plain-object@5.1.0/node_modules/is-plain-object/dist/is-plain-object.mjs
|
|
6892
7240
|
/*!
|
|
6893
7241
|
* is-plain-object <https://github.com/jonschlinkert/is-plain-object>
|
|
@@ -7251,7 +7599,7 @@ var require_dist = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
7251
7599
|
tslib_1.__exportStar(require_dist$1(), exports);
|
|
7252
7600
|
}));
|
|
7253
7601
|
//#endregion
|
|
7254
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
7602
|
+
//#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
|
|
7255
7603
|
function useUpdateEffect(effect, deps) {
|
|
7256
7604
|
const mountedRef = (0, react.useRef)(false);
|
|
7257
7605
|
(0, react.useEffect)(() => {
|
|
@@ -8889,7 +9237,7 @@ _createEmotion.css;
|
|
|
8889
9237
|
_createEmotion.sheet;
|
|
8890
9238
|
_createEmotion.cache;
|
|
8891
9239
|
//#endregion
|
|
8892
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9240
|
+
//#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
|
|
8893
9241
|
var isSerializedStyles = (o) => typeof o !== "undefined" && o !== null && ["name", "styles"].every((p) => typeof o[p] !== "undefined");
|
|
8894
9242
|
var useCx = () => {
|
|
8895
9243
|
const cache = __unsafe_useEmotionCache();
|
|
@@ -8996,7 +9344,7 @@ function memize(fn, options) {
|
|
|
8996
9344
|
return memoized;
|
|
8997
9345
|
}
|
|
8998
9346
|
//#endregion
|
|
8999
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9347
|
+
//#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
|
|
9000
9348
|
var white = "#fff";
|
|
9001
9349
|
var GRAY = {
|
|
9002
9350
|
900: "#1e1e1e",
|
|
@@ -9075,7 +9423,7 @@ var COLORS = Object.freeze({
|
|
|
9075
9423
|
ui: UI
|
|
9076
9424
|
});
|
|
9077
9425
|
//#endregion
|
|
9078
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9426
|
+
//#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
|
|
9079
9427
|
var CONTROL_HEIGHT = "36px";
|
|
9080
9428
|
var CONTROL_PROPS = {
|
|
9081
9429
|
controlPaddingX: 12,
|
|
@@ -9193,7 +9541,7 @@ function warning(message) {
|
|
|
9193
9541
|
logged.add(message);
|
|
9194
9542
|
}
|
|
9195
9543
|
//#endregion
|
|
9196
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9544
|
+
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@date-fns+tz@1.4.1_@types+react-dom@18.3.7_@types+react@18_4546240ebdf94d561ebf2fde285113fe/node_modules/@wordpress/components/build-module/context/context-system-provider.mjs
|
|
9197
9545
|
var import_es6 = /* @__PURE__ */ __toESM(require_es6(), 1);
|
|
9198
9546
|
var ComponentsContext = (0, react.createContext)(
|
|
9199
9547
|
/** @type {Record<string, any>} */
|
|
@@ -9220,19 +9568,19 @@ var BaseContextSystemProvider = ({ children, value }) => {
|
|
|
9220
9568
|
};
|
|
9221
9569
|
(0, react.memo)(BaseContextSystemProvider);
|
|
9222
9570
|
//#endregion
|
|
9223
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9571
|
+
//#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
|
|
9224
9572
|
var COMPONENT_NAMESPACE = "data-wp-component";
|
|
9225
9573
|
var CONNECTED_NAMESPACE = "data-wp-c16t";
|
|
9226
9574
|
var CONNECT_STATIC_NAMESPACE = "__contextSystemKey__";
|
|
9227
9575
|
//#endregion
|
|
9228
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9576
|
+
//#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
|
|
9229
9577
|
var import_dist = require_dist();
|
|
9230
9578
|
function getStyledClassName(namespace) {
|
|
9231
9579
|
return `components-${(0, import_dist.paramCase)(namespace)}`;
|
|
9232
9580
|
}
|
|
9233
9581
|
var getStyledClassNameFromKey = memize(getStyledClassName);
|
|
9234
9582
|
//#endregion
|
|
9235
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9583
|
+
//#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
|
|
9236
9584
|
function contextConnect(Component, namespace) {
|
|
9237
9585
|
return _contextConnect(Component, namespace, { forwardsRef: true });
|
|
9238
9586
|
}
|
|
@@ -9249,7 +9597,7 @@ function _contextConnect(Component, namespace, options) {
|
|
|
9249
9597
|
});
|
|
9250
9598
|
}
|
|
9251
9599
|
//#endregion
|
|
9252
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9600
|
+
//#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
|
|
9253
9601
|
function getNamespace(componentName) {
|
|
9254
9602
|
return { [COMPONENT_NAMESPACE]: componentName };
|
|
9255
9603
|
}
|
|
@@ -9257,7 +9605,7 @@ function getConnectedNamespace() {
|
|
|
9257
9605
|
return { [CONNECTED_NAMESPACE]: true };
|
|
9258
9606
|
}
|
|
9259
9607
|
//#endregion
|
|
9260
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9608
|
+
//#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
|
|
9261
9609
|
function useContextSystem(props, namespace) {
|
|
9262
9610
|
const contextSystemProps = useComponentsContext();
|
|
9263
9611
|
if (typeof namespace === "undefined") globalThis.SCRIPT_DEBUG === true && warning("useContextSystem: Please provide a namespace");
|
|
@@ -9277,7 +9625,7 @@ function useContextSystem(props, namespace) {
|
|
|
9277
9625
|
return finalComponentProps;
|
|
9278
9626
|
}
|
|
9279
9627
|
//#endregion
|
|
9280
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9628
|
+
//#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
|
|
9281
9629
|
var visuallyHidden = {
|
|
9282
9630
|
border: 0,
|
|
9283
9631
|
clip: "rect(1px, 1px, 1px, 1px)",
|
|
@@ -9293,7 +9641,7 @@ var visuallyHidden = {
|
|
|
9293
9641
|
wordBreak: "normal"
|
|
9294
9642
|
};
|
|
9295
9643
|
//#endregion
|
|
9296
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9644
|
+
//#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
|
|
9297
9645
|
var customAttributeRegExp = /^(data|aria|x)-/i;
|
|
9298
9646
|
var eventHandlerRegExp = /^on[A-Z]/;
|
|
9299
9647
|
var svgElementNames = new Set(`animate animateMotion animateTransform circle clipPath defs desc ellipse
|
|
@@ -9383,7 +9731,7 @@ function UnforwardedPolymorphicElement({ as, ...props }, ref) {
|
|
|
9383
9731
|
}
|
|
9384
9732
|
var PolymorphicElement = (0, react.forwardRef)(UnforwardedPolymorphicElement);
|
|
9385
9733
|
//#endregion
|
|
9386
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9734
|
+
//#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
|
|
9387
9735
|
function UnforwardedView({ css, ...restProps }, ref) {
|
|
9388
9736
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PolymorphicElement, {
|
|
9389
9737
|
ref,
|
|
@@ -9392,7 +9740,7 @@ function UnforwardedView({ css, ...restProps }, ref) {
|
|
|
9392
9740
|
}
|
|
9393
9741
|
var component_default$2 = Object.assign((0, react.forwardRef)(UnforwardedView), { selector: ".components-view" });
|
|
9394
9742
|
//#endregion
|
|
9395
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9743
|
+
//#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
|
|
9396
9744
|
function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
9397
9745
|
const { style: styleProp, ...contextProps } = useContextSystem(props, "VisuallyHidden");
|
|
9398
9746
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
@@ -9407,7 +9755,7 @@ function UnconnectedVisuallyHidden(props, forwardedRef) {
|
|
|
9407
9755
|
}
|
|
9408
9756
|
var component_default$1 = contextConnect(UnconnectedVisuallyHidden, "VisuallyHidden");
|
|
9409
9757
|
//#endregion
|
|
9410
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9758
|
+
//#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
|
|
9411
9759
|
var breakpoints = [
|
|
9412
9760
|
"40em",
|
|
9413
9761
|
"52em",
|
|
@@ -9441,7 +9789,7 @@ function useResponsiveValue(values, options = {}) {
|
|
|
9441
9789
|
return array[index >= array.length ? array.length - 1 : index];
|
|
9442
9790
|
}
|
|
9443
9791
|
//#endregion
|
|
9444
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9792
|
+
//#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
|
|
9445
9793
|
var ALIGNMENTS = {
|
|
9446
9794
|
bottom: {
|
|
9447
9795
|
alignItems: "flex-end",
|
|
@@ -9489,7 +9837,7 @@ function getAlignmentProps(alignment) {
|
|
|
9489
9837
|
return alignment ? ALIGNMENTS[alignment] : {};
|
|
9490
9838
|
}
|
|
9491
9839
|
//#endregion
|
|
9492
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9840
|
+
//#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
|
|
9493
9841
|
function useGrid(props) {
|
|
9494
9842
|
const { align, alignment, className, columnGap, columns = 2, gap = 3, isInline = false, justify, rowGap, rows, templateColumns, templateRows, ...otherProps } = useContextSystem(props, "Grid");
|
|
9495
9843
|
const column = useResponsiveValue(Array.isArray(columns) ? columns : [columns]);
|
|
@@ -9531,7 +9879,7 @@ function useGrid(props) {
|
|
|
9531
9879
|
};
|
|
9532
9880
|
}
|
|
9533
9881
|
//#endregion
|
|
9534
|
-
//#region ../../../node_modules/.pnpm/@wordpress+components@40.0.0_@types+react-dom@18.3.7_@types+react@
|
|
9882
|
+
//#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
|
|
9535
9883
|
function UnconnectedGrid(props, forwardedRef) {
|
|
9536
9884
|
const gridProps = useGrid(props);
|
|
9537
9885
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(component_default$2, {
|
|
@@ -10833,6 +11181,7 @@ exports.parseHslString = parseHslString;
|
|
|
10833
11181
|
exports.prefersLightText = prefersLightText;
|
|
10834
11182
|
exports.relativeLuminance = relativeLuminance;
|
|
10835
11183
|
exports.resolveCssVariable = resolveCssVariable;
|
|
11184
|
+
exports.useCalendarHeatmapData = useCalendarHeatmapData;
|
|
10836
11185
|
exports.useChartFormatting = useChartFormatting;
|
|
10837
11186
|
exports.useChartLegendItems = useChartLegendItems;
|
|
10838
11187
|
exports.useChartRegistration = useChartRegistration;
|