@sproutsocial/seeds-react-data-viz 0.14.0 → 0.16.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.
@@ -0,0 +1,796 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+ var _chunkEEVKTTT3js = require('./chunk-EEVKTTT3.js');
14
+
15
+ // src/charts/shared/chartBase.tsx
16
+ var _highcharts = require('highcharts'); var _highcharts2 = _interopRequireDefault(_highcharts);
17
+ var _highchartsreactofficial = require('highcharts-react-official');
18
+ var _accessibility = require('highcharts/modules/accessibility'); var _accessibility2 = _interopRequireDefault(_accessibility);
19
+ var _annotations = require('highcharts/modules/annotations'); var _annotations2 = _interopRequireDefault(_annotations);
20
+ var _exporting = require('highcharts/modules/exporting'); var _exporting2 = _interopRequireDefault(_exporting);
21
+ var _offlineexporting = require('highcharts/modules/offline-exporting'); var _offlineexporting2 = _interopRequireDefault(_offlineexporting);
22
+ var _exportdata = require('highcharts/modules/export-data'); var _exportdata2 = _interopRequireDefault(_exportdata);
23
+
24
+
25
+
26
+
27
+
28
+
29
+ var _react = require('react');
30
+ var _styledcomponents = require('styled-components');
31
+ var _seedsreactbox = require('@sproutsocial/seeds-react-box');
32
+
33
+ // src/charts/shared/ChartAnnotationMarkerPortal.tsx
34
+
35
+ var _reactdom = require('react-dom');
36
+
37
+ var _seedsreacticon = require('@sproutsocial/seeds-react-icon');
38
+ var _jsxruntime = require('react/jsx-runtime');
39
+ function ChartAnnotationMarker({
40
+ annotation,
41
+ lineHeight
42
+ }) {
43
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _seedsreactbox.Box, { display: "flex", flexDirection: "column", alignItems: "center", gap: 200, children: [
44
+ annotation.icon ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
45
+ _seedsreactbox.Box,
46
+ {
47
+ display: "flex",
48
+ alignItems: "center",
49
+ justifyContent: "center",
50
+ width: "20px",
51
+ height: "20px",
52
+ bg: "icon.base",
53
+ borderRadius: "50%",
54
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacticon.Icon, { name: annotation.icon, size: "mini", color: "icon.inverse" })
55
+ }
56
+ ) : null,
57
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
58
+ _seedsreactbox.Box,
59
+ {
60
+ height: `${lineHeight}px`,
61
+ width: "0.5px",
62
+ bg: _nullishCoalesce(annotation.color, () => ( "neutral.200"))
63
+ }
64
+ )
65
+ ] });
66
+ }
67
+ var MARKER_ATTR = "data-v2-chart-annotation-marker";
68
+ var ChartAnnotationMarkerPortal = _react.memo.call(void 0,
69
+ function ChartAnnotationMarkerPortal2({
70
+ annotationLookup,
71
+ annotationContext,
72
+ chartContainer,
73
+ plotHeight
74
+ }) {
75
+ const annotationContainers = _react.useRef.call(void 0, {});
76
+ const [, setRenderCount] = _react.useState.call(void 0, 0);
77
+ const forceRender = () => setRenderCount((prev) => prev + 1);
78
+ _react.useEffect.call(void 0, () => {
79
+ if (!annotationContext.labels) return;
80
+ const newContainers = {};
81
+ const existingAnnotationContainers = chartContainer.querySelectorAll(
82
+ `div[${MARKER_ATTR}='true']`
83
+ );
84
+ existingAnnotationContainers.forEach(
85
+ (annotation) => annotation.setAttribute(MARKER_ATTR, "false")
86
+ );
87
+ annotationContext.labels.forEach((label) => {
88
+ const labelElement = _optionalChain([label, 'access', _ => _.graphic, 'optionalAccess', _2 => _2.div]);
89
+ if (!labelElement) return;
90
+ let annotationDiv = labelElement.querySelector(
91
+ `div[${MARKER_ATTR}]`
92
+ );
93
+ if (!annotationDiv) {
94
+ annotationDiv = document.createElement("div");
95
+ labelElement.appendChild(annotationDiv);
96
+ }
97
+ annotationDiv.setAttribute(MARKER_ATTR, "true");
98
+ const xValue = _optionalChain([label, 'access', _3 => _3.options, 'optionalAccess', _4 => _4.point, 'optionalAccess', _5 => _5.x]);
99
+ newContainers[xValue] = annotationDiv;
100
+ });
101
+ annotationContainers.current = newContainers;
102
+ forceRender();
103
+ requestAnimationFrame(() => {
104
+ chartContainer.querySelectorAll("div.highcharts-annotation").forEach((annotationDiv) => {
105
+ const reactAnnotations = annotationDiv.querySelectorAll(
106
+ `div[${MARKER_ATTR}]`
107
+ );
108
+ const hasActiveAnnotations = Array.from(reactAnnotations).some(
109
+ (div) => div.getAttribute(MARKER_ATTR) === "true"
110
+ );
111
+ if (!hasActiveAnnotations) annotationDiv.remove();
112
+ });
113
+ });
114
+ }, [annotationContext.labels, annotationLookup, chartContainer]);
115
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _jsxruntime.Fragment, { children: Object.entries(annotationContainers.current).map(
116
+ ([xValue, container]) => {
117
+ const annotation = annotationLookup.get(Number(xValue));
118
+ return annotation ? _reactdom.createPortal.call(void 0,
119
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
120
+ ChartAnnotationMarker,
121
+ {
122
+ annotation,
123
+ lineHeight: plotHeight
124
+ }
125
+ ),
126
+ container
127
+ ) : null;
128
+ }
129
+ ) });
130
+ }
131
+ );
132
+
133
+ // src/charts/shared/DefaultChartTooltip.tsx
134
+
135
+
136
+ var _seedsreacttext = require('@sproutsocial/seeds-react-text');
137
+
138
+ // src/charts/shared/formatters/valueFormatter.ts
139
+ var _seedsreactduration = require('@sproutsocial/seeds-react-duration');
140
+ var _seedsreactnumeral = require('@sproutsocial/seeds-react-numeral');
141
+ function valueFormatter({
142
+ value,
143
+ numberFormat = "decimal",
144
+ currency = "USD",
145
+ abbreviate = true,
146
+ percentInput = "decimal",
147
+ numberLocale,
148
+ textLocale
149
+ }) {
150
+ const numberValue = Number(value);
151
+ if (numberValue === 0) {
152
+ return _seedsreactnumeral.formatNumeral.call(void 0, { locale: numberLocale, number: 0 });
153
+ }
154
+ if (numberFormat === "duration") {
155
+ return _seedsreactduration.formatDuration.call(void 0, {
156
+ display: "narrow",
157
+ locale: textLocale,
158
+ milliseconds: numberValue
159
+ });
160
+ }
161
+ if (numberFormat === "percent") {
162
+ const whole = percentInput === "decimal" ? numberValue * 100 : numberValue;
163
+ return _seedsreactnumeral.formatNumeral.call(void 0, {
164
+ format: "percent",
165
+ locale: numberLocale,
166
+ number: whole
167
+ });
168
+ }
169
+ return _seedsreactnumeral.formatNumeral.call(void 0, {
170
+ abbreviate,
171
+ currency,
172
+ format: numberFormat,
173
+ locale: numberLocale,
174
+ number: numberValue
175
+ });
176
+ }
177
+
178
+ // src/charts/shared/DefaultChartTooltip.tsx
179
+
180
+ function formatTitle(position, timezone) {
181
+ if (typeof position === "string") return position;
182
+ return new Date(position).toLocaleDateString(void 0, {
183
+ year: "numeric",
184
+ month: "long",
185
+ day: "numeric",
186
+ weekday: "long",
187
+ timeZone: timezone
188
+ });
189
+ }
190
+ function AnnotationHeader({
191
+ icon,
192
+ title,
193
+ description
194
+ }) {
195
+ const hasIconOrTitle = Boolean(icon || title);
196
+ if (!hasIconOrTitle && !description) return null;
197
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
198
+ hasIconOrTitle ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.ChartTooltipHeader, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _seedsreactbox.Box, { display: "flex", alignItems: "center", gap: 300, children: [
199
+ icon ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacticon.Icon, { name: icon, size: "mini", color: "icon.base" }) : null,
200
+ title ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacttext.Text, { color: "text.body", fontSize: 200, children: title }) : null
201
+ ] }) }) : null,
202
+ description ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.ChartTooltipHeader, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacttext.Text, { fontSize: 200, color: "text.subtext", children: description }) }) : null
203
+ ] });
204
+ }
205
+ function DefaultChartTooltip({
206
+ data,
207
+ position,
208
+ annotation,
209
+ hasOnClick,
210
+ tooltipClickLabel,
211
+ timezone,
212
+ invalidNumberLabel,
213
+ valueFormat
214
+ }) {
215
+ const rows = data.map((d) => ({
216
+ cells: [
217
+ {
218
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.ChartLegendLabel, { color: d.color, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacttext.Text, { "aria-label": `${d.name}: `, children: d.name }) })
219
+ },
220
+ {
221
+ // Format non-null values through the shared formatter when a
222
+ // `valueFormat` is supplied. Tooltip values are always full precision
223
+ // (`abbreviate: false`) — the axis tick scan never applies here (v1
224
+ // parity: the bar tooltip always passed `abbreviate={false}`).
225
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacttext.Text, { children: d.value == null ? _nullishCoalesce(invalidNumberLabel, () => ( "\u2014")) : valueFormat ? valueFormatter({
226
+ ...valueFormat,
227
+ value: d.value,
228
+ abbreviate: false
229
+ }) : d.value }),
230
+ align: "right"
231
+ }
232
+ ]
233
+ }));
234
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkEEVKTTT3js.ChartTooltip, { children: [
235
+ annotation ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
236
+ AnnotationHeader,
237
+ {
238
+ icon: annotation.icon,
239
+ title: annotation.title,
240
+ description: annotation.description
241
+ }
242
+ ) : null,
243
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.ChartTooltipTitle, { children: formatTitle(position, timezone) }),
244
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.ChartTooltipTable, { rows }),
245
+ hasOnClick && tooltipClickLabel ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.ChartTooltipFooter, { children: typeof tooltipClickLabel === "string" ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _seedsreactbox.Box, { display: "flex", alignItems: "center", gap: 300, children: [
246
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacticon.Icon, { name: "hand-pointer-clicking-outline", color: "icon.base" }),
247
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacttext.Text, { color: "text.subtext", fontSize: 200, children: tooltipClickLabel })
248
+ ] }) : tooltipClickLabel }) : null
249
+ ] });
250
+ }
251
+
252
+ // src/charts/shared/SeriesLegend.tsx
253
+
254
+
255
+
256
+ var SeriesLegend = _react.memo.call(void 0, function SeriesLegend2({
257
+ items
258
+ }) {
259
+ const labels = items.map((item) => ({
260
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
261
+ _chunkEEVKTTT3js.ChartLegendLabelContentWithIcon,
262
+ {
263
+ icon: item.icon ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreacticon.Icon, { name: item.icon, fixedWidth: true, "aria-hidden": true }) : void 0,
264
+ children: item.name
265
+ }
266
+ ),
267
+ color: item.color
268
+ }));
269
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.ChartLegend, { legendLabels: labels });
270
+ });
271
+
272
+ // src/charts/shared/chartExport.ts
273
+ function defaultFilename(type, now) {
274
+ const iso = now.toISOString();
275
+ const stamp = `${iso.slice(0, 10)}-${iso.slice(11, 19).replace(/:/g, "-")}`;
276
+ return slugify(type ? `chart-${type}-${stamp}` : `chart-${stamp}`);
277
+ }
278
+ function slugify(value) {
279
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
280
+ }
281
+
282
+ // src/charts/shared/chartBase.tsx
283
+
284
+ _accessibility2.default.call(void 0, _highcharts2.default);
285
+ _annotations2.default.call(void 0, _highcharts2.default);
286
+ _exporting2.default.call(void 0, _highcharts2.default);
287
+ _offlineexporting2.default.call(void 0, _highcharts2.default);
288
+ _exportdata2.default.call(void 0, _highcharts2.default);
289
+ function useSeedsChartSetup({
290
+ series,
291
+ includePatterns = false,
292
+ seriesLimit,
293
+ isSeriesLimitOverridden = false,
294
+ hideSeriesLimitWarning = false,
295
+ componentName
296
+ }) {
297
+ const theme = _styledcomponents.useTheme.call(void 0, );
298
+ const palette = theme.colors.DATAVIZ_COLORS_LIST;
299
+ const cappedSeries = _react.useMemo.call(void 0,
300
+ () => seriesLimit !== void 0 && seriesLimit >= 1 && series.length > seriesLimit ? series.slice(0, seriesLimit) : series,
301
+ [series, seriesLimit]
302
+ );
303
+ _react.useEffect.call(void 0, () => {
304
+ if (seriesLimit !== void 0 && seriesLimit >= 1 && series.length > seriesLimit && !isSeriesLimitOverridden && !hideSeriesLimitWarning && componentName != null) {
305
+ console.warn(
306
+ `${componentName}: Maximum number of series (${seriesLimit}) exceeded. Only the first ${seriesLimit} series will be displayed.`
307
+ );
308
+ }
309
+ }, [
310
+ series.length,
311
+ seriesLimit,
312
+ isSeriesLimitOverridden,
313
+ hideSeriesLimitWarning,
314
+ componentName
315
+ ]);
316
+ const colors = _react.useMemo.call(void 0, () => {
317
+ const out = [];
318
+ const paletteLen = palette.length;
319
+ for (let i = 0; i < cappedSeries.length; i++) {
320
+ const s = cappedSeries[i];
321
+ out.push(_nullishCoalesce(_nullishCoalesce(s.color, () => ( palette[i % paletteLen])), () => ( "")));
322
+ }
323
+ return out;
324
+ }, [cappedSeries, palette]);
325
+ const patterns = _react.useMemo.call(void 0, () => {
326
+ if (!includePatterns) return [];
327
+ const out = [];
328
+ for (let i = 0; i < cappedSeries.length; i++) {
329
+ const s = cappedSeries[i];
330
+ out.push(_nullishCoalesce(s.pattern, () => ( "solid")));
331
+ }
332
+ return out;
333
+ }, [cappedSeries, includePatterns]);
334
+ return { theme, colors, patterns, series: cappedSeries };
335
+ }
336
+ function buildExportChartOptions(theme, colors) {
337
+ const axisOptions = {
338
+ lineColor: theme.colors.container.border.base,
339
+ gridLineColor: theme.colors.container.border.base,
340
+ labels: {
341
+ style: {
342
+ color: theme.colors.text.subtext,
343
+ fontFamily: theme.fontFamily,
344
+ fontSize: theme.typography[100].fontSize,
345
+ fontWeight: String(theme.fontWeights.normal)
346
+ }
347
+ }
348
+ };
349
+ return {
350
+ chart: {
351
+ styledMode: false,
352
+ backgroundColor: theme.colors.container.background.base
353
+ },
354
+ // Series without an explicit `color` fall through to this palette by index.
355
+ colors: [...colors],
356
+ // The on-screen legend is a React sibling (`SeriesLegend`) outside the chart
357
+ // SVG, so the export can't capture it. Turn on Highcharts' native legend for
358
+ // the clone instead, themed to approximate the Seeds `ChartLegend` (centered
359
+ // row of swatch + `text.subtext` label). It can't reproduce per-series Seeds
360
+ // icons — those series show colour + name only.
361
+ legend: {
362
+ enabled: true,
363
+ symbolRadius: 4,
364
+ symbolHeight: 12,
365
+ symbolWidth: 12,
366
+ itemStyle: {
367
+ color: theme.colors.text.subtext,
368
+ fontFamily: theme.fontFamily,
369
+ fontSize: theme.typography[200].fontSize,
370
+ fontWeight: String(theme.fontWeights.normal)
371
+ }
372
+ },
373
+ xAxis: {
374
+ ...axisOptions,
375
+ crosshair: {
376
+ color: theme.colors.container.border.decorative.neutral,
377
+ width: 1
378
+ }
379
+ },
380
+ // No zero-line: the `y-axis-zero-line` rule in chartStyles is a v1 leftover;
381
+ // the v2 bar adapter never creates that plotLine.
382
+ yAxis: axisOptions
383
+ };
384
+ }
385
+ function createChartExportHandle(chart, getExportChartOptions) {
386
+ const resolveName = (filename) => _nullishCoalesce(filename, () => ( defaultFilename(_optionalChain([chart, 'access', _6 => _6.options, 'access', _7 => _7.chart, 'optionalAccess', _8 => _8.type]), /* @__PURE__ */ new Date())));
387
+ const exportImage = async (type, filename) => {
388
+ chart.exportChartLocal(
389
+ { type, filename: resolveName(filename) },
390
+ getExportChartOptions()
391
+ );
392
+ };
393
+ return {
394
+ exportPNG: ({ filename } = {}) => exportImage("image/png", filename),
395
+ exportSVG: ({ filename } = {}) => exportImage("image/svg+xml", filename),
396
+ exportPDF: async ({ filename } = {}) => {
397
+ const { loadPdfExportLibs } = await Promise.resolve().then(() => _interopRequireWildcard(require("./pdfExportLibs-BZR2D3RA.js")));
398
+ loadPdfExportLibs();
399
+ await exportImage("application/pdf", filename);
400
+ },
401
+ exportCSV: async ({ filename } = {}) => {
402
+ const exporting = chart.options.exporting ??= {};
403
+ const previous = exporting.filename;
404
+ exporting.filename = resolveName(filename);
405
+ try {
406
+ chart.downloadCSV();
407
+ } finally {
408
+ exporting.filename = previous;
409
+ }
410
+ }
411
+ };
412
+ }
413
+ function ChartRenderer({
414
+ options,
415
+ series,
416
+ colors,
417
+ tooltip,
418
+ annotationLookup,
419
+ hasOnClick,
420
+ tooltipClickLabel,
421
+ timezone,
422
+ invalidNumberLabel,
423
+ valueFormat,
424
+ onReady
425
+ }) {
426
+ const [chart, setChart] = _react.useState.call(void 0, null);
427
+ const [plotHeight, setPlotHeight] = _react.useState.call(void 0, 0);
428
+ const renderTooltip = _nullishCoalesce(tooltip, () => ( DefaultChartTooltip));
429
+ const theme = _styledcomponents.useTheme.call(void 0, );
430
+ const exportThemeRef = _react.useRef.call(void 0, { theme, colors });
431
+ exportThemeRef.current = { theme, colors };
432
+ const captureChart = _react.useCallback.call(void 0, (chartInstance) => {
433
+ const forExport = _optionalChain([chartInstance, 'access', _9 => _9.options, 'access', _10 => _10.chart, 'optionalAccess', _11 => _11.forExport]);
434
+ if (!forExport) {
435
+ setChart(chartInstance);
436
+ setPlotHeight(chartInstance.plotHeight);
437
+ }
438
+ }, []);
439
+ const onReadyRef = _react.useRef.call(void 0, onReady);
440
+ onReadyRef.current = onReady;
441
+ _react.useEffect.call(void 0, () => {
442
+ if (!chart) return;
443
+ _optionalChain([onReadyRef, 'access', _12 => _12.current, 'optionalCall', _13 => _13(
444
+ createChartExportHandle(
445
+ chart,
446
+ () => buildExportChartOptions(
447
+ exportThemeRef.current.theme,
448
+ exportThemeRef.current.colors
449
+ )
450
+ )
451
+ )]);
452
+ }, [chart]);
453
+ _react.useEffect.call(void 0, () => {
454
+ if (!chart) return;
455
+ setPlotHeight(chart.plotHeight);
456
+ const unbind = _highcharts2.default.addEvent(chart, "redraw", () => {
457
+ setPlotHeight(chart.plotHeight);
458
+ });
459
+ return () => unbind();
460
+ }, [chart]);
461
+ const highchartsOptions = _react.useMemo.call(void 0,
462
+ () => ({
463
+ ...options,
464
+ // useHTML is load-bearing: the tooltip portal's target div only mounts
465
+ // when the label renders as HTML, not SVG (see `charts/README.md`).
466
+ tooltip: { ...options.tooltip, useHTML: true },
467
+ // Client-side/offline export only; native context button hidden (export
468
+ // is exposed via the `onReady` handle).
469
+ exporting: {
470
+ fallbackToExportServer: false,
471
+ buttons: { contextButton: { enabled: false } }
472
+ }
473
+ }),
474
+ [options]
475
+ );
476
+ if (series.length === 0) return null;
477
+ const chartWithAnnotations = chart;
478
+ const hasRenderedAnnotations = !!_optionalChain([chartWithAnnotations, 'optionalAccess', _14 => _14.annotations, 'optionalAccess', _15 => _15.length]) && !!_optionalChain([annotationLookup, 'optionalAccess', _16 => _16.size]) && plotHeight > 0;
479
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
480
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkEEVKTTT3js.GlobalChartStyleOverrides, {}),
481
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
482
+ _highchartsreactofficial.HighchartsReact,
483
+ {
484
+ highcharts: _highcharts2.default,
485
+ options: highchartsOptions,
486
+ callback: captureChart
487
+ }
488
+ ),
489
+ hasRenderedAnnotations ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
490
+ ChartAnnotationMarkerPortal,
491
+ {
492
+ annotationLookup,
493
+ annotationContext: chartWithAnnotations.annotations[0],
494
+ chartContainer: chartWithAnnotations.container,
495
+ plotHeight
496
+ }
497
+ ) : null,
498
+ chart ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
499
+ _chunkEEVKTTT3js.ChartTooltipPortal,
500
+ {
501
+ chart,
502
+ renderContent: (context) => {
503
+ const data = _chunkEEVKTTT3js.transformTimeSeriesTooltipData.call(void 0, {
504
+ context,
505
+ data: series.map((s, i) => ({
506
+ name: s.name,
507
+ points: [],
508
+ styles: { color: _nullishCoalesce(_nullishCoalesce(s.color, () => ( colors[i])), () => ( "")) }
509
+ }))
510
+ }).map((row) => ({
511
+ color: row.color,
512
+ name: row.name,
513
+ value: row.value
514
+ }));
515
+ const position = context.x;
516
+ const resolved = _optionalChain([annotationLookup, 'optionalAccess', _17 => _17.get, 'call', _18 => _18(context.point.x)]);
517
+ const annotation = resolved ? {
518
+ icon: resolved.icon,
519
+ color: resolved.color,
520
+ title: resolved.title,
521
+ description: resolved.description
522
+ } : void 0;
523
+ return renderTooltip({
524
+ data,
525
+ position,
526
+ annotation,
527
+ hasOnClick,
528
+ tooltipClickLabel,
529
+ timezone,
530
+ invalidNumberLabel,
531
+ valueFormat
532
+ });
533
+ }
534
+ }
535
+ ) : null,
536
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _seedsreactbox.Box, { mt: 350, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
537
+ SeriesLegend,
538
+ {
539
+ items: series.map((s, i) => ({
540
+ name: s.name,
541
+ icon: s.icon,
542
+ color: _nullishCoalesce(_nullishCoalesce(s.color, () => ( colors[i])), () => ( ""))
543
+ }))
544
+ }
545
+ ) })
546
+ ] });
547
+ }
548
+
549
+ // src/charts/shared/annotations.ts
550
+ function buildAnnotationConfig(annotations) {
551
+ if (!_optionalChain([annotations, 'optionalAccess', _19 => _19.length])) {
552
+ return { annotations: void 0, lookup: void 0 };
553
+ }
554
+ const labels = [];
555
+ const lookup = /* @__PURE__ */ new Map();
556
+ for (const annotation of annotations) {
557
+ const { position } = annotation;
558
+ labels.push({
559
+ // Highcharts anchor — always uses `x` regardless of chart orientation.
560
+ point: { x: position, y: 0, xAxis: 0, yAxis: 0 },
561
+ // Space (not empty) — Highcharts reverts to its built-in label text on empty string.
562
+ text: " "
563
+ });
564
+ lookup.set(position, annotation);
565
+ }
566
+ if (labels.length === 0) {
567
+ return { annotations: void 0, lookup: void 0 };
568
+ }
569
+ return {
570
+ // `useHTML: true` makes Highcharts attach an HTML `graphic.div` to each
571
+ // label, which the marker portal needs as its render target. `padding: 0`
572
+ // removes Highcharts' default left padding so markers stay centered.
573
+ annotations: [{ labels, labelOptions: { useHTML: true, padding: 0 } }],
574
+ lookup
575
+ };
576
+ }
577
+
578
+ // src/charts/shared/baseChartOptions.ts
579
+ function buildBaseChartOptions({
580
+ type,
581
+ description,
582
+ valueSuffix,
583
+ reserveTopMargin = false,
584
+ timezone
585
+ }) {
586
+ return {
587
+ chart: {
588
+ type,
589
+ styledMode: true,
590
+ animation: false,
591
+ ...reserveTopMargin ? { marginTop: 24 } : {}
592
+ },
593
+ accessibility: { description },
594
+ title: { text: "" },
595
+ credits: { enabled: false },
596
+ legend: { enabled: false },
597
+ tooltip: {
598
+ enabled: true,
599
+ outside: true,
600
+ padding: 0,
601
+ shape: "rect",
602
+ shared: true,
603
+ hideDelay: 0,
604
+ valueSuffix
605
+ },
606
+ // Chart-global in Highcharts; only meaningful for datetime axes, so it's
607
+ // present only when a timezone was resolved (omitted for category axes).
608
+ ...timezone ? { time: { timezone } } : {}
609
+ };
610
+ }
611
+
612
+ // src/charts/shared/formatters/datetimeFormatter.ts
613
+ var DAY_MS = 864e5;
614
+ var WEEK_MS = 6048e5;
615
+ var MIN_MONTH_MS = 24192e5;
616
+ var MIN_YEAR_MS = 31536e6;
617
+ var getDatePartsInTimezone = (date, timezone) => {
618
+ const formatter = new Intl.DateTimeFormat("en-US", {
619
+ year: "numeric",
620
+ month: "numeric",
621
+ day: "numeric",
622
+ timeZone: timezone
623
+ });
624
+ const parts = formatter.formatToParts(date);
625
+ return {
626
+ day: parseInt(_nullishCoalesce(_optionalChain([parts, 'access', _20 => _20.find, 'call', _21 => _21((p) => p.type === "day"), 'optionalAccess', _22 => _22.value]), () => ( "0")), 10),
627
+ month: parseInt(_nullishCoalesce(_optionalChain([parts, 'access', _23 => _23.find, 'call', _24 => _24((p) => p.type === "month"), 'optionalAccess', _25 => _25.value]), () => ( "0")), 10),
628
+ year: parseInt(_nullishCoalesce(_optionalChain([parts, 'access', _26 => _26.find, 'call', _27 => _27((p) => p.type === "year"), 'optionalAccess', _28 => _28.value]), () => ( "0")), 10)
629
+ };
630
+ };
631
+ var deriveGranularity = (tickPositions) => {
632
+ if (tickPositions.length < 2) {
633
+ return "day";
634
+ }
635
+ const deltas = [];
636
+ for (let i = 1; i < tickPositions.length; i++) {
637
+ const curr = tickPositions[i];
638
+ const prev = tickPositions[i - 1];
639
+ if (curr === void 0 || prev === void 0) {
640
+ continue;
641
+ }
642
+ deltas.push(Math.abs(curr - prev));
643
+ }
644
+ deltas.sort((a, b) => a - b);
645
+ const mid = Math.floor(deltas.length / 2);
646
+ const upper = deltas[mid];
647
+ const lower = deltas[mid - 1];
648
+ const median = deltas.length % 2 === 0 && lower !== void 0 ? (lower + upper) / 2 : upper;
649
+ if (median < DAY_MS) {
650
+ return "hour";
651
+ }
652
+ if (median < WEEK_MS) {
653
+ return "day";
654
+ }
655
+ if (median < MIN_MONTH_MS) {
656
+ return "week";
657
+ }
658
+ if (median < MIN_YEAR_MS) {
659
+ return "month";
660
+ }
661
+ return "year";
662
+ };
663
+ function datetimeFormatter({
664
+ value,
665
+ tickPositions = [],
666
+ // optional
667
+ timezone = "UTC",
668
+ timeFormat = "12",
669
+ textLocale = "en-US"
670
+ }) {
671
+ if (typeof value === "string" || !Number.isFinite(value)) {
672
+ return { primary: String(value) };
673
+ }
674
+ const granularity = deriveGranularity(tickPositions);
675
+ const tickIndex = tickPositions.indexOf(value);
676
+ const isFirst = tickIndex === 0;
677
+ const previousValue = tickPositions[tickIndex - 1];
678
+ const valueDate = new Date(value);
679
+ const valueParts = getDatePartsInTimezone(valueDate, timezone);
680
+ const previousValueDate = previousValue ? new Date(previousValue) : void 0;
681
+ const previousValueParts = previousValueDate ? getDatePartsInTimezone(previousValueDate, timezone) : void 0;
682
+ let firstPartOptions = {};
683
+ let secondPartOptions = {};
684
+ switch (granularity) {
685
+ case "hour":
686
+ firstPartOptions = timeFormat === "24" ? { hour: "numeric", minute: "numeric", hour12: false } : { hour: "numeric" };
687
+ if (isFirst || valueParts.day !== _optionalChain([previousValueParts, 'optionalAccess', _29 => _29.day])) {
688
+ secondPartOptions = { day: "numeric", month: "short" };
689
+ }
690
+ break;
691
+ case "day":
692
+ case "week":
693
+ firstPartOptions = { day: "numeric" };
694
+ if (isFirst || valueParts.month !== _optionalChain([previousValueParts, 'optionalAccess', _30 => _30.month])) {
695
+ secondPartOptions = { month: "short" };
696
+ }
697
+ break;
698
+ case "month":
699
+ firstPartOptions = { month: "short" };
700
+ if (isFirst || valueParts.year !== _optionalChain([previousValueParts, 'optionalAccess', _31 => _31.year])) {
701
+ secondPartOptions = { year: "numeric" };
702
+ }
703
+ break;
704
+ case "year":
705
+ firstPartOptions = { year: "numeric" };
706
+ break;
707
+ default:
708
+ firstPartOptions = {};
709
+ break;
710
+ }
711
+ const primary = new Intl.DateTimeFormat(textLocale, {
712
+ ...firstPartOptions,
713
+ timeZone: timezone
714
+ }).format(valueDate);
715
+ if (Object.keys(secondPartOptions).length > 0) {
716
+ const secondary = new Intl.DateTimeFormat(textLocale, {
717
+ ...secondPartOptions,
718
+ timeZone: timezone
719
+ }).format(valueDate);
720
+ return { primary, secondary };
721
+ }
722
+ return { primary };
723
+ }
724
+
725
+ // src/charts/shared/axisOptions.ts
726
+ function makeDatetimeAxisLabelFormatter(timezone, timeFormat) {
727
+ return function() {
728
+ const { primary, secondary } = datetimeFormatter({
729
+ value: this.value,
730
+ tickPositions: _nullishCoalesce(this.axis.tickPositions, () => ( [])),
731
+ timezone,
732
+ timeFormat
733
+ });
734
+ return secondary ? `${primary}<br/><span class="hc-axis-label-secondary">${secondary}</span>` : primary;
735
+ };
736
+ }
737
+ function buildDimensionalAxis(axis, timezone) {
738
+ if (axis.type === "datetime") {
739
+ return {
740
+ type: "datetime",
741
+ crosshair: axis.crosshair,
742
+ labels: {
743
+ formatter: makeDatetimeAxisLabelFormatter(timezone, axis.timeFormat)
744
+ }
745
+ };
746
+ }
747
+ return {
748
+ type: "category",
749
+ categories: [...axis.categories],
750
+ crosshair: axis.crosshair
751
+ };
752
+ }
753
+ function resolveTooltipTimezone(axis, timezone) {
754
+ return axis.type === "datetime" ? _nullishCoalesce(timezone, () => ( "UTC")) : void 0;
755
+ }
756
+
757
+ // src/charts/shared/valueAxisLabelFormatter.ts
758
+
759
+ var FIXED_LOCALE = "en-US";
760
+ function deriveAbbreviateFromTicks(context) {
761
+ const tickPositions = context.axis.tickPositions;
762
+ const maxValue = tickPositions && tickPositions.length > 0 ? tickPositions[tickPositions.length - 1] : void 0;
763
+ return typeof maxValue === "number" && maxValue > 9999 ? 1e3 : true;
764
+ }
765
+ function defaultValueAxisLabelFormatter() {
766
+ const numberValue = Number(this.value);
767
+ if (numberValue === 0) {
768
+ return _seedsreactnumeral.formatNumeral.call(void 0, { locale: FIXED_LOCALE, number: 0 });
769
+ }
770
+ const abbreviate = deriveAbbreviateFromTicks(this);
771
+ return _seedsreactnumeral.formatNumeral.call(void 0, {
772
+ abbreviate,
773
+ format: "decimal",
774
+ locale: FIXED_LOCALE,
775
+ number: numberValue
776
+ });
777
+ }
778
+ function makeValueAxisLabelFormatter(format) {
779
+ return function() {
780
+ const numberValue = Number(this.value);
781
+ const abbreviate = format.abbreviate === false ? false : deriveAbbreviateFromTicks(this);
782
+ return valueFormatter({ ...format, value: numberValue, abbreviate });
783
+ };
784
+ }
785
+
786
+
787
+
788
+
789
+
790
+
791
+
792
+
793
+
794
+
795
+ exports.useSeedsChartSetup = useSeedsChartSetup; exports.ChartRenderer = ChartRenderer; exports.buildAnnotationConfig = buildAnnotationConfig; exports.buildBaseChartOptions = buildBaseChartOptions; exports.buildDimensionalAxis = buildDimensionalAxis; exports.resolveTooltipTimezone = resolveTooltipTimezone; exports.defaultValueAxisLabelFormatter = defaultValueAxisLabelFormatter; exports.makeValueAxisLabelFormatter = makeValueAxisLabelFormatter;
796
+ //# sourceMappingURL=chunk-XVV7PYQE.js.map