@sproutsocial/seeds-react-data-viz 0.16.0 → 0.17.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.
Files changed (66) hide show
  1. package/dist/annotations-CjFoRPXf.d.mts +20 -0
  2. package/dist/annotations-CjFoRPXf.d.ts +20 -0
  3. package/dist/axis-WOeYkTO1.d.mts +44 -0
  4. package/dist/axis-WOeYkTO1.d.ts +44 -0
  5. package/dist/bar/index.d.mts +4 -2
  6. package/dist/bar/index.d.ts +4 -2
  7. package/dist/bar/index.js +14 -10
  8. package/dist/bar/index.js.map +1 -1
  9. package/dist/{axis-PJwu5Xmo.d.ts → chartBase-C-l7yYGx.d.ts} +6 -60
  10. package/dist/{axis-DXzufRRj.d.mts → chartBase-Cn_5CUJi.d.mts} +6 -60
  11. package/dist/{chunk-XVV7PYQE.js → chunk-2K7PFHIM.js} +101 -254
  12. package/dist/chunk-2K7PFHIM.js.map +1 -0
  13. package/dist/chunk-6D7P3IOT.js +150 -0
  14. package/dist/chunk-6D7P3IOT.js.map +1 -0
  15. package/dist/chunk-CYQXUAJC.js +169 -0
  16. package/dist/chunk-CYQXUAJC.js.map +1 -0
  17. package/dist/chunk-VVGBJOFH.js +68 -0
  18. package/dist/chunk-VVGBJOFH.js.map +1 -0
  19. package/dist/{chunk-EEVKTTT3.js → chunk-WEKDYQ4T.js} +1 -1
  20. package/dist/chunk-WEKDYQ4T.js.map +1 -0
  21. package/dist/donut/index.d.mts +48 -0
  22. package/dist/donut/index.d.ts +48 -0
  23. package/dist/donut/index.js +125 -0
  24. package/dist/donut/index.js.map +1 -0
  25. package/dist/esm/bar/index.js +11 -7
  26. package/dist/esm/bar/index.js.map +1 -1
  27. package/dist/esm/chunk-AUJ3EWRH.js +68 -0
  28. package/dist/esm/chunk-AUJ3EWRH.js.map +1 -0
  29. package/dist/esm/{chunk-ZXXFRUVF.js → chunk-LPQXJJNT.js} +94 -247
  30. package/dist/esm/chunk-LPQXJJNT.js.map +1 -0
  31. package/dist/esm/chunk-NAKJY5PA.js +150 -0
  32. package/dist/esm/chunk-NAKJY5PA.js.map +1 -0
  33. package/dist/esm/chunk-XMYGML25.js +169 -0
  34. package/dist/esm/chunk-XMYGML25.js.map +1 -0
  35. package/dist/esm/{chunk-LC3HGWDD.js → chunk-Z4LOM4OZ.js} +1 -1
  36. package/dist/esm/chunk-Z4LOM4OZ.js.map +1 -0
  37. package/dist/esm/donut/index.js +125 -0
  38. package/dist/esm/donut/index.js.map +1 -0
  39. package/dist/esm/export/index.js.map +1 -1
  40. package/dist/esm/index.js +20 -164
  41. package/dist/esm/index.js.map +1 -1
  42. package/dist/esm/line-area/index.js +12 -7
  43. package/dist/esm/line-area/index.js.map +1 -1
  44. package/dist/esm/sparkline/index.js +123 -0
  45. package/dist/esm/sparkline/index.js.map +1 -0
  46. package/dist/export/index.js.map +1 -1
  47. package/dist/index.d.mts +26 -23
  48. package/dist/index.d.ts +26 -23
  49. package/dist/index.js +113 -257
  50. package/dist/index.js.map +1 -1
  51. package/dist/line-area/index.d.mts +7 -4
  52. package/dist/line-area/index.d.ts +7 -4
  53. package/dist/line-area/index.js +15 -10
  54. package/dist/line-area/index.js.map +1 -1
  55. package/dist/sparkline/index.d.mts +75 -0
  56. package/dist/sparkline/index.d.ts +75 -0
  57. package/dist/sparkline/index.js +123 -0
  58. package/dist/sparkline/index.js.map +1 -0
  59. package/dist/sparkline.css +76 -0
  60. package/dist/{types-B7ILUQ6_.d.mts → types-DxrhdAdn.d.mts} +3 -3
  61. package/dist/{types-B7ILUQ6_.d.ts → types-DxrhdAdn.d.ts} +3 -3
  62. package/package.json +15 -3
  63. package/dist/chunk-EEVKTTT3.js.map +0 -1
  64. package/dist/chunk-XVV7PYQE.js.map +0 -1
  65. package/dist/esm/chunk-LC3HGWDD.js.map +0 -1
  66. package/dist/esm/chunk-ZXXFRUVF.js.map +0 -1
@@ -0,0 +1,150 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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; }// src/charts/shared/formatters/datetimeFormatter.ts
2
+ var DAY_MS = 864e5;
3
+ var WEEK_MS = 6048e5;
4
+ var MIN_MONTH_MS = 24192e5;
5
+ var MIN_YEAR_MS = 31536e6;
6
+ var getDatePartsInTimezone = (date, timezone) => {
7
+ const formatter = new Intl.DateTimeFormat("en-US", {
8
+ year: "numeric",
9
+ month: "numeric",
10
+ day: "numeric",
11
+ timeZone: timezone
12
+ });
13
+ const parts = formatter.formatToParts(date);
14
+ return {
15
+ day: parseInt(_nullishCoalesce(_optionalChain([parts, 'access', _ => _.find, 'call', _2 => _2((p) => p.type === "day"), 'optionalAccess', _3 => _3.value]), () => ( "0")), 10),
16
+ month: parseInt(_nullishCoalesce(_optionalChain([parts, 'access', _4 => _4.find, 'call', _5 => _5((p) => p.type === "month"), 'optionalAccess', _6 => _6.value]), () => ( "0")), 10),
17
+ year: parseInt(_nullishCoalesce(_optionalChain([parts, 'access', _7 => _7.find, 'call', _8 => _8((p) => p.type === "year"), 'optionalAccess', _9 => _9.value]), () => ( "0")), 10)
18
+ };
19
+ };
20
+ var deriveGranularity = (tickPositions) => {
21
+ if (tickPositions.length < 2) {
22
+ return "day";
23
+ }
24
+ const deltas = [];
25
+ for (let i = 1; i < tickPositions.length; i++) {
26
+ const curr = tickPositions[i];
27
+ const prev = tickPositions[i - 1];
28
+ if (curr === void 0 || prev === void 0) {
29
+ continue;
30
+ }
31
+ deltas.push(Math.abs(curr - prev));
32
+ }
33
+ deltas.sort((a, b) => a - b);
34
+ const mid = Math.floor(deltas.length / 2);
35
+ const upper = deltas[mid];
36
+ const lower = deltas[mid - 1];
37
+ const median = deltas.length % 2 === 0 && lower !== void 0 ? (lower + upper) / 2 : upper;
38
+ if (median < DAY_MS) {
39
+ return "hour";
40
+ }
41
+ if (median < WEEK_MS) {
42
+ return "day";
43
+ }
44
+ if (median < MIN_MONTH_MS) {
45
+ return "week";
46
+ }
47
+ if (median < MIN_YEAR_MS) {
48
+ return "month";
49
+ }
50
+ return "year";
51
+ };
52
+ function datetimeFormatter({
53
+ value,
54
+ tickPositions = [],
55
+ // optional
56
+ timezone = "UTC",
57
+ timeFormat = "12",
58
+ textLocale = "en-US"
59
+ }) {
60
+ if (typeof value === "string" || !Number.isFinite(value)) {
61
+ return { primary: String(value) };
62
+ }
63
+ const granularity = deriveGranularity(tickPositions);
64
+ const tickIndex = tickPositions.indexOf(value);
65
+ const isFirst = tickIndex === 0;
66
+ const previousValue = tickPositions[tickIndex - 1];
67
+ const valueDate = new Date(value);
68
+ const valueParts = getDatePartsInTimezone(valueDate, timezone);
69
+ const previousValueDate = previousValue ? new Date(previousValue) : void 0;
70
+ const previousValueParts = previousValueDate ? getDatePartsInTimezone(previousValueDate, timezone) : void 0;
71
+ let firstPartOptions = {};
72
+ let secondPartOptions = {};
73
+ switch (granularity) {
74
+ case "hour":
75
+ firstPartOptions = timeFormat === "24" ? { hour: "numeric", minute: "numeric", hour12: false } : { hour: "numeric" };
76
+ if (isFirst || valueParts.day !== _optionalChain([previousValueParts, 'optionalAccess', _10 => _10.day])) {
77
+ secondPartOptions = { day: "numeric", month: "short" };
78
+ }
79
+ break;
80
+ case "day":
81
+ case "week":
82
+ firstPartOptions = { day: "numeric" };
83
+ if (isFirst || valueParts.month !== _optionalChain([previousValueParts, 'optionalAccess', _11 => _11.month])) {
84
+ secondPartOptions = { month: "short" };
85
+ }
86
+ break;
87
+ case "month":
88
+ firstPartOptions = { month: "short" };
89
+ if (isFirst || valueParts.year !== _optionalChain([previousValueParts, 'optionalAccess', _12 => _12.year])) {
90
+ secondPartOptions = { year: "numeric" };
91
+ }
92
+ break;
93
+ case "year":
94
+ firstPartOptions = { year: "numeric" };
95
+ break;
96
+ default:
97
+ firstPartOptions = {};
98
+ break;
99
+ }
100
+ const primary = new Intl.DateTimeFormat(textLocale, {
101
+ ...firstPartOptions,
102
+ timeZone: timezone
103
+ }).format(valueDate);
104
+ if (Object.keys(secondPartOptions).length > 0) {
105
+ const secondary = new Intl.DateTimeFormat(textLocale, {
106
+ ...secondPartOptions,
107
+ timeZone: timezone
108
+ }).format(valueDate);
109
+ return { primary, secondary };
110
+ }
111
+ return { primary };
112
+ }
113
+
114
+ // src/charts/shared/axisOptions.ts
115
+ function makeDatetimeAxisLabelFormatter(timezone, timeFormat) {
116
+ return function() {
117
+ const { primary, secondary } = datetimeFormatter({
118
+ value: this.value,
119
+ tickPositions: _nullishCoalesce(this.axis.tickPositions, () => ( [])),
120
+ timezone,
121
+ timeFormat
122
+ });
123
+ return secondary ? `${primary}<br/><span class="hc-axis-label-secondary">${secondary}</span>` : primary;
124
+ };
125
+ }
126
+ function buildDimensionalAxis(axis, timezone) {
127
+ if (axis.type === "datetime") {
128
+ return {
129
+ type: "datetime",
130
+ crosshair: axis.crosshair,
131
+ labels: {
132
+ formatter: makeDatetimeAxisLabelFormatter(timezone, axis.timeFormat)
133
+ }
134
+ };
135
+ }
136
+ return {
137
+ type: "category",
138
+ categories: [...axis.categories],
139
+ crosshair: axis.crosshair
140
+ };
141
+ }
142
+ function resolveTooltipTimezone(axis, timezone) {
143
+ return axis.type === "datetime" ? _nullishCoalesce(timezone, () => ( "UTC")) : void 0;
144
+ }
145
+
146
+
147
+
148
+
149
+ exports.buildDimensionalAxis = buildDimensionalAxis; exports.resolveTooltipTimezone = resolveTooltipTimezone;
150
+ //# sourceMappingURL=chunk-6D7P3IOT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-6D7P3IOT.js","../src/charts/shared/formatters/datetimeFormatter.ts","../src/charts/shared/axisOptions.ts"],"names":[],"mappings":"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","file":"/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-6D7P3IOT.js","sourcesContent":[null,"/**\n * Pure, Highcharts-free datetime axis label formatter for v2 chart families.\n *\n * Ports v1's `helpers/xAxisLabelFormatter` into a rendering-agnostic shape: it\n * returns a `{ primary, secondary? }` object instead of an HTML string, leaving\n * SVG rendering to the caller. The timezone- and DST-correct boundary detection\n * (calendar parts read in the target timezone) and the per-granularity\n * `Intl.DateTimeFormat` option sets are a near-verbatim port of v1.\n *\n * The one net-new piece versus v1 is granularity derivation: v1 receives\n * `unitName` from Highcharts, but `charts/` may not depend on Highcharts types\n * (see `charts/README.md` invariants), so granularity is derived from the\n * spacing of `tickPositions`.\n */\n\n// Local types — defined here rather than imported from the Highcharts package\n// or v1's src/types.ts, to keep charts/ self-contained per the README invariant.\nexport type DatetimeTimeFormat = \"12\" | \"24\";\n\nexport type DatetimeLabel = Readonly<{\n primary: string;\n /** Omitted (undefined) when the tick is not on a unit boundary. */\n secondary?: string;\n}>;\n\ntype DatetimeGranularity = \"hour\" | \"day\" | \"week\" | \"month\" | \"year\";\n\ntype DatetimeFormatterInput = Readonly<{\n /** ms-epoch tick value, or a categorical string passed through verbatim. */\n value: number | string;\n /** Full tick array — used for boundary lookup and granularity derivation. */\n tickPositions: readonly number[];\n // optional\n /** IANA timezone. Defaults to \"UTC\". */\n timezone?: string;\n /** \"12\" | \"24\" hour clock for the hour granularity. Defaults to \"12\". */\n timeFormat?: DatetimeTimeFormat;\n /** Locale for Intl formatting. Defaults to \"en-US\". */\n textLocale?: Intl.LocalesArgument;\n}>;\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars -- kept alongside DAY_MS/WEEK_MS for upcoming duration formatting; stable numeric constant unlikely to drift\nconst HOUR_MS = 3_600_000;\nconst DAY_MS = 86_400_000;\nconst WEEK_MS = 604_800_000;\n// Granularity cutoffs use the *minimum* month/year length, not the average, so\n// calendar-aligned axes classify correctly: a real Highcharts month-unit axis\n// sits 28–31d apart and a year-unit axis 365–366d apart. Comparing the median\n// tick delta against the *average* month (30.44d) / year (365.25d) length\n// misclassified a 28-day February month gap as \"week\" and a 365-day non-leap\n// year as \"month\". Bias to the minimum so the shortest real span still reads as\n// \"month\" / \"year\".\nconst MIN_MONTH_MS = 2_419_200_000; // 28 days (shortest month, non-leap Feb)\nconst MIN_YEAR_MS = 31_536_000_000; // 365 days (shortest, non-leap year)\n\n/**\n * Reads the calendar day/month/year of a date *in the target timezone* via\n * `Intl.DateTimeFormat(...).formatToParts`. This is what makes boundary\n * detection timezone- and DST-correct (a 25-hour \"fall back\" day still rolls\n * the day over on the correct local-midnight tick). Ported verbatim from v1.\n */\nconst getDatePartsInTimezone = (date: Date, timezone: string) => {\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n timeZone: timezone,\n });\n const parts = formatter.formatToParts(date);\n return {\n day: parseInt(parts.find((p) => p.type === \"day\")?.value ?? \"0\", 10),\n month: parseInt(parts.find((p) => p.type === \"month\")?.value ?? \"0\", 10),\n year: parseInt(parts.find((p) => p.type === \"year\")?.value ?? \"0\", 10),\n };\n};\n\n/**\n * Derives the axis granularity from the median delta between consecutive\n * `tickPositions`. Median (not mean) so an irregular first/last gap does not\n * skew the result. With fewer than two ticks there is no spacing to measure, so\n * we default to \"day\".\n *\n * Note: \"day\" and \"week\" produce identical output (same primary/secondary\n * option sets), so the day/week threshold is cosmetic and never changes a label.\n * The week↔month and month↔year cutoffs do change output, so they compare\n * against the *minimum* month/year length (not the average); see MIN_MONTH_MS /\n * MIN_YEAR_MS for why calendar-aligned axes would otherwise be misclassified.\n */\nconst deriveGranularity = (\n tickPositions: readonly number[]\n): DatetimeGranularity => {\n if (tickPositions.length < 2) {\n return \"day\";\n }\n\n const deltas: number[] = [];\n for (let i = 1; i < tickPositions.length; i++) {\n const curr = tickPositions[i];\n const prev = tickPositions[i - 1];\n // Both reads are in range by the loop bounds (1 <= i < length); the guard\n // only satisfies noUncheckedIndexedAccess and is unreachable at runtime.\n if (curr === undefined || prev === undefined) {\n continue;\n }\n deltas.push(Math.abs(curr - prev));\n }\n deltas.sort((a, b) => a - b);\n\n const mid = Math.floor(deltas.length / 2);\n // `length >= 2` is guaranteed by the early return above, so `deltas` has at\n // least one element and `deltas[mid]` is always defined; `deltas[mid - 1]` is\n // only read on the even-length branch, where it is guaranteed in range too.\n const upper = deltas[mid]!;\n const lower = deltas[mid - 1];\n const median =\n deltas.length % 2 === 0 && lower !== undefined\n ? (lower + upper) / 2\n : upper;\n\n if (median < DAY_MS) {\n return \"hour\";\n }\n if (median < WEEK_MS) {\n return \"day\";\n }\n if (median < MIN_MONTH_MS) {\n return \"week\";\n }\n if (median < MIN_YEAR_MS) {\n return \"month\";\n }\n return \"year\";\n};\n\n/**\n * Derives a datetime tick's two-line stacked label as a rendering-agnostic\n * `{ primary, secondary? }` object. `secondary` is emitted only on a unit\n * boundary (the first tick, or when the relevant calendar part changes versus\n * the previous tick), matching v1's two-line semantics.\n *\n * Categorical (string) values and non-finite numbers are passed through as\n * `{ primary: String(value) }` with no secondary, so callers always get a\n * stable, markup-free string rather than \"Invalid Date\".\n */\nexport function datetimeFormatter({\n value,\n tickPositions = [],\n // optional\n timezone = \"UTC\",\n timeFormat = \"12\",\n textLocale = \"en-US\",\n}: DatetimeFormatterInput): DatetimeLabel {\n // Categorical (string) data, and non-finite timestamps, pass through.\n if (typeof value === \"string\" || !Number.isFinite(value)) {\n return { primary: String(value) };\n }\n\n const granularity = deriveGranularity(tickPositions);\n\n const tickIndex = tickPositions.indexOf(value);\n const isFirst = tickIndex === 0;\n const previousValue = tickPositions[tickIndex - 1];\n\n const valueDate = new Date(value);\n const valueParts = getDatePartsInTimezone(valueDate, timezone);\n const previousValueDate = previousValue ? new Date(previousValue) : undefined;\n const previousValueParts = previousValueDate\n ? getDatePartsInTimezone(previousValueDate, timezone)\n : undefined;\n\n let firstPartOptions: Intl.DateTimeFormatOptions = {};\n let secondPartOptions: Intl.DateTimeFormatOptions = {};\n\n switch (granularity) {\n case \"hour\":\n firstPartOptions =\n timeFormat === \"24\"\n ? { hour: \"numeric\", minute: \"numeric\", hour12: false }\n : { hour: \"numeric\" };\n if (isFirst || valueParts.day !== previousValueParts?.day) {\n secondPartOptions = { day: \"numeric\", month: \"short\" };\n }\n break;\n case \"day\":\n case \"week\":\n firstPartOptions = { day: \"numeric\" };\n if (isFirst || valueParts.month !== previousValueParts?.month) {\n secondPartOptions = { month: \"short\" };\n }\n break;\n case \"month\":\n firstPartOptions = { month: \"short\" };\n if (isFirst || valueParts.year !== previousValueParts?.year) {\n secondPartOptions = { year: \"numeric\" };\n }\n break;\n case \"year\":\n firstPartOptions = { year: \"numeric\" };\n break;\n default:\n firstPartOptions = {};\n break;\n }\n\n const primary = new Intl.DateTimeFormat(textLocale, {\n ...firstPartOptions,\n timeZone: timezone,\n }).format(valueDate);\n\n if (Object.keys(secondPartOptions).length > 0) {\n const secondary = new Intl.DateTimeFormat(textLocale, {\n ...secondPartOptions,\n timeZone: timezone,\n }).format(valueDate);\n return { primary, secondary };\n }\n\n return { primary };\n}\n","// Shared adapter helpers for the X/Y chart families (bar, line-area, …). Each\n// family's adapter still owns its `chart.type`, `plotOptions`, `series`, and\n// value (y) axis; these utilities cover the dimensional-axis + timezone wiring\n// that is identical across families, so it lives in one place.\n//\n// Deliberately granular (one concern per function) rather than a single base-\n// options builder, so a non-X/Y family like donut can reuse the subset that\n// applies to it. The broader shared-shell + value-axis sharing is left to the\n// X/Y pattern-sharing spike — the value axis in particular diverges per family\n// today (e.g. bar's declarative `format` from CE-41), so it stays per-family.\n\nimport type { DimensionalAxis } from \"./axis\";\nimport type {\n SeedsAxisLabelFormatterContext,\n SeedsChartXAxisOptions,\n} from \"./chartBase\";\nimport { datetimeFormatter } from \"./formatters/datetimeFormatter\";\nimport type { DatetimeTimeFormat } from \"./formatters/datetimeFormatter\";\n\n// Datetime tick labels: a granularity-aware, timezone/DST-correct two-line\n// stacked label via the shared `datetimeFormatter`, rendered as SVG. `<br/>` is a\n// line break in Highcharts' SVG text (styledMode, useHTML: false); the secondary\n// token is wrapped in a <span> — rendered as a <tspan> — styled by the\n// `.highcharts-xaxis-labels` rule in `styles/chartStyles.ts`.\nfunction makeDatetimeAxisLabelFormatter(\n timezone: string,\n timeFormat: DatetimeTimeFormat | undefined\n) {\n return function (this: SeedsAxisLabelFormatterContext): string {\n const { primary, secondary } = datetimeFormatter({\n value: this.value,\n tickPositions: this.axis.tickPositions ?? [],\n timezone,\n timeFormat,\n });\n return secondary\n ? `${primary}<br/><span class=\"hc-axis-label-secondary\">${secondary}</span>`\n : primary;\n };\n}\n\n/**\n * Builds the dimensional (x) axis options shared by the X/Y chart families.\n * Category axes pass their labels through; datetime axes get the granularity-\n * aware two-line label formatter. `timezone` is only consulted for datetime.\n */\nexport function buildDimensionalAxis(\n axis: DimensionalAxis,\n timezone: string\n): SeedsChartXAxisOptions {\n if (axis.type === \"datetime\") {\n return {\n type: \"datetime\",\n crosshair: axis.crosshair,\n labels: {\n formatter: makeDatetimeAxisLabelFormatter(timezone, axis.timeFormat),\n },\n };\n }\n return {\n type: \"category\",\n categories: [...axis.categories],\n crosshair: axis.crosshair,\n };\n}\n\n/**\n * The timezone shared by datetime-axis ticks (`time.timezone`) and the tooltip\n * date formatter, so they can never disagree about the day. Defaults to `\"UTC\"`\n * on a datetime axis; `undefined` on a category axis (timezone is meaningless).\n */\nexport function resolveTooltipTimezone(\n axis: DimensionalAxis,\n timezone?: string\n): string | undefined {\n return axis.type === \"datetime\" ? timezone ?? \"UTC\" : undefined;\n}\n"]}
@@ -0,0 +1,169 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/constants/chartOptions.ts
2
+ var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash);
3
+ var baseChartOptions = {
4
+ chart: {
5
+ animation: false,
6
+ styledMode: true
7
+ },
8
+ credits: {
9
+ enabled: false
10
+ },
11
+ exporting: {
12
+ enabled: false,
13
+ fallbackToExportServer: false
14
+ },
15
+ legend: {
16
+ enabled: false
17
+ },
18
+ title: {
19
+ text: void 0
20
+ },
21
+ tooltip: {
22
+ hideDelay: 0,
23
+ outside: true,
24
+ padding: 0,
25
+ shape: "rect",
26
+ shared: true,
27
+ useHTML: true
28
+ }
29
+ };
30
+ var TIME_SERIES_CHART_HEIGHT = 275;
31
+ var timeSeriesChartOptions = _lodash2.default.merge({}, baseChartOptions, {
32
+ annotations: [
33
+ {
34
+ draggable: "",
35
+ labelOptions: {
36
+ useHTML: true,
37
+ padding: 0
38
+ // removes "left" property padding created by highcharts so that label is centered
39
+ }
40
+ }
41
+ ],
42
+ chart: {
43
+ // events.click is set at the component level because of the optional onClick prop
44
+ height: TIME_SERIES_CHART_HEIGHT,
45
+ spacing: [5, 1, 0, 2]
46
+ },
47
+ plotOptions: {
48
+ series: {
49
+ animation: false,
50
+ clip: false,
51
+ marker: {
52
+ enabled: false,
53
+ states: {
54
+ hover: {
55
+ enabled: false
56
+ }
57
+ }
58
+ }
59
+ }
60
+ },
61
+ xAxis: {
62
+ crosshair: {
63
+ zIndex: 3
64
+ },
65
+ minPadding: 0,
66
+ // must be handled dynamically instead of css
67
+ maxPadding: 0,
68
+ // must be handled dynamically instead of css
69
+ type: "datetime",
70
+ labels: {
71
+ useHTML: true
72
+ // formatter is set at the component level because of the required text locale prop
73
+ }
74
+ },
75
+ yAxis: {
76
+ labels: {
77
+ useHTML: true
78
+ // formatter is set at the component level because of the optional yAxisLabelFormatter prop
79
+ },
80
+ softMax: 0,
81
+ softMin: 0,
82
+ title: {
83
+ text: void 0
84
+ },
85
+ plotLines: [
86
+ /* Adds a custom plotLine at y=0 to represent the chart baseline.
87
+ This approach allows full control over the line's appearance (e.g., color, z-index),
88
+ unlike relying on the default xAxis line, which always renders at the bottom of the chart
89
+ even when y=0 appears elsewhere (e.g., with negative values).
90
+ */
91
+ {
92
+ className: "y-axis-zero-line",
93
+ value: 0,
94
+ zIndex: 3
95
+ // ensures the line appears over the default y=0 line, which we can't seleect as specifically
96
+ }
97
+ ]
98
+ }
99
+ });
100
+ var lineChartOptions = _lodash2.default.merge({}, timeSeriesChartOptions, {
101
+ // plotOptions.spline.events.click is set at the component level because of the optional onClick prop
102
+ });
103
+ var areaChartOptions = _lodash2.default.merge({}, timeSeriesChartOptions, {
104
+ plotOptions: {
105
+ areaspline: {
106
+ // events.click is set at the component level because of the optional onClick prop
107
+ stacking: "normal"
108
+ }
109
+ }
110
+ });
111
+ var columnChartOptions = _lodash2.default.merge({}, timeSeriesChartOptions, {
112
+ plotOptions: {
113
+ column: {
114
+ stacking: "normal",
115
+ pointPadding: 0.25,
116
+ groupPadding: 0.25,
117
+ borderRadius: 4
118
+ }
119
+ },
120
+ xAxis: {
121
+ crosshair: false
122
+ },
123
+ yAxis: {
124
+ plotLines: [
125
+ {
126
+ // For stacked column charts with visible borders (e.g., white for contrast),
127
+ // we raise the zIndex of the y=0 plotLine to ensure it remains visible
128
+ // and isn't visually covered by overlapping column borders.
129
+ zIndex: 5
130
+ }
131
+ ]
132
+ }
133
+ });
134
+ var VERTICAL_BAR_CHART_DEFAULT_SERIES_LIMIT = 10;
135
+ var DONUT_CHART_HALO_SIZE = 10;
136
+ var DONUT_CHART_HEIGHT = 250 + DONUT_CHART_HALO_SIZE * 2;
137
+ var DONUT_CHART_WIDTH = DONUT_CHART_HEIGHT;
138
+ var donutChartOptions = _lodash2.default.merge({}, baseChartOptions, {
139
+ chart: {
140
+ height: DONUT_CHART_HEIGHT,
141
+ spacing: [0, 0, 0, 0]
142
+ },
143
+ plotOptions: {
144
+ pie: {
145
+ animation: false,
146
+ borderRadius: 0,
147
+ // must be handled here instead of css because of path rendering
148
+ dataLabels: {
149
+ enabled: false
150
+ },
151
+ innerSize: "50%"
152
+ }
153
+ }
154
+ });
155
+
156
+
157
+
158
+
159
+
160
+
161
+
162
+
163
+
164
+
165
+
166
+
167
+
168
+ exports.baseChartOptions = baseChartOptions; exports.TIME_SERIES_CHART_HEIGHT = TIME_SERIES_CHART_HEIGHT; exports.timeSeriesChartOptions = timeSeriesChartOptions; exports.lineChartOptions = lineChartOptions; exports.areaChartOptions = areaChartOptions; exports.columnChartOptions = columnChartOptions; exports.VERTICAL_BAR_CHART_DEFAULT_SERIES_LIMIT = VERTICAL_BAR_CHART_DEFAULT_SERIES_LIMIT; exports.DONUT_CHART_HALO_SIZE = DONUT_CHART_HALO_SIZE; exports.DONUT_CHART_HEIGHT = DONUT_CHART_HEIGHT; exports.DONUT_CHART_WIDTH = DONUT_CHART_WIDTH; exports.donutChartOptions = donutChartOptions;
169
+ //# sourceMappingURL=chunk-CYQXUAJC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-CYQXUAJC.js","../src/constants/chartOptions.ts"],"names":[],"mappings":"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","file":"/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-CYQXUAJC.js","sourcesContent":[null,"import type { Options } from \"highcharts\";\nimport _ from \"lodash\";\n\n// options that should apply to all charts\n// this is being exported because it's needed for the listening bubble chart component.\n// when that components gets moved into the data-viz package, we can remove the export here\nexport const baseChartOptions: Options = {\n chart: {\n animation: false,\n styledMode: true,\n },\n credits: {\n enabled: false,\n },\n exporting: {\n enabled: false,\n fallbackToExportServer: false,\n },\n legend: {\n enabled: false,\n },\n title: {\n text: undefined,\n },\n tooltip: {\n hideDelay: 0,\n outside: true,\n padding: 0,\n shape: \"rect\",\n shared: true,\n useHTML: true,\n },\n};\n\n// options that should apply to time series charts\nexport const TIME_SERIES_CHART_HEIGHT = 275;\nexport const timeSeriesChartOptions: Options = _.merge({}, baseChartOptions, {\n annotations: [\n {\n draggable: \"\",\n labelOptions: {\n useHTML: true,\n padding: 0, // removes \"left\" property padding created by highcharts so that label is centered\n },\n },\n ],\n chart: {\n // events.click is set at the component level because of the optional onClick prop\n height: TIME_SERIES_CHART_HEIGHT,\n spacing: [5, 1, 0, 2],\n },\n plotOptions: {\n series: {\n animation: false,\n clip: false,\n marker: {\n enabled: false,\n states: {\n hover: {\n enabled: false,\n },\n },\n },\n },\n },\n xAxis: {\n crosshair: {\n zIndex: 3,\n },\n minPadding: 0, // must be handled dynamically instead of css\n maxPadding: 0, // must be handled dynamically instead of css\n type: \"datetime\",\n labels: {\n useHTML: true,\n // formatter is set at the component level because of the required text locale prop\n },\n },\n yAxis: {\n labels: {\n useHTML: true,\n // formatter is set at the component level because of the optional yAxisLabelFormatter prop\n },\n softMax: 0,\n softMin: 0,\n title: {\n text: undefined,\n },\n plotLines: [\n /* Adds a custom plotLine at y=0 to represent the chart baseline.\n This approach allows full control over the line's appearance (e.g., color, z-index),\n unlike relying on the default xAxis line, which always renders at the bottom of the chart\n even when y=0 appears elsewhere (e.g., with negative values).\n */\n {\n className: \"y-axis-zero-line\",\n value: 0,\n zIndex: 3, // ensures the line appears over the default y=0 line, which we can't seleect as specifically\n },\n ],\n },\n});\n\n// options that should apply to LineChart\nexport const lineChartOptions: Options = _.merge({}, timeSeriesChartOptions, {\n // plotOptions.spline.events.click is set at the component level because of the optional onClick prop\n});\n\n// options that should apply to AreaChart\nexport const areaChartOptions: Options = _.merge({}, timeSeriesChartOptions, {\n plotOptions: {\n areaspline: {\n // events.click is set at the component level because of the optional onClick prop\n stacking: \"normal\",\n },\n },\n});\n\nexport const columnChartOptions: Options = _.merge({}, timeSeriesChartOptions, {\n plotOptions: {\n column: {\n stacking: \"normal\",\n pointPadding: 0.25,\n groupPadding: 0.25,\n borderRadius: 4,\n },\n },\n xAxis: {\n crosshair: false,\n },\n yAxis: {\n plotLines: [\n {\n // For stacked column charts with visible borders (e.g., white for contrast),\n // we raise the zIndex of the y=0 plotLine to ensure it remains visible\n // and isn't visually covered by overlapping column borders.\n zIndex: 5,\n },\n ],\n },\n});\n\n/**\n * The default series limit for VerticalBarChart.\n * This limit is recommended to maintain chart readability and accessibility.\n * @see {VerticalBarChart}\n */\nexport const VERTICAL_BAR_CHART_DEFAULT_SERIES_LIMIT = 10;\n\n// options that should apply to DonutChart\nexport const DONUT_CHART_HALO_SIZE = 10; // 10 is the default from highcharts\nexport const DONUT_CHART_HEIGHT = 250 + DONUT_CHART_HALO_SIZE * 2;\nexport const DONUT_CHART_WIDTH = DONUT_CHART_HEIGHT;\nexport const donutChartOptions: Options = _.merge({}, baseChartOptions, {\n chart: {\n height: DONUT_CHART_HEIGHT,\n spacing: [0, 0, 0, 0],\n },\n plotOptions: {\n pie: {\n animation: false,\n borderRadius: 0, // must be handled here instead of css because of path rendering\n dataLabels: {\n enabled: false,\n },\n innerSize: \"50%\",\n },\n },\n});\n"]}
@@ -0,0 +1,68 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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
+ var _chunk2K7PFHIMjs = require('./chunk-2K7PFHIM.js');
4
+
5
+ // src/charts/shared/annotations.ts
6
+ function buildAnnotationConfig(annotations) {
7
+ if (!_optionalChain([annotations, 'optionalAccess', _ => _.length])) {
8
+ return { annotations: void 0, lookup: void 0 };
9
+ }
10
+ const labels = [];
11
+ const lookup = /* @__PURE__ */ new Map();
12
+ for (const annotation of annotations) {
13
+ const { position } = annotation;
14
+ labels.push({
15
+ // Highcharts anchor — always uses `x` regardless of chart orientation.
16
+ point: { x: position, y: 0, xAxis: 0, yAxis: 0 },
17
+ // Space (not empty) — Highcharts reverts to its built-in label text on empty string.
18
+ text: " "
19
+ });
20
+ lookup.set(position, annotation);
21
+ }
22
+ if (labels.length === 0) {
23
+ return { annotations: void 0, lookup: void 0 };
24
+ }
25
+ return {
26
+ // `useHTML: true` makes Highcharts attach an HTML `graphic.div` to each
27
+ // label, which the marker portal needs as its render target. `padding: 0`
28
+ // removes Highcharts' default left padding so markers stay centered.
29
+ annotations: [{ labels, labelOptions: { useHTML: true, padding: 0 } }],
30
+ lookup
31
+ };
32
+ }
33
+
34
+ // src/charts/shared/valueAxisLabelFormatter.ts
35
+ var _seedsreactnumeral = require('@sproutsocial/seeds-react-numeral');
36
+ var FIXED_LOCALE = "en-US";
37
+ function deriveAbbreviateFromTicks(context) {
38
+ const tickPositions = context.axis.tickPositions;
39
+ const maxValue = tickPositions && tickPositions.length > 0 ? tickPositions[tickPositions.length - 1] : void 0;
40
+ return typeof maxValue === "number" && maxValue > 9999 ? 1e3 : true;
41
+ }
42
+ function defaultValueAxisLabelFormatter() {
43
+ const numberValue = Number(this.value);
44
+ if (numberValue === 0) {
45
+ return _seedsreactnumeral.formatNumeral.call(void 0, { locale: FIXED_LOCALE, number: 0 });
46
+ }
47
+ const abbreviate = deriveAbbreviateFromTicks(this);
48
+ return _seedsreactnumeral.formatNumeral.call(void 0, {
49
+ abbreviate,
50
+ format: "decimal",
51
+ locale: FIXED_LOCALE,
52
+ number: numberValue
53
+ });
54
+ }
55
+ function makeValueAxisLabelFormatter(format) {
56
+ return function() {
57
+ const numberValue = Number(this.value);
58
+ const abbreviate = format.abbreviate === false ? false : deriveAbbreviateFromTicks(this);
59
+ return _chunk2K7PFHIMjs.valueFormatter.call(void 0, { ...format, value: numberValue, abbreviate });
60
+ };
61
+ }
62
+
63
+
64
+
65
+
66
+
67
+ exports.buildAnnotationConfig = buildAnnotationConfig; exports.defaultValueAxisLabelFormatter = defaultValueAxisLabelFormatter; exports.makeValueAxisLabelFormatter = makeValueAxisLabelFormatter;
68
+ //# sourceMappingURL=chunk-VVGBJOFH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-VVGBJOFH.js","../src/charts/shared/annotations.ts","../src/charts/shared/valueAxisLabelFormatter.ts"],"names":[],"mappings":"AAAA;AACE;AACF,sDAA4B;AAC5B;AACA;ACkCO,SAAS,qBAAA,CACd,WAAA,EAIA;AACA,EAAA,GAAA,CAAI,iBAAC,WAAA,2BAAa,QAAA,EAAQ;AACxB,IAAA,OAAO,EAAE,WAAA,EAAa,KAAA,CAAA,EAAW,MAAA,EAAQ,KAAA,EAAU,CAAA;AAAA,EACrD;AACA,EAAA,MAAM,OAAA,EAGA,CAAC,CAAA;AACP,EAAA,MAAM,OAAA,kBAAgC,IAAI,GAAA,CAAI,CAAA;AAC9C,EAAA,IAAA,CAAA,MAAW,WAAA,GAAc,WAAA,EAAa;AACpC,IAAA,MAAM,EAAE,SAAS,EAAA,EAAI,UAAA;AACrB,IAAA,MAAA,CAAO,IAAA,CAAK;AAAA;AAAA,MAEV,KAAA,EAAO,EAAE,CAAA,EAAG,QAAA,EAAU,CAAA,EAAG,CAAA,EAAG,KAAA,EAAO,CAAA,EAAG,KAAA,EAAO,EAAE,CAAA;AAAA;AAAA,MAE/C,IAAA,EAAM;AAAA,IACR,CAAC,CAAA;AAID,IAAA,MAAA,CAAO,GAAA,CAAI,QAAA,EAAU,UAAU,CAAA;AAAA,EACjC;AACA,EAAA,GAAA,CAAI,MAAA,CAAO,OAAA,IAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAE,WAAA,EAAa,KAAA,CAAA,EAAW,MAAA,EAAQ,KAAA,EAAU,CAAA;AAAA,EACrD;AACA,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA,IAIL,WAAA,EAAa,CAAC,EAAE,MAAA,EAAQ,YAAA,EAAc,EAAE,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,EAAE,EAAE,CAAC,CAAA;AAAA,IACrE;AAAA,EACF,CAAA;AACF;AD3CA;AACA;AEjCA,sEAA8B;AAW9B,IAAM,aAAA,EAAe,OAAA;AAWrB,SAAS,yBAAA,CACP,OAAA,EACkB;AAClB,EAAA,MAAM,cAAA,EAAgB,OAAA,CAAQ,IAAA,CAAK,aAAA;AACnC,EAAA,MAAM,SAAA,EACJ,cAAA,GAAiB,aAAA,CAAc,OAAA,EAAS,EAAA,EACpC,aAAA,CAAc,aAAA,CAAc,OAAA,EAAS,CAAC,EAAA,EACtC,KAAA,CAAA;AACN,EAAA,OAAO,OAAO,SAAA,IAAa,SAAA,GAAY,SAAA,EAAW,KAAA,EAAO,IAAA,EAAO,IAAA;AAClE;AAWO,SAAS,8BAAA,CAAA,EAEN;AACR,EAAA,MAAM,YAAA,EAAc,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAErC,EAAA,GAAA,CAAI,YAAA,IAAgB,CAAA,EAAG;AACrB,IAAA,OAAO,8CAAA,EAAgB,MAAA,EAAQ,YAAA,EAAc,MAAA,EAAQ,EAAE,CAAC,CAAA;AAAA,EAC1D;AAEA,EAAA,MAAM,WAAA,EAAa,yBAAA,CAA0B,IAAI,CAAA;AAEjD,EAAA,OAAO,8CAAA;AAAc,IACnB,UAAA;AAAA,IACA,MAAA,EAAQ,SAAA;AAAA,IACR,MAAA,EAAQ,YAAA;AAAA,IACR,MAAA,EAAQ;AAAA,EACV,CAAC,CAAA;AACH;AAYO,SAAS,2BAAA,CAA4B,MAAA,EAAqB;AAC/D,EAAA,OAAO,QAAA,CAAA,EAAwD;AAC7D,IAAA,MAAM,YAAA,EAAc,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AAMrC,IAAA,MAAM,WAAA,EACJ,MAAA,CAAO,WAAA,IAAe,MAAA,EAAQ,MAAA,EAAQ,yBAAA,CAA0B,IAAI,CAAA;AAEtE,IAAA,OAAO,6CAAA,EAAiB,GAAG,MAAA,EAAQ,KAAA,EAAO,WAAA,EAAa,WAAW,CAAC,CAAA;AAAA,EACrE,CAAA;AACF;AFvBA;AACA;AACE;AACA;AACA;AACF,kMAAC","file":"/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-VVGBJOFH.js","sourcesContent":[null,"// Shared annotation plumbing across v2 chart families. Currently consumed by\n// BarChart; v2 Line/Area will share the same `annotations` shape and reuse\n// `buildAnnotationConfig` directly. Annotation data is purely numeric —\n// the module has no knowledge of `categories`; resolving a numeric position to\n// a display name is the tooltip's job (see chartBase `renderContent`).\n\nimport type { TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport type { SeedsChartAnnotationsOptions } from \"./chartBase\";\n\n/**\n * Annotations keyed by the numeric Highcharts index. Both consumers resolve\n * numerically: the marker portal reads `label.point.x` and the tooltip reads\n * `context.point.x` (numeric on both category and datetime axes).\n */\nexport type ChartAnnotationLookup = Map<number, ChartAnnotation>;\n\n/**\n * Declarative annotation shape — the DS renders the marker and tooltip header\n * internally; consumers don't supply render functions. See CE-7.\n */\nexport interface ChartAnnotation {\n /** Numeric x-axis coordinate — a category index (category axes) or the raw coordinate (datetime/linear axes). */\n position: number;\n /** Icon shown above the chart at `position` and inline with `title` in the tooltip header. */\n icon?: TypeIconName;\n /** Color applied to the marker's vertical line. */\n color?: string;\n /** Tooltip header line 1. */\n title?: string;\n /** Tooltip header line 2. */\n description?: string;\n}\n\n/**\n * Build the Highcharts `annotations` config and a parallel lookup keyed by the\n * numeric `position`. Both consumers (chart adapter for Highcharts, ChartRenderer\n * for the portal + tooltip) read from the same numeric lookup to stay aligned.\n */\nexport function buildAnnotationConfig(\n annotations: ChartAnnotation[] | undefined\n): {\n annotations: SeedsChartAnnotationsOptions[] | undefined;\n lookup: ChartAnnotationLookup | undefined;\n} {\n if (!annotations?.length) {\n return { annotations: undefined, lookup: undefined };\n }\n const labels: {\n point: { x: number; y: number; xAxis: 0; yAxis: 0 };\n text: string;\n }[] = [];\n const lookup: ChartAnnotationLookup = new Map();\n for (const annotation of annotations) {\n const { position } = annotation;\n labels.push({\n // Highcharts anchor — always uses `x` regardless of chart orientation.\n point: { x: position, y: 0, xAxis: 0, yAxis: 0 },\n // Space (not empty) — Highcharts reverts to its built-in label text on empty string.\n text: \" \",\n });\n // Keyed by the numeric position only. The marker portal reads\n // `label.point.x` and the tooltip reads `context.point.x` — both numeric on\n // every axis type, so no category-name keying is needed.\n lookup.set(position, annotation);\n }\n if (labels.length === 0) {\n return { annotations: undefined, lookup: undefined };\n }\n return {\n // `useHTML: true` makes Highcharts attach an HTML `graphic.div` to each\n // label, which the marker portal needs as its render target. `padding: 0`\n // removes Highcharts' default left padding so markers stay centered.\n annotations: [{ labels, labelOptions: { useHTML: true, padding: 0 } }],\n lookup,\n };\n}\n","import { formatNumeral } from \"@sproutsocial/seeds-react-numeral\";\n\nimport type { SeedsAxisLabelFormatterContext } from \"./chartBase\";\nimport { valueFormatter, type ValueFormat } from \"./formatters/valueFormatter\";\n\n/**\n * Fixed internal locale for the default value-axis formatter. Pins the en-US\n * compact symbols (2K / 1.2M / 1.2B) so output is deterministic regardless of\n * the environment's locale resolution.\n * TODO: consumer-facing locale and an override surface may be added later.\n */\nconst FIXED_LOCALE = \"en-US\";\n\n/**\n * Derive formatNumeral's `abbreviate` threshold from the axis tick scan.\n *\n * formatNumeral abbreviates above 10,000 by default; passing a numeric\n * `abbreviate` lowers that threshold to that value. When the top tick exceeds\n * 9,999 we lower it to 1,000 so the whole axis reads \"2K 4K 6K 8K 10K\" rather\n * than a mixed \"2,000 4,000 6,000 8,000 10K\". Otherwise `true` keeps the default\n * 10,000 threshold. Centralizes the 9,999 rule for both formatters below.\n */\nfunction deriveAbbreviateFromTicks(\n context: SeedsAxisLabelFormatterContext\n): boolean | number {\n const tickPositions = context.axis.tickPositions;\n const maxValue =\n tickPositions && tickPositions.length > 0\n ? tickPositions[tickPositions.length - 1]\n : undefined;\n return typeof maxValue === \"number\" && maxValue > 9999 ? 1000 : true;\n}\n\n/**\n * Internal, zero-config default value-axis label formatter for v2 chart\n * families. Abbreviates value-axis ticks (1.20K / 1.20M / 1.20B); decimal mode\n * only. Zero renders \"0\". Decimal compact precision is fixed at two fraction\n * digits, so abbreviated ticks always carry two decimals.\n *\n * Wired as a Highcharts `yAxis.labels.formatter`, invoked `this`-bound with the\n * Seeds-local context.\n */\nexport function defaultValueAxisLabelFormatter(\n this: SeedsAxisLabelFormatterContext\n): string {\n const numberValue = Number(this.value);\n\n if (numberValue === 0) {\n return formatNumeral({ locale: FIXED_LOCALE, number: 0 });\n }\n\n const abbreviate = deriveAbbreviateFromTicks(this);\n\n return formatNumeral({\n abbreviate,\n format: \"decimal\",\n locale: FIXED_LOCALE,\n number: numberValue,\n });\n}\n\n/**\n * Build a `format`-driven value-axis label formatter that runs a declarative\n * {@link ValueFormat} through the shared {@link valueFormatter}. Reuses the same\n * `tickPositions` scan as {@link defaultValueAxisLabelFormatter} so the\n * axis-wide \"smart 1k/10k\" abbreviation is preserved for decimal/currency ticks.\n *\n * Wired as a Highcharts `yAxis.labels.formatter`; invoked `this`-bound with the\n * Seeds-local context. The returned formatter never carries chart-engine types,\n * keeping the engine boundary intact.\n */\nexport function makeValueAxisLabelFormatter(format: ValueFormat) {\n return function (this: SeedsAxisLabelFormatterContext): string {\n const numberValue = Number(this.value);\n\n // Honor an explicit `abbreviate: false` opt-out; otherwise derive the\n // threshold from the same tick scan as the default formatter (abbreviation\n // only affects decimal/currency — percent and duration ignore it inside\n // valueFormatter).\n const abbreviate =\n format.abbreviate === false ? false : deriveAbbreviateFromTicks(this);\n\n return valueFormatter({ ...format, value: numberValue, abbreviate });\n };\n}\n"]}
@@ -965,4 +965,4 @@ var ChartLegendLabelContentWithIcon = _react.memo.call(void 0,
965
965
 
966
966
 
967
967
  exports.ColorBox = ColorBox; exports.DatavizColorBox = DatavizColorBox; exports.getDatavizColor = getDatavizColor; exports.getDatavizOpacity = getDatavizOpacity; exports.getDatavizColorWithAlpha = getDatavizColorWithAlpha; exports.NetworkColorBox = NetworkColorBox; exports.ChartLegendLabel = ChartLegendLabel; exports.ChartLegend = ChartLegend; exports.ChartLegendLabelContentWithIcon = ChartLegendLabelContentWithIcon; exports.ChartTooltip = ChartTooltip; exports.ChartTooltipFooter = ChartTooltipFooter; exports.ChartTooltipHeader = ChartTooltipHeader; exports.generateChartTooltipPortalId = generateChartTooltipPortalId; exports.ChartTooltipPortal = ChartTooltipPortal; exports.ChartTable = ChartTable; exports.ChartTooltipTable = ChartTooltipTable; exports.ChartTooltipTitle = ChartTooltipTitle; exports.transformDataToSeries = transformDataToSeries; exports.transformTimeSeriesTooltipData = transformTimeSeriesTooltipData; exports.yAxisLabelFormatter = yAxisLabelFormatter; exports.xAxisLabelFormatter = xAxisLabelFormatter; exports.isHourlyTimeData = isHourlyTimeData; exports.isCategoricalHourData = isCategoricalHourData; exports.getStorybookCategoricalData = getStorybookCategoricalData; exports.getStorybookSparseTimelineData = getStorybookSparseTimelineData; exports.GlobalChartStyleOverrides = GlobalChartStyleOverrides; exports.baseChartStyles = baseChartStyles; exports.timeSeriesChartStyles = timeSeriesChartStyles; exports.lineChartStyles = lineChartStyles; exports.areaChartStyles = areaChartStyles; exports.donutChartStyles = donutChartStyles;
968
- //# sourceMappingURL=chunk-EEVKTTT3.js.map
968
+ //# sourceMappingURL=chunk-WEKDYQ4T.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-WEKDYQ4T.js","../src/components/ColorBox/ColorBox.tsx","../../seeds-react-theme-provider/src/index.tsx","../src/components/ColorBox/DatavizColorBox.tsx","../src/components/ColorBox/NetworkColorBox.tsx","../src/components/ChartLegend/components/ChartLegendLabel.tsx","../src/components/ChartLegend/ChartLegend.tsx","../src/components/ChartTooltip/ChartTooltip.tsx","../src/components/ChartTooltip/components/ChartTooltipFooter.tsx","../src/components/ChartTooltip/components/ChartTooltipHeader.tsx","../src/components/ChartTooltip/components/ChartTooltipPortal.tsx","../src/components/ChartTable/ChartTable.tsx","../src/components/ChartTooltip/components/ChartTooltipTable.tsx","../src/components/ChartTooltip/components/ChartTooltipTitle.tsx","../src/helpers/transformDataToSeries.ts","../src/helpers/transformTimeSeriesTooltipData.ts","../src/helpers/yAxisLabelFormatter.ts","../src/helpers/xAxisLabelFormatter.ts","../src/helpers/isHourlyTimeData.ts","../src/helpers/isCategoricalHourData.ts","../src/helpers/getStorybookRandomColor.ts","../src/helpers/getStorybookCategoricalData.ts","../src/helpers/getStorybookSparseTimelineData.ts","../src/styles/chartStyles.ts","../src/components/ChartLegend/components/ChartLegendLabelContentWithIcon.tsx"],"names":["jsx","props"],"mappings":"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","file":"/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/chunk-WEKDYQ4T.js","sourcesContent":[null,"import { css, type CSSProp } from \"styled-components\";\nimport { Box, type TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport ThemeProvider from \"@sproutsocial/seeds-react-theme-provider\";\nimport { type TypeSproutTheme } from \"@sproutsocial/seeds-react-theme\";\n\nexport type TypeColorBoxProps = TypeBoxProps;\n\n/**\n * ColorBox extends Box to apply basic styles.\n */\nexport const ColorBox = ({\n display = \"inline-block\",\n height = \"16px\",\n width = \"16px\",\n minWidth = width,\n borderRadius = \"400\",\n ...props\n}: TypeColorBoxProps) => {\n return (\n <Box\n {...props}\n display={display}\n height={height}\n width={width}\n minWidth={minWidth}\n borderRadius={borderRadius}\n css={\n css`\n cursor: ${(\n props: typeof ThemeProvider & {\n onClick: ((e: React.MouseEvent<HTMLElement>) => void) | void;\n }\n ) => (props?.onClick ? \"pointer\" : \"default\")};\n ` as CSSProp<TypeSproutTheme>\n }\n />\n );\n};\n","import * as React from \"react\";\nimport {\n ThemeProvider as BaseThemeProvider,\n createGlobalStyle,\n} from \"styled-components\";\nimport { theme } from \"@sproutsocial/seeds-react-theme\";\nimport type {\n TypeSproutTheme,\n TypeTheme,\n} from \"@sproutsocial/seeds-react-theme\";\n\n// We can append additional themes types here\ntype TypeAllThemes = TypeTheme | TypeSproutTheme;\n\ntype TypeProps = {\n readonly theme?: TypeAllThemes;\n readonly children?: React.ReactNode;\n};\n\n// CSS custom properties for token values that cannot be represented in SCSS maps\n// (e.g. radial-gradient + color-mix). These are injected here so styled-components\n// consumers get the values without needing to load the compiled SCSS theme CSS.\nconst GlobalTokenStyles = createGlobalStyle`\n :root {\n --color-container-bg-ai-generated: radial-gradient(\n circle at bottom left,\n color-mix(in srgb, #205bc3, transparent 80%) 0%,\n color-mix(in srgb, #6f5ed3, transparent 80%) 61%,\n color-mix(in srgb, #f282f5, transparent 80%) 100%\n ), #f3f4f4;\n }\n`;\n\nconst ThemeProvider = (props: TypeProps) => (\n <BaseThemeProvider {...props} theme={props.theme || theme}>\n <GlobalTokenStyles />\n {props.children}\n </BaseThemeProvider>\n);\n\nexport default ThemeProvider;\n","import type * as React from \"react\";\nimport styled from \"styled-components\";\nimport { theme } from \"@sproutsocial/seeds-react-theme\";\nimport { ColorBox, type TypeColorBoxProps } from \"./ColorBox\";\n\nexport type TypeDatavizColorBoxProps = Readonly<\n Partial<TypeColorBoxProps> & {\n colorIndex: number;\n }\n>;\nexport type TypeDatavizColorBox = (\n props: TypeDatavizColorBoxProps\n) => React.JSXElementConstructor<TypeDatavizColorBoxProps>;\n\n/**\n * DatavizColorBox extends ColorBox to set the background color from a rotation of <a href=\"https://seeds.sproutsocial.com/visual/dataviz#color-combinations-for-general-sprout-social-data-visualizations\">dataviz colors</a>.\n */\nexport const DatavizColorBox = styled(ColorBox).attrs(\n ({ colorIndex }: TypeDatavizColorBoxProps) => ({\n style: {\n background: getDatavizColor(colorIndex),\n opacity: getDatavizOpacity(colorIndex),\n },\n })\n)<TypeDatavizColorBoxProps>``;\n\nexport const getDatavizColor = (colorIndex: number): string =>\n theme.colors.DATAVIZ_COLORS_LIST[\n colorIndex % theme.colors.DATAVIZ_COLORS_LIST.length\n ] || \"\";\n\nexport const getDatavizOpacity = (colorIndex: number): number => {\n const opacitySteps = [1, 0.6, 0.4, 0.2];\n const opacityStep =\n Math.floor(colorIndex / theme.colors.DATAVIZ_COLORS_LIST.length) %\n opacitySteps.length;\n // @ts-expect-error - opacitySteps index access may be undefined under noUncheckedIndexedAccess\n return opacitySteps[opacityStep];\n};\n\n// information on 8 digit hex codes can be found here: https://css-tricks.com/8-digit-hex-codes/\nexport const getDatavizColorWithAlpha = (colorIndex: number): string => {\n const color = getDatavizColor(colorIndex);\n const opacity = getDatavizOpacity(colorIndex);\n\n // make sure the opacity is always between 0 and 1\n if (opacity < 0 || opacity > 1) {\n return color;\n }\n\n // sourced from https://stackoverflow.com/a/66143374\n return `${color}${Math.floor(opacity * 255)\n .toString(16)\n .padStart(2, \"0\")}`;\n};\n","import NETWORK_COLORS from \"@sproutsocial/seeds-networkcolor\";\n\nimport { ColorBox, type TypeColorBoxProps } from \"./ColorBox\";\n\n// $Keys<typeof NETWORK_COLORS>\ntype TypeNetworkColor =\n | \"NETWORK_COLOR_TWITTER\"\n | \"NETWORK_COLOR_TWITTER_LIKE\"\n | \"NETWORK_COLOR_FACEBOOK\"\n | \"NETWORK_COLOR_FACEBOOK_AUDIENCE_NETWORK\"\n | \"NETWORK_COLOR_LINKEDIN\"\n | \"NETWORK_COLOR_INSTAGRAM\"\n | \"NETWORK_COLOR_FEEDLY\"\n | \"NETWORK_COLOR_ANALYTICS\"\n | \"NETWORK_COLOR_YOUTUBE\"\n | \"NETWORK_COLOR_MESSENGER\"\n | \"NETWORK_COLOR_SNAPCHAT\"\n | \"NETWORK_COLOR_PINTEREST\"\n | \"NETWORK_COLOR_REDDIT\"\n | \"NETWORK_COLOR_TUMBLR\"\n | \"NETWORK_COLOR_GOOGLE_MY_BUSINESS\"\n | \"NETWORK_COLOR_TIKTOK\"\n | \"NETWORK_COLOR_TRIPADVISOR\"\n | \"NETWORK_COLOR_GLASSDOOR\"\n | \"NETWORK_COLOR_SALESFORCE\"\n | \"NETWORK_COLOR_ZENDESK\"\n | \"NETWORK_COLOR_HUBSPOT\"\n | \"NETWORK_COLOR_MICROSOFT_DYNAMICS\";\n\ntype TypeNetworkColorBoxProps = Readonly<\n TypeColorBoxProps & {\n networkColor: TypeNetworkColor;\n }\n>;\n\n/**\n * NetworkColorBox extends ColorBox to set the background color to a <a href=\"https://seeds.sproutsocial.com/visual/color#full-color-palette\">network color</a>.\n */\nexport const NetworkColorBox = ({\n networkColor,\n ...props\n}: TypeNetworkColorBoxProps) => {\n return <ColorBox {...props} bg={NETWORK_COLORS[networkColor]} />;\n};\n","import styled from \"styled-components\";\nimport { memo } from \"react\";\nimport { Box, type TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport { Text } from \"@sproutsocial/seeds-react-text\";\n\nimport type { TypeLegendLabel } from \"../ChartLegend\";\n\nimport { ColorBox } from \"../../ColorBox\";\n\nconst StyledBox = styled(Box)<TypeBoxProps>`\n list-style: none;\n display: flex;\n align-items: center;\n gap: ${({ theme }) => theme.space[300]};\n`;\n\nexport type TypeChartLegendLabelProps = Readonly<{\n children: TypeLegendLabel[\"content\"];\n color: TypeLegendLabel[\"color\"];\n // optional\n containerBoxProps?: TypeBoxProps;\n}>;\n\nexport const ChartLegendLabel = memo<TypeChartLegendLabelProps>(\n function ChartLegendLabel({\n children,\n color = \"#CCC\",\n containerBoxProps = {},\n }: TypeChartLegendLabelProps) {\n return (\n <StyledBox {...containerBoxProps}>\n <ColorBox bg={color} />\n <Text as=\"div\" fontSize={200} color=\"text.subtext\">\n {children}\n </Text>\n </StyledBox>\n );\n }\n);\n","import { memo } from \"react\";\nimport { Box, type TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\nimport { theme } from \"@sproutsocial/seeds-react-theme\";\n\nimport { ChartLegendLabel } from \"./components/ChartLegendLabel\";\n\nexport type TypeLegendLabel = Readonly<{\n content: React.ReactNode;\n color?: string;\n}>;\n\nexport type TypeChartLegendProps = Readonly<{\n legendLabels: ReadonlyArray<TypeLegendLabel>;\n // optional\n containerBoxProps?: TypeBoxProps;\n stacked?: boolean;\n}>;\n\nexport const ChartLegend = memo<TypeChartLegendProps>(function ChartLegend({\n legendLabels,\n containerBoxProps = {},\n stacked = false,\n}: TypeChartLegendProps) {\n return (\n <Box\n as=\"ul\"\n aria-hidden=\"true\"\n display=\"flex\"\n justifyContent=\"center\"\n flexDirection={stacked ? \"column\" : \"row\"}\n flexWrap=\"wrap\"\n columnGap={450}\n rowGap={200}\n m={0}\n p={0}\n {...containerBoxProps}\n >\n {legendLabels.map(({ color, content }, index) => (\n <ChartLegendLabel\n key={`chart-legend-label-${index}`}\n color={color || theme.colors.DATAVIZ_COLORS_LIST[index]}\n containerBoxProps={{ as: \"li\" }}\n >\n {content}\n </ChartLegendLabel>\n ))}\n </Box>\n );\n});\n","import { memo } from \"react\";\nimport styled from \"styled-components\";\nimport { Box } from \"@sproutsocial/seeds-react-box\";\n\n// styled components\nconst StyledBox = styled(Box)`\n .Icon,\n .logo {\n stroke: none;\n }\n`;\n\n// Chart Tooltip\ntype TypeChartTooltipProps = Readonly<{\n children: React.ReactNode;\n}>;\n\nexport const ChartTooltip = memo<TypeChartTooltipProps>(function ChartTooltip({\n children,\n}: TypeChartTooltipProps) {\n return (\n <StyledBox\n bg=\"container.background.base\"\n boxShadow=\"medium\"\n border={500}\n borderColor=\"container.border.base\"\n borderRadius={500}\n p={400}\n minWidth={285}\n >\n <Box display=\"flex\" flexDirection=\"column\" gap={350}>\n {children}\n </Box>\n </StyledBox>\n );\n});\n","import { memo } from \"react\";\nimport { Box } from \"@sproutsocial/seeds-react-box\";\n\ntype TypeChartTooltipFooterProps = {\n children: React.ReactNode;\n};\n\nexport const ChartTooltipFooter = memo<TypeChartTooltipFooterProps>(\n function ChartTooltipFooter({ children }: TypeChartTooltipFooterProps) {\n return (\n <Box\n borderTop={500}\n borderColor=\"container.border.base\"\n mx={-400}\n mb={-200}\n px={400}\n pt={350}\n >\n {children}\n </Box>\n );\n }\n);\n","import { memo } from \"react\";\nimport { Box } from \"@sproutsocial/seeds-react-box\";\n\ntype TypeChartTooltipHeaderProps = {\n children: React.ReactNode;\n};\n\nexport const ChartTooltipHeader = memo<TypeChartTooltipHeaderProps>(\n function ChartTooltipHeader({ children }: TypeChartTooltipHeaderProps) {\n return (\n <Box\n borderBottom={500}\n borderColor=\"container.border.base\"\n mx={-400}\n mt={-200}\n px={400}\n pb={350}\n >\n {children}\n </Box>\n );\n }\n);\n","import { memo, useState, useRef, useEffect, type ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport type {\n Tooltip,\n Chart,\n TooltipFormatterContextObject,\n TooltipFormatterCallbackFunction,\n} from \"highcharts\";\n\ninterface ExtendedHighchartsTooltip extends Tooltip {\n label: {\n box: { attr({ height, width }: { height: number; width: number }): void };\n text: { element: HTMLElement };\n };\n}\n\nexport const generateChartTooltipPortalId = (chartId: number) =>\n `highcharts-custom-tooltip-${chartId}`;\n\ntype ChartTooltipPortalProps = Readonly<{\n chart: Chart;\n renderContent: (_context: TooltipFormatterContextObject) => ReactNode;\n}>;\n\nexport const ChartTooltipPortal = memo<ChartTooltipPortalProps>(\n function ChartTooltipPortal({\n chart,\n renderContent,\n }: ChartTooltipPortalProps) {\n const isInitialized = useRef<boolean>(false);\n const [node, setNode] = useState<HTMLElement | null>(null);\n const [context, setContext] =\n useState<TooltipFormatterContextObject | null>(null);\n\n useEffect(() => {\n const formatter: TooltipFormatterCallbackFunction = function () {\n // Ensures that tooltip DOM container is rendered before React portal is created.\n if (!isInitialized.current) {\n isInitialized.current = true;\n chart.tooltip.refresh.apply(chart.tooltip, [this.point]);\n chart.tooltip.hide(0);\n }\n\n setContext(this);\n\n return `<div id=\"${generateChartTooltipPortalId(\n chart.index\n )}\" role='tooltip'></div>`;\n };\n\n chart.update({ tooltip: { formatter } });\n }, [chart]);\n\n useEffect(() => {\n // In some cases tooltip is not available on the chart yet\n if (context?.series?.chart?.tooltip) {\n const tooltip = context.series.chart\n .tooltip as ExtendedHighchartsTooltip;\n const textElement = tooltip.label.text.element;\n\n tooltip.label.box.attr({\n height: textElement.offsetHeight,\n width: textElement.offsetWidth,\n });\n\n setNode(\n document.getElementById(generateChartTooltipPortalId(chart.index))\n );\n }\n }, [context, chart.index]);\n\n return node && context ? createPortal(renderContent(context), node) : null;\n }\n);\n","import { memo } from \"react\";\nimport styled from \"styled-components\";\nimport { Text } from \"@sproutsocial/seeds-react-text\";\nimport { Table as SeedsTable } from \"@sproutsocial/seeds-react-table\";\n\nconst StyledSeedsTable = styled<typeof SeedsTable>(SeedsTable)`\n tbody tr:last-child {\n border-bottom: none;\n }\n tr:last-child td,\n tr:last-child th {\n padding-bottom: 0;\n }\n tr:first-child td,\n tr:first-child th {\n padding-top: 0;\n }\n tr th {\n padding-left: 0;\n }\n tr td:last-child {\n padding-right: 0;\n }\n`;\n\nconst StyledSeedsTableRow = styled(SeedsTable.TableRow)<{\n $isAppendedRow?: boolean;\n}>`\n ${({ $isAppendedRow, theme }) =>\n $isAppendedRow\n ? `border-top: 2px solid ${theme.colors.container.border.base}`\n : \"\"}\n`;\n\nexport type TypeChartTableProps = Readonly<{\n rows: ReadonlyArray<{\n cells: ReadonlyArray<{\n content: React.ReactNode;\n align?: React.ComponentProps<typeof SeedsTable.Cell>[\"align\"];\n colSpan?: React.ComponentProps<typeof SeedsTable.Cell>[\"colSpan\"];\n }>;\n isAppendedRow?: boolean;\n }>;\n}>;\n\nexport const ChartTable = memo<TypeChartTableProps>(function ChartTable({\n rows,\n}: TypeChartTableProps) {\n if (!rows || rows.length === 0) {\n return null;\n }\n\n return (\n <StyledSeedsTable>\n <SeedsTable.TableBody>\n {rows.map(({ cells, isAppendedRow }, rowIndex) => {\n if (!cells || cells.length === 0) {\n return null;\n }\n\n return (\n <StyledSeedsTableRow\n key={`chart-tooltip-table-row-${rowIndex}`}\n $isAppendedRow={isAppendedRow}\n >\n {cells.map(\n ({ content, align = \"left\", colSpan = 1 }, cellIndex) => {\n const uniqueIdentifier = `chart-tooltip-table-cell-${cellIndex}`;\n return (\n <SeedsTable.Cell\n key={uniqueIdentifier}\n id={uniqueIdentifier}\n scope={cellIndex === 0 ? \"row\" : undefined}\n align={align}\n colSpan={colSpan}\n py={200}\n >\n <Text.SmallBodyCopy as=\"div\">\n {content}\n </Text.SmallBodyCopy>\n </SeedsTable.Cell>\n );\n }\n )}\n </StyledSeedsTableRow>\n );\n })}\n </SeedsTable.TableBody>\n </StyledSeedsTable>\n );\n});\n","import { memo } from \"react\";\n\nimport { ChartTable, type TypeChartTableProps } from \"../../ChartTable\";\n\nexport type TypeChartTooltipTableProps = {\n rows: TypeChartTableProps[\"rows\"];\n};\n\nexport const ChartTooltipTable = memo<TypeChartTooltipTableProps>(\n function ChartTooltipTable({ rows }: TypeChartTooltipTableProps) {\n return <ChartTable rows={rows} />;\n }\n);\n","import { memo } from \"react\";\nimport { Text } from \"@sproutsocial/seeds-react-text\";\n\ntype TypeChartTooltipTitleProps = {\n children: React.ReactNode;\n};\n\nexport const ChartTooltipTitle = memo<TypeChartTooltipTitleProps>(\n function ChartTooltipTitle({ children }: TypeChartTooltipTitleProps) {\n return <Text.SmallSubHeadline as=\"p\">{children}</Text.SmallSubHeadline>;\n }\n);\n","import type {\n SeriesSplineOptions,\n SeriesAreasplineOptions,\n SeriesColumnOptions,\n} from \"highcharts\";\n\nimport type { TypeAreaChartProps } from \"../components/AreaChart\";\nimport type { TypeLineChartProps } from \"../components/LineChart\";\nimport type { TypeVerticalBarChartProps, TypeSeriesType } from \"../types\";\n\ntype TypeTimeSeriesOptions =\n | SeriesSplineOptions\n | SeriesAreasplineOptions\n | SeriesColumnOptions;\n\n// returns a transformed set of data to series with some logic for handling null values\nexport const transformDataToSeries = (\n {\n data,\n }: {\n data:\n | TypeAreaChartProps[\"data\"]\n | TypeLineChartProps[\"data\"]\n | TypeVerticalBarChartProps[\"data\"];\n },\n type: TypeSeriesType\n): TypeTimeSeriesOptions[] => {\n // Check if we have categorical data (string x values)\n const hasCategoricalData = data.some((series) =>\n series.points.some((point) => typeof point.x === \"string\")\n );\n\n return data.map((dataItem, dataIndex) => {\n const points = dataItem.points || [];\n const dataPoints = points.map((point, pointsIndex) => {\n let enableMarker = false;\n const isFirstPoint = pointsIndex === 0;\n const isLastPoint = pointsIndex === points.length - 1;\n\n // @ts-expect-error - points[index] may be undefined under noUncheckedIndexedAccess; guarded by isFirstPoint\n const previousY = isFirstPoint ? null : points[pointsIndex - 1].y;\n // @ts-expect-error - points[index] may be undefined under noUncheckedIndexedAccess; guarded by isLastPoint\n const nextY = isLastPoint ? null : points[pointsIndex + 1].y;\n\n if (isFirstPoint && nextY === null) {\n // if the first point has data and the second point is null, show a marker for the first point\n enableMarker = true;\n } else if (isLastPoint && previousY === null) {\n // if the last point has data and the second to last point is null, show a marker for the last point\n enableMarker = true;\n } else if (previousY === null && nextY === null) {\n // if the a point has null values on both sides, show a marker\n enableMarker = true;\n }\n\n return {\n x: hasCategoricalData ? pointsIndex : point.x,\n y: point.y,\n marker: {\n enabled: enableMarker ? enableMarker : undefined,\n symbol: enableMarker ? \"circle\" : undefined,\n },\n // For categorical data, store the original category name\n ...(hasCategoricalData && { name: point.x }),\n };\n });\n\n return {\n colorIndex: dataIndex,\n data: dataPoints as TypeTimeSeriesOptions[\"data\"],\n name: dataItem.name as TypeTimeSeriesOptions[\"name\"],\n type: type,\n };\n });\n};\n","import type { TooltipFormatterContextObject } from \"highcharts\";\nimport { theme } from \"@sproutsocial/seeds-react-theme\";\n\nimport type { TypeAreaChartProps } from \"../components/AreaChart\";\nimport type { TypeLineChartProps } from \"../components/LineChart\";\nimport type { TypeChartTooltipProps } from \"../types\";\n\ntype TypeTransformTimeSeriesTooltipDataProps = Readonly<{\n context: TooltipFormatterContextObject;\n data: TypeAreaChartProps[\"data\"] | TypeLineChartProps[\"data\"];\n}>;\ntype TypeTransformTimeSeriesTooltipDataReturn = TypeChartTooltipProps[\"data\"];\n\nexport const transformTimeSeriesTooltipData = ({\n context,\n data,\n}: TypeTransformTimeSeriesTooltipDataProps): TypeTransformTimeSeriesTooltipDataReturn => {\n // @ts-expect-error - Highcharts tooltip context series typing does not expose chart.series here\n return (context.series.chart.series || []).map((series, index) => {\n const pointIndex = context.point.index;\n const y = series?.points?.[pointIndex]?.y;\n\n return {\n color:\n data[index]?.styles?.color || theme.colors.DATAVIZ_COLORS_LIST[index],\n ...(data[index]?.icon ? { icon: data[index]?.icon } : {}),\n name: series.name,\n value: typeof y === \"number\" ? y : null,\n };\n });\n};\n","import type {\n AxisLabelsFormatterContextObject,\n AxisTickPositionsArray,\n} from \"highcharts\";\nimport { formatDuration } from \"@sproutsocial/seeds-react-duration\";\nimport { formatNumeral } from \"@sproutsocial/seeds-react-numeral\";\n\nimport type { TypeChartNumberFormat } from \"../types\";\n\ntype TypeYAxisLabelFormatterProps = Readonly<{\n numberLocale: Intl.LocalesArgument;\n textLocale: Intl.LocalesArgument;\n tickPositions: AxisTickPositionsArray;\n value: AxisLabelsFormatterContextObject[\"value\"];\n // optional\n currency?: string;\n numberFormat?: TypeChartNumberFormat;\n}>;\n\nexport const yAxisLabelFormatter = ({\n numberLocale,\n textLocale,\n tickPositions,\n value,\n currency = \"USD\",\n numberFormat = \"decimal\",\n}: TypeYAxisLabelFormatterProps): string => {\n const numberValue = Number(value);\n\n if (numberValue === 0) {\n return formatNumeral({\n locale: numberLocale as string,\n number: numberValue,\n });\n }\n\n if (numberFormat === \"duration\") {\n return formatDuration({\n display: \"narrow\",\n locale: textLocale,\n milliseconds: numberValue,\n });\n }\n\n // Seeds formatNumeral helper starts abbreviating numbers above 10,000. this maxValue logic\n // helps bring that threshold down to 1,000 if the last tick on the y axis is greater than 9,999\n // so we render \"2k 4k 6k 8k 10k\" instead of \"2,000 4,000 6,000 8,000 10k\"\n const maxValue =\n tickPositions && tickPositions.length > 0\n ? tickPositions[tickPositions.length - 1]\n : undefined;\n const abbreviate =\n typeof maxValue === \"number\" && maxValue > 9999 ? 1000 : true;\n\n return formatNumeral({\n abbreviate,\n currency,\n format: numberFormat,\n locale: numberLocale as string,\n number: numberValue,\n });\n};\n","import type {\n AxisLabelsFormatterContextObject,\n AxisTickPositionsArray,\n} from \"highcharts\";\n\nimport type {\n ExtendedTimeTicksInfoObject,\n TypeChartTimeFormat,\n} from \"../types\";\n\nconst getDatePartsInTimezone = (date: Date, timezone: string) => {\n const formatter = new Intl.DateTimeFormat(\"en-US\", {\n year: \"numeric\",\n month: \"numeric\",\n day: \"numeric\",\n timeZone: timezone,\n });\n const parts = formatter.formatToParts(date);\n return {\n day: parseInt(parts.find((p) => p.type === \"day\")?.value ?? \"0\", 10),\n month: parseInt(parts.find((p) => p.type === \"month\")?.value ?? \"0\", 10),\n year: parseInt(parts.find((p) => p.type === \"year\")?.value ?? \"0\", 10),\n };\n};\n\ntype TypeXAxisLabelFormatterProps = Readonly<{\n textLocale: Intl.LocalesArgument;\n tickPositions: AxisTickPositionsArray;\n unitName: ExtendedTimeTicksInfoObject[\"unitName\"];\n value: AxisLabelsFormatterContextObject[\"value\"];\n // optional\n timeFormat?: TypeChartTimeFormat;\n timezone?: string;\n}>;\n\nexport const xAxisLabelFormatter = ({\n textLocale,\n tickPositions = [],\n unitName,\n value,\n // optional\n timeFormat = \"12\",\n timezone = \"UTC\",\n}: TypeXAxisLabelFormatterProps): string => {\n // Handle categorical (string) data\n if (typeof value === \"string\") {\n return `<span>${value}</span>`;\n }\n const tickIndex = tickPositions.indexOf(value as number);\n const isFirst = tickIndex === 0;\n const previousValue = tickPositions[tickIndex - 1];\n\n const valueDate = new Date(value);\n const valueParts = getDatePartsInTimezone(valueDate, timezone);\n const previousValueDate = previousValue ? new Date(previousValue) : undefined;\n const previousValueParts = previousValueDate\n ? getDatePartsInTimezone(previousValueDate, timezone)\n : undefined;\n\n let firstPartOptions = {};\n let secondPartOptions = {};\n\n switch (unitName) {\n case \"hour\":\n firstPartOptions =\n timeFormat === \"24\"\n ? { hour: \"numeric\", minute: \"numeric\", hour12: false }\n : { hour: \"numeric\" };\n if (isFirst || valueParts.day !== previousValueParts?.day) {\n secondPartOptions = { day: \"numeric\", month: \"short\" };\n }\n break;\n case \"day\":\n case \"week\":\n firstPartOptions = { day: \"numeric\" };\n if (isFirst || valueParts.month !== previousValueParts?.month) {\n secondPartOptions = { month: \"short\" };\n }\n break;\n case \"month\":\n firstPartOptions = { month: \"short\" };\n if (isFirst || valueParts.year !== previousValueParts?.year) {\n secondPartOptions = { year: \"numeric\" };\n }\n break;\n case \"year\":\n firstPartOptions = { year: \"numeric\" };\n break;\n default:\n firstPartOptions = {};\n break;\n }\n\n const firstPart = new Intl.DateTimeFormat(textLocale, {\n ...firstPartOptions,\n timeZone: timezone,\n }).format(valueDate);\n const secondPart =\n Object.keys(secondPartOptions).length > 0\n ? new Intl.DateTimeFormat(textLocale, {\n ...secondPartOptions,\n timeZone: timezone,\n }).format(valueDate)\n : undefined;\n\n return `<span>${firstPart}</span>${\n secondPart ? `<span>${secondPart}</span>` : \"\"\n }`;\n};\n","/**\n * Helper to detect if data is hourly time data (all x values are hours of the same day)\n * @param data - Array of series data with points containing x values\n * @returns boolean indicating if all x values are hours of the same day\n * @deprecated Auto-detection of hourly data is deprecated. v2 is declarative:\n * use `xAxis={{ type: \"datetime\", timeFormat: \"12\" | \"24\" }}` + a top-level\n * `timezone` instead of relying on implicit detection. See\n * `seeds-tooling/seeds-codemod-cli/src/usage-patterns/VERTICALBARCHARTV1_PATTERNS.md`\n * (CE-8).\n */\nexport function isHourlyTimeData(\n data: ReadonlyArray<\n Readonly<{ points: ReadonlyArray<{ x: number | string }> }>\n >\n): boolean {\n // Return false if there is no data.\n if (!data.length) return false;\n\n // Flatten all data points into a single array of x values.\n const xVals = data.flatMap((series) => series.points.map((p) => p.x));\n\n // Return false if there are no x values.\n if (!xVals.length) return false;\n\n // Return false if any x values are strings (categorical data)\n if (xVals.some((x) => typeof x === \"string\")) return false;\n\n // Check if all x values are on the same calendar date.\n // We do this by converting each timestamp to a YYYY-MM-DD string and checking if there's only one unique date string.\n const dates = (xVals as number[]).map((x) => {\n const d = new Date(x);\n return `${d.getUTCFullYear()}-${d.getUTCMonth()}-${d.getUTCDate()}`;\n });\n const uniqueDates = new Set(dates);\n if (uniqueDates.size !== 1) return false;\n\n // Check if all x values are exactly on the hour (e.g., 2:00:00, not 2:00:01).\n // We also check that the hour is within the valid 0-23 range.\n return (xVals as number[]).every((x) => {\n const d = new Date(x);\n const hour = d.getUTCHours();\n const minutes = d.getUTCMinutes();\n const seconds = d.getUTCSeconds();\n return hour >= 0 && hour <= 23 && minutes === 0 && seconds === 0;\n });\n}\n","/**\n * Helper to detect if data is categorical hour data (all x values are hour strings)\n * Supports both 12-hour format (\"12 AM\", \"1 PM\") and 24-hour format (\"00:00\", \"13:00\", \"23:00\")\n * @param data - Array of series data with points containing x values\n * @returns boolean indicating if all x values are hour strings\n * @deprecated Auto-detection of hourly data is deprecated. v2 is declarative:\n * use `xAxis={{ type: \"datetime\", timeFormat: \"12\" | \"24\" }}` + a top-level\n * `timezone` instead of relying on implicit detection. See\n * `seeds-tooling/seeds-codemod-cli/src/usage-patterns/VERTICALBARCHARTV1_PATTERNS.md`\n * (CE-8).\n */\nexport function isCategoricalHourData(\n data: ReadonlyArray<\n Readonly<{ points: ReadonlyArray<{ x: number | string }> }>\n >\n): boolean {\n // Return false if there is no data.\n if (!data.length) return false;\n\n // Flatten all data points into a single array of x values.\n const xVals = data.flatMap((series) => series.points.map((p) => p.x));\n\n // Return false if there are no x values.\n if (!xVals.length) return false;\n\n // Return false if any x values are not strings (numerical data)\n if (xVals.some((x) => typeof x !== \"string\")) return false;\n\n // Check if all x values match either 12-hour or 24-hour format patterns\n const hour12Pattern = /^\\d{1,2} (AM|PM)$/; // \"12 AM\", \"1 PM\", \"10 AM\"\n const hour24Pattern = /^([01]?\\d|2[0-3]):([0-5]\\d)$/; // \"00:00\", \"13:00\", \"23:59\"\n\n const stringValues = xVals as string[];\n\n // Check if all values match 12-hour format\n const allMatch12Hour = stringValues.every((x) => hour12Pattern.test(x));\n\n // Check if all values match 24-hour format\n const allMatch24Hour = stringValues.every((x) => hour24Pattern.test(x));\n\n return allMatch12Hour || allMatch24Hour;\n}\n","export const getStorybookRandomColor = (): string => {\n const letters = \"0123456789ABCDEF\";\n let color = \"#\";\n for (let i = 0; i < 6; i++) {\n color += letters[Math.floor(Math.random() * 16)];\n }\n return color;\n};\n","import { getStorybookRandomColor } from \"./getStorybookRandomColor\";\n\nexport const getStorybookCategoricalData = ({\n showNulls,\n showNegativeValues,\n numberOfSeries,\n yAxisMax,\n showCustomColors,\n showDashedLines,\n categoryType,\n}: {\n showNulls: boolean;\n showNegativeValues: boolean;\n numberOfSeries: number;\n yAxisMax: number;\n showCustomColors: boolean;\n showDashedLines: boolean;\n categoryType: \"hours\" | \"hours24\" | \"days\" | \"months\" | \"custom\";\n}) => {\n // Define different category sets\n const categoryOptions = {\n hours: [\n \"12 AM\",\n \"1 AM\",\n \"2 AM\",\n \"3 AM\",\n \"4 AM\",\n \"5 AM\",\n \"6 AM\",\n \"7 AM\",\n \"8 AM\",\n \"9 AM\",\n \"10 AM\",\n \"11 AM\",\n \"12 PM\",\n \"1 PM\",\n \"2 PM\",\n \"3 PM\",\n \"4 PM\",\n \"5 PM\",\n \"6 PM\",\n \"7 PM\",\n \"8 PM\",\n \"9 PM\",\n \"10 PM\",\n \"11 PM\",\n ],\n hours24: [\n \"00:00\",\n \"01:00\",\n \"02:00\",\n \"03:00\",\n \"04:00\",\n \"05:00\",\n \"06:00\",\n \"07:00\",\n \"08:00\",\n \"09:00\",\n \"10:00\",\n \"11:00\",\n \"12:00\",\n \"13:00\",\n \"14:00\",\n \"15:00\",\n \"16:00\",\n \"17:00\",\n \"18:00\",\n \"19:00\",\n \"20:00\",\n \"21:00\",\n \"22:00\",\n \"23:00\",\n ],\n days: [\n \"Monday\",\n \"Tuesday\",\n \"Wednesday\",\n \"Thursday\",\n \"Friday\",\n \"Saturday\",\n \"Sunday\",\n ],\n months: [\n \"January\",\n \"February\",\n \"March\",\n \"April\",\n \"May\",\n \"June\",\n \"July\",\n \"August\",\n \"September\",\n \"October\",\n \"November\",\n \"December\",\n ],\n custom: [\n \"Category A\",\n \"Category B\",\n \"Category C\",\n \"Category D\",\n \"Category E\",\n ],\n };\n\n const categories = categoryOptions[categoryType];\n const numberOfPoints = categories.length;\n\n return [...Array(numberOfSeries).keys()].map((seriesIndex) => {\n let nullsArray: ReadonlyArray<number> = [];\n\n if (showNulls) {\n const nullsArrayLength = Math.floor(numberOfPoints / 5);\n nullsArray = [...Array(nullsArrayLength)].map(() =>\n Math.floor(Math.random() * numberOfPoints)\n );\n }\n\n return {\n points: categories.map((category, pointIndex) => {\n const showNull =\n nullsArray && nullsArray.length > 0\n ? nullsArray.includes(pointIndex)\n : false;\n const randomValue = Math.random();\n const positiveOrNegativeYAxisMax = showNegativeValues\n ? randomValue < 0.5\n ? -yAxisMax\n : yAxisMax\n : yAxisMax;\n\n return {\n x: category,\n y: showNull\n ? null\n : Math.floor(randomValue * positiveOrNegativeYAxisMax),\n };\n }),\n name: `Series ${seriesIndex + 1}`,\n styles: {\n color: showCustomColors ? getStorybookRandomColor() : undefined,\n pattern: showDashedLines ? \"dashed\" : \"solid\",\n },\n };\n });\n};\n","import { getStorybookRandomColor } from \"./getStorybookRandomColor\";\n\nexport const getStorybookSparseTimelineData = ({\n showNulls,\n showNegativeValues,\n numberOfSeries,\n yAxisMax,\n showCustomColors,\n showDashedLines,\n numberOfPoints = 5,\n timeSpanHours = 24,\n}: {\n showNulls: boolean;\n showNegativeValues: boolean;\n numberOfSeries: number;\n yAxisMax: number;\n showCustomColors: boolean;\n showDashedLines: boolean;\n numberOfPoints?: number;\n timeSpanHours?: number;\n}) => {\n const seriesNames = [\n \"Posts Published\",\n \"Comments\",\n \"Likes\",\n \"Shares\",\n \"Clicks\",\n \"Views\",\n \"Saves\",\n \"Reposts\",\n \"Mentions\",\n \"Reactions\",\n ];\n\n const baseDate = new Date(\"2024-01-01T00:00:00Z\");\n const timeSpanMs = timeSpanHours * 60 * 60 * 1000;\n\n return [...Array(numberOfSeries).keys()].map((seriesIndex) => {\n let nullsArray: ReadonlyArray<number> = [];\n\n if (showNulls) {\n const nullsArrayLength = Math.floor(numberOfPoints / 5);\n nullsArray = [...Array(nullsArrayLength)].map(() =>\n Math.floor(Math.random() * numberOfPoints)\n );\n }\n\n // Generate random timestamps for this series\n const timestamps = [...Array(numberOfPoints)]\n .map(() => {\n const randomOffset = Math.random() * timeSpanMs;\n return baseDate.getTime() + randomOffset;\n })\n .sort((a, b) => a - b); // Sort chronologically\n\n return {\n points: timestamps.map((timestamp, pointIndex) => {\n const showNull =\n nullsArray && nullsArray.length > 0\n ? nullsArray.includes(pointIndex)\n : false;\n const randomValue = Math.random();\n const positiveOrNegativeYAxisMax = showNegativeValues\n ? randomValue < 0.5\n ? -yAxisMax\n : yAxisMax\n : yAxisMax;\n\n return {\n x: timestamp,\n y: showNull\n ? null\n : Math.floor(randomValue * positiveOrNegativeYAxisMax),\n };\n }),\n name: seriesNames[seriesIndex] || `Series ${seriesIndex + 1}`,\n styles: {\n color: showCustomColors ? getStorybookRandomColor() : undefined,\n pattern: showDashedLines ? \"dashed\" : \"solid\",\n },\n };\n });\n};\n","import { css, createGlobalStyle } from \"styled-components\";\nimport { theme } from \"@sproutsocial/seeds-react-theme\";\nimport {\n type TypeChartStyleColor,\n type TypeChartStyleHasOnClick,\n type TypeChartStylePattern,\n} from \"../types\";\nimport \"highcharts/css/highcharts.css\";\n\nexport const GlobalChartStyleOverrides = createGlobalStyle`\n // USAGE NOTE:\n // Put general styles in baseChartStyles instead when possible to avoid excessive global styling.\n // This global component is only for styles that can't override highcharts defaults when scoped.\n\n .highcharts-tooltip-container {\n z-index: 7 !important;\n }\n .highcharts-tooltip-box {\n fill: transparent !important;\n }\n`;\n\n// options that should apply to all charts\nexport const baseChartStyles = css<\n Readonly<{ $colors: ReadonlyArray<TypeChartStyleColor> }>\n>`\n --highcharts-background-color: ${({ theme }) =>\n theme.colors.container.background.base};\n\n // set color variables and map to each series\n ${({ $colors }) =>\n $colors\n .map((color, index) => {\n const chartColor = color || theme.colors.DATAVIZ_COLORS_LIST[index];\n return `\n\t\t\t\t// map colors to custom assigned colors or fallback to default data viz color rotation\n\t\t\t\t--highcharts-color-${index}: ${chartColor};\n\n\t\t\t\t// highcharts already accounts for 10 series, but if we have more, we need to add them\n\t\t\t\t.highcharts-color-${index} {\n\t\t\t\t\tcolor: var(--highcharts-color-${index});\n\t\t\t\t\tstroke: var(--highcharts-color-${index});\n\t\t\t\t\tfill: var(--highcharts-color-${index});\n\t\t\t\t}`;\n })\n .join(\"\\n\")}\n\n // set overall chart background color\n .highcharts-background {\n fill: ${({ theme }) => theme.colors.container.background.base};\n }\n\n g.highcharts-annotation-label {\n display: none;\n }\n\n div.highcharts-annotation-label {\n top: 0 !important;\n transform: translateX(-50%); // centers the label on the targeted axis point\n pointer-events: none; // prevents tooltip hover from being interrupted by this element since it renders after on the dom\n }\n`;\n\n// options that should apply to time series charts\nexport const timeSeriesChartStyles = css<\n Readonly<{\n $colors: ReadonlyArray<TypeChartStyleColor>;\n $hasOnClick: TypeChartStyleHasOnClick;\n }>\n>`\n ${baseChartStyles}\n\n // vertical crosshair styles\n\t.highcharts-crosshair {\n stroke: ${({ theme }) => theme.colors.container.border.decorative.neutral};\n stroke-width: 1;\n }\n\n // axis and gridline styles\n .highcharts-grid-line {\n stroke: ${({ theme }) => theme.colors.container.border.base};\n }\n\n .highcharts-axis-line {\n stroke: ${({ theme }) => theme.colors.container.border.base};\n }\n\n .highcharts-tick {\n stroke: none;\n }\n .highcharts-xaxis-labels,\n .highcharts-yaxis-labels {\n // v1 HTML labels (useHTML: true). v2 SVG label styles live in\n // charts/shared/styles.ts (axisLabelV2Styles) — don't add v2 rules here.\n > span {\n font-family: ${({ theme }) => theme.fontFamily};\n ${({ theme }) => theme.typography[100]};\n font-weight: ${({ theme }) => theme.fontWeights.normal};\n color: ${({ theme }) => theme.colors.text.subtext};\n }\n }\n .highcharts-xaxis-labels {\n // v1 HTML stacked labels (useHTML: true). v2 SVG stacked-label styles live\n // in charts/shared/styles.ts (axisLabelV2Styles).\n > span {\n display: flex;\n flex-direction: column;\n align-items: center;\n > span:nth-of-type(2) {\n font-weight: ${({ theme }) => theme.fontWeights.semibold};\n }\n }\n }\n\n // we don't want to drop the opacity when another item is hovered\n .highcharts-series-inactive {\n opacity: 1;\n }\n\n // apply cursor pointer when click functionality is turned on\n ${({ $hasOnClick }) =>\n $hasOnClick &&\n `\n \t\t\t.highcharts-series,\n \t\t\t.highcharts-point {\n \t\t\t\tcursor: pointer;\n \t\t\t}\n \t\t\t.highcharts-plot-background,\n \t\t\t.highcharts-crosshair,\n \t\t\t.highcharts-grid-line {\n \t\t\t\tfill: transparent;\n \t\t\t\tcursor: pointer;\n \t\t}`}\n\n path.highcharts-plot-line.y-axis-zero-line {\n stroke: ${({ theme }) => theme.colors.container.border.decorative.neutral};\n }\n`;\n\n// options that should apply to line charts\nexport const lineChartStyles = css<\n Readonly<{\n $colors: ReadonlyArray<TypeChartStyleColor>;\n $patterns: ReadonlyArray<TypeChartStylePattern>;\n $hasOnClick: TypeChartStyleHasOnClick;\n }>\n>`\n ${timeSeriesChartStyles}\n\n // set the line stroke\n\t.highcharts-graph {\n stroke-width: 3;\n }\n\n // dashed line styles\n ${({ $patterns }) =>\n $patterns.map((pattern, index) => {\n return pattern === \"dashed\"\n ? `\n \t\t\t\t\t// highcharts already accounts for 10 series, but if we have more, we need to add them\n \t\t\t\t\t.highcharts-series-${index} {\n \t\t\t\t\t\tstroke-dasharray: 2, 8;\n \t\t\t\t\t}`\n : \"\";\n })}\n`;\n\n// options that should apply to area charts\nexport const areaChartStyles = css`\n ${timeSeriesChartStyles}\n\n // don't need to show a stroke for the line part of each area\n\t.highcharts-graph {\n stroke-width: 0;\n }\n\n // fill areas to full opacity\n .highcharts-area {\n fill-opacity: 1;\n }\n`;\n\n// options that should apply to donut charts\nexport const donutChartStyles = css<\n Readonly<{\n $colors: ReadonlyArray<TypeChartStyleColor>;\n $hasOnClick: TypeChartStyleHasOnClick;\n }>\n>`\n ${baseChartStyles}\n\n // remove 250ms fade in/out when hovering over different donut chart slices\n\t.highcharts-point {\n transition: opacity 0s;\n }\n\n // remove stroke on donut slices\n .highcharts-pie-series .highcharts-point {\n stroke: none;\n }\n\n // don't reduce opacity when hovering\n .highcharts-point-hover {\n fill-opacity: none;\n }\n\n // apply cursor pointer when click functionality is turned on\n ${({ $hasOnClick }) =>\n $hasOnClick &&\n `\n \t\t\t.highcharts-series,\n \t\t\t.highcharts-point {\n \t\t\t\tcursor: pointer;\n \t\t\t}\n \t\t\t.highcharts-plot-background,\n \t\t\t.highcharts-crosshair,\n \t\t\t.highcharts-grid-line {\n \t\t\t\tfill: transparent;\n \t\t\t\tcursor: pointer;\n \t\t}`}\n`;\n","import { memo } from \"react\";\nimport { Box } from \"@sproutsocial/seeds-react-box\";\n\nexport type TypeChartLegendLabelContentWithIconProps = Readonly<{\n children: React.ReactNode;\n // optional\n icon?: React.ReactNode;\n}>;\n\nexport const ChartLegendLabelContentWithIcon =\n memo<TypeChartLegendLabelContentWithIconProps>(\n function ChartLegendLabelContentWithIcon({\n children,\n icon,\n }: TypeChartLegendLabelContentWithIconProps) {\n return icon ? (\n <Box display=\"flex\" alignItems=\"center\" gap={200}>\n {icon}\n {children}\n </Box>\n ) : (\n children\n );\n }\n );\n"]}