@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.
- package/dist/axis-DXzufRRj.d.mts +116 -0
- package/dist/axis-PJwu5Xmo.d.ts +116 -0
- package/dist/bar/index.d.mts +16 -156
- package/dist/bar/index.d.ts +16 -156
- package/dist/bar/index.js +97 -823
- package/dist/bar/index.js.map +1 -1
- package/dist/{chunk-VFBZ7FNK.js → chunk-EEVKTTT3.js} +13 -199
- package/dist/chunk-EEVKTTT3.js.map +1 -0
- package/dist/chunk-XVV7PYQE.js +796 -0
- package/dist/chunk-XVV7PYQE.js.map +1 -0
- package/dist/esm/bar/index.js +99 -825
- package/dist/esm/bar/index.js.map +1 -1
- package/dist/esm/{chunk-CDBW4SOR.js → chunk-LC3HGWDD.js} +2 -188
- package/dist/esm/chunk-LC3HGWDD.js.map +1 -0
- package/dist/esm/chunk-ZXXFRUVF.js +796 -0
- package/dist/esm/chunk-ZXXFRUVF.js.map +1 -0
- package/dist/esm/index.js +179 -13
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/line-area/index.js +151 -0
- package/dist/esm/line-area/index.js.map +1 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +272 -106
- package/dist/index.js.map +1 -1
- package/dist/line-area/index.d.mts +83 -0
- package/dist/line-area/index.d.ts +83 -0
- package/dist/line-area/index.js +151 -0
- package/dist/line-area/index.js.map +1 -0
- package/package.json +6 -1
- package/dist/chunk-VFBZ7FNK.js.map +0 -1
- package/dist/esm/chunk-CDBW4SOR.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/charts/shared/chartBase.tsx","../../src/charts/shared/ChartAnnotationMarkerPortal.tsx","../../src/charts/shared/DefaultChartTooltip.tsx","../../src/charts/shared/formatters/valueFormatter.ts","../../src/charts/shared/SeriesLegend.tsx","../../src/charts/shared/chartExport.ts","../../src/charts/shared/annotations.ts","../../src/charts/shared/baseChartOptions.ts","../../src/charts/shared/formatters/datetimeFormatter.ts","../../src/charts/shared/axisOptions.ts","../../src/charts/shared/valueAxisLabelFormatter.ts"],"sourcesContent":["// Engine boundary for the v2 chart architecture. The only file under `charts/`\n// that imports from \"highcharts\". See `charts/README.md` for invariants.\n\nimport Highcharts from \"highcharts\";\nimport { HighchartsReact } from \"highcharts-react-official\";\nimport highchartsAccessibility from \"highcharts/modules/accessibility\";\nimport highchartsAnnotations from \"highcharts/modules/annotations\";\nimport highchartsExporting from \"highcharts/modules/exporting\";\nimport highchartsOfflineExporting from \"highcharts/modules/offline-exporting\";\nimport highchartsExportData from \"highcharts/modules/export-data\";\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { useTheme } from \"styled-components\";\n\nimport { Box } from \"@sproutsocial/seeds-react-box\";\nimport { ChartTooltipPortal } from \"../../components/ChartTooltip/components/ChartTooltipPortal\";\nimport { transformTimeSeriesTooltipData } from \"../../helpers\";\nimport { GlobalChartStyleOverrides } from \"../../styles/chartStyles\";\nimport { ChartAnnotationMarkerPortal } from \"./ChartAnnotationMarkerPortal\";\nimport { DefaultChartTooltip } from \"./DefaultChartTooltip\";\nimport { SeriesLegend } from \"./SeriesLegend\";\nimport type { TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport type { TypeTheme } from \"@sproutsocial/seeds-react-theme\";\nimport { defaultFilename } from \"./chartExport\";\nimport type { ChartAnnotationLookup } from \"./annotations\";\nimport type { ValueFormat } from \"./formatters/valueFormatter\";\nimport type { ChartExportHandle } from \"./chartExport\";\nimport type { TypeChartStyleColor, TypeChartStylePattern } from \"../../types\";\n\nhighchartsAccessibility(Highcharts);\nhighchartsAnnotations(Highcharts);\n// `exporting` must register before `offline-exporting` and `export-data`, which\n// extend it. `exporting` adds a native context (hamburger) button by default;\n// `ChartRenderer` disables it on the chart options so v2 charts expose export\n// only through the `onReady` handle. Export is client-side/offline only —\n// we never call the Highcharts export server.\nhighchartsExporting(Highcharts);\nhighchartsOfflineExporting(Highcharts);\nhighchartsExportData(Highcharts);\n\n/** Highcharts series type. `column` is vertical bars; `bar` is horizontal bars. */\nexport type SeedsChartType =\n | \"column\"\n | \"bar\"\n | \"line\"\n | \"spline\"\n | \"area\"\n | \"areaspline\";\n\nexport interface SeedsChartMarkerOptions {\n enabled?: boolean;\n symbol?: \"circle\";\n}\n\n/** Object form of a series point — carries an optional per-point `marker` override. */\nexport interface SeedsChartDataPoint {\n x?: number;\n y: number | null;\n marker?: SeedsChartMarkerOptions;\n}\n\nexport interface SeedsChartSeriesOptions {\n type: SeedsChartType;\n name: string;\n data: Array<number | null | [number, number | null] | SeedsChartDataPoint>;\n color?: string;\n}\n\n/**\n * Seeds-local shape of the `this` context Highcharts binds when invoking an\n * axis-label `formatter`. Models only the fields our default formatter reads\n * (`value` and `axis.tickPositions`).\n */\nexport interface SeedsAxisLabelFormatterContext {\n value: number | string;\n axis: { tickPositions?: ReadonlyArray<number> };\n}\n\nexport interface SeedsChartAxisLabelOptions {\n useHTML?: boolean;\n /** Show the axis tick labels. Maps to Highcharts' `labels.enabled`; defaults to shown. */\n enabled?: boolean;\n /** `this`-bound tick-label formatter returning the rendered string. */\n formatter?: (this: SeedsAxisLabelFormatterContext) => string;\n}\n\n/**\n * Highcharts datetime tick-label formats, keyed by the auto-selected tick unit.\n * Only the units the chart families set are modeled; Highcharts merges the rest\n * with its own defaults.\n */\nexport interface SeedsChartDateTimeLabelFormats {\n hour?: string;\n day?: string;\n week?: string;\n month?: string;\n year?: string;\n}\n\nexport interface SeedsChartAxisTitleOptions {\n text: string;\n}\n\nexport interface SeedsChartXAxisOptions {\n type?: \"category\" | \"datetime\" | \"linear\";\n categories?: Array<string>;\n crosshair?: boolean;\n min?: number;\n max?: number;\n labels?: SeedsChartAxisLabelOptions;\n dateTimeLabelFormats?: SeedsChartDateTimeLabelFormats;\n}\n\nexport interface SeedsChartYAxisOptions {\n min?: number;\n max?: number;\n /** Soft minimum — the axis won't start above this value, but may extend below it for negative data. */\n softMin?: number;\n /** Soft maximum — the axis won't end below this value, but may extend above it. */\n softMax?: number;\n gridLineWidth?: number;\n title?: SeedsChartAxisTitleOptions;\n labels?: SeedsChartAxisLabelOptions;\n}\n\nexport interface SeedsChartTooltipOptions {\n enabled?: boolean;\n // `useHTML` is intentionally not here — it's hardcoded `true` at the engine\n // boundary (ChartRenderer) because the tooltip portal can't work without it.\n outside?: boolean;\n padding?: number;\n shape?: \"rect\" | \"callout\";\n shared?: boolean;\n hideDelay?: number;\n valueSuffix?: string;\n}\n\nexport interface SeedsChartSeriesPlotOptions {\n animation?: boolean;\n /** Stacking applied across all series. Used by the line/area family for `stacked-area`. */\n stacking?: \"normal\" | \"percent\";\n /** Point-level event wiring (e.g. click). The events shape is family-agnostic. */\n point?: { events?: SeedsChartPointEvents };\n /** Default point-marker visibility. The line/area family disables markers and re-enables them per isolated point. */\n marker?: SeedsChartMarkerOptions;\n}\n\nexport interface SeedsChartPointEventContext {\n x: number | string;\n series: {\n chart: {\n series: ReadonlyArray<{\n type: string;\n data: ReadonlyArray<{\n x: number | string;\n graphic?: { element?: Element };\n }>;\n }>;\n };\n };\n}\n\nexport interface SeedsChartPointEvents {\n mouseOver?: (this: SeedsChartPointEventContext) => void;\n mouseOut?: (this: SeedsChartPointEventContext) => void;\n click?: (event: { point: { x: number | string } }) => void;\n}\n\nexport interface SeedsChartColumnPointOptions {\n events?: SeedsChartPointEvents;\n}\n\nexport interface SeedsChartColumnPlotOptions {\n stacking?: \"normal\" | \"percent\";\n pointPadding?: number;\n groupPadding?: number;\n pointWidth?: number;\n borderRadius?: number;\n borderWidth?: number;\n point?: SeedsChartColumnPointOptions;\n}\n\n/** Type-scoped stacking for filled line-area variants (parity with `column`). */\nexport interface SeedsChartAreaPlotOptions {\n stacking?: \"normal\" | \"percent\";\n}\n\nexport interface SeedsChartPlotOptions {\n series?: SeedsChartSeriesPlotOptions;\n // `column` (vertical bars) and `bar` (horizontal bars) take the same option\n // shape; the bar adapter assigns one config under whichever key is active.\n column?: SeedsChartColumnPlotOptions;\n bar?: SeedsChartColumnPlotOptions;\n area?: SeedsChartAreaPlotOptions;\n areaspline?: SeedsChartAreaPlotOptions;\n}\n\nexport interface SeedsChartChartOptions {\n type: SeedsChartType;\n styledMode?: boolean;\n animation?: boolean;\n marginTop?: number;\n}\n\nexport interface SeedsChartAnnotationLabelOptions {\n point: { x: number; y: number; xAxis: 0; yAxis: 0 };\n /** Highcharts shows a default label if this is empty; pass `\" \"` to suppress. */\n text?: string;\n}\n\n/**\n * Shared options applied to every label in a Highcharts annotation block.\n * `useHTML: true` is load-bearing — it makes Highcharts attach an HTML\n * `graphic.div` to each label, which `ChartAnnotationMarkerPortal` portals\n * React content into. Without it, labels render as SVG `<text>` and the\n * portal finds no containers.\n */\nexport interface SeedsChartAnnotationLabelOptionsShared {\n useHTML?: boolean;\n padding?: number;\n}\n\nexport interface SeedsChartAnnotationsOptions {\n labels?: SeedsChartAnnotationLabelOptions[];\n labelOptions?: SeedsChartAnnotationLabelOptionsShared;\n}\n\nexport interface SeedsChartAccessibilityOptions {\n description?: string;\n}\n\nexport interface SeedsChartTitleOptions {\n text?: string;\n}\n\nexport interface SeedsChartCreditsOptions {\n enabled?: boolean;\n}\n\nexport interface SeedsChartLegendOptions {\n enabled?: boolean;\n}\n\n/** Maps to Highcharts `time` — chart-global; `timezone` only affects datetime axes. */\nexport interface SeedsChartTimeOptions {\n timezone?: string;\n}\n\nexport interface SeedsChartOptions {\n chart?: SeedsChartChartOptions;\n accessibility?: SeedsChartAccessibilityOptions;\n title?: SeedsChartTitleOptions;\n credits?: SeedsChartCreditsOptions;\n legend?: SeedsChartLegendOptions;\n tooltip?: SeedsChartTooltipOptions;\n time?: SeedsChartTimeOptions;\n xAxis?: SeedsChartXAxisOptions;\n yAxis?: SeedsChartYAxisOptions;\n plotOptions?: SeedsChartPlotOptions;\n series?: Array<SeedsChartSeriesOptions>;\n annotations?: SeedsChartAnnotationsOptions[];\n}\n\nexport interface SeedsChartSetupSeriesInput {\n color?: string;\n pattern?: TypeChartStylePattern;\n}\n\nexport interface UseSeedsChartSetupParams<\n T extends SeedsChartSetupSeriesInput = SeedsChartSetupSeriesInput\n> {\n series: Array<T>;\n /** Opt-in for the pattern array. Families that apply patterns (line, area) pass `true`. */\n includePatterns?: boolean;\n /**\n * Resolved effective cap (the family default, or the consumer's explicit\n * value). Series beyond it are dropped. Omit to disable capping entirely.\n */\n seriesLimit?: number;\n /**\n * Whether the consumer set `seriesLimit` explicitly. Suppresses the over-limit\n * warning (an explicit cap is intentional, not an accidental overflow).\n * Default `false`.\n */\n isSeriesLimitOverridden?: boolean;\n /** Opt out of the over-limit warning. Default `false`. */\n hideSeriesLimitWarning?: boolean;\n /** Component name used in the over-limit warning message (kept generic for future families). */\n componentName?: string;\n}\n\nexport interface UseSeedsChartSetupResult<\n T extends SeedsChartSetupSeriesInput = SeedsChartSetupSeriesInput\n> {\n theme: TypeTheme;\n colors: Array<TypeChartStyleColor>;\n patterns: Array<TypeChartStylePattern>;\n /** Series after applying the (optional) cap. Referentially equal to the input when no cap applies. */\n series: Array<T>;\n}\n\nexport function useSeedsChartSetup<\n T extends SeedsChartSetupSeriesInput = SeedsChartSetupSeriesInput\n>({\n series,\n includePatterns = false,\n seriesLimit,\n isSeriesLimitOverridden = false,\n hideSeriesLimitWarning = false,\n componentName,\n}: UseSeedsChartSetupParams<T>): UseSeedsChartSetupResult<T> {\n const theme = useTheme() as TypeTheme;\n const palette = theme.colors.DATAVIZ_COLORS_LIST;\n\n // Cap the series at the resolved limit. Memoized so the input reference is\n // preserved when no cap applies, keeping the colors/patterns memos\n // referentially stable.\n const cappedSeries = useMemo<Array<T>>(\n () =>\n seriesLimit !== undefined &&\n seriesLimit >= 1 &&\n series.length > seriesLimit\n ? series.slice(0, seriesLimit)\n : series,\n [series, seriesLimit]\n );\n\n // Warn when the limit was exceeded, was not explicitly overridden by the\n // consumer, and the warning isn't suppressed. Keyed off the gating conditions\n // so it fires when those change rather than on every render.\n useEffect(() => {\n if (\n seriesLimit !== undefined &&\n seriesLimit >= 1 &&\n series.length > seriesLimit &&\n !isSeriesLimitOverridden &&\n !hideSeriesLimitWarning &&\n componentName != null\n ) {\n console.warn(\n `${componentName}: Maximum number of series (${seriesLimit}) exceeded. Only the first ${seriesLimit} series will be displayed.`\n );\n }\n }, [\n series.length,\n seriesLimit,\n isSeriesLimitOverridden,\n hideSeriesLimitWarning,\n componentName,\n ]);\n\n const colors = useMemo<Array<TypeChartStyleColor>>(() => {\n const out: TypeChartStyleColor[] = [];\n const paletteLen = palette.length;\n for (let i = 0; i < cappedSeries.length; i++) {\n const s = cappedSeries[i]!;\n out.push(s.color ?? palette[i % paletteLen] ?? \"\");\n }\n return out;\n }, [cappedSeries, palette]);\n\n const patterns = useMemo<Array<TypeChartStylePattern>>(() => {\n if (!includePatterns) return [];\n const out: TypeChartStylePattern[] = [];\n for (let i = 0; i < cappedSeries.length; i++) {\n const s = cappedSeries[i]!;\n out.push(s.pattern ?? \"solid\");\n }\n return out;\n }, [cappedSeries, includePatterns]);\n\n return { theme, colors, patterns, series: cappedSeries };\n}\n\nexport interface ChartRendererSeries {\n name: string;\n color?: string;\n /** Seeds icon or partner-logo name rendered before the series name in the legend label. */\n icon?: TypeIconName;\n}\n\nexport interface ChartTooltipDataRow {\n color: TypeChartStyleColor;\n name: string;\n value: number | null;\n}\n\n/** Tooltip render-prop signature for v2 charts. */\nexport interface ChartTooltipProps {\n data: ChartTooltipDataRow[];\n /** Resolved x-axis position. Category name for category axes, numeric for time/linear. */\n position: number | string;\n /** Resolved chart timezone — pass to date formatters when `position` is a numeric timestamp. Undefined on category axes. */\n timezone?: string;\n /** Declarative annotation anchored at this position, if any. Rendered in the tooltip header. */\n annotation?: {\n icon?: TypeIconName;\n color?: string;\n title?: string;\n description?: string;\n };\n /** True when the chart has an `onClick` handler — used by the default tooltip to render the click-label footer. */\n hasOnClick?: boolean;\n /** Footer content shown in the default tooltip when the chart is clickable. */\n tooltipClickLabel?: ReactNode;\n /** Content shown in place of a row's value when the value is null. Defaults to an em-dash. */\n invalidNumberLabel?: ReactNode;\n /** Declarative value format for the tooltip value cell. Omit for raw rendering. Applied at full precision (abbreviation off). */\n valueFormat?: ValueFormat;\n}\n\nexport interface ChartRendererProps {\n options: SeedsChartOptions;\n series: Array<ChartRendererSeries>;\n /** Theme-aware palette resolved by `useSeedsChartSetup`. Used as the swatch color for any series that doesn't carry an explicit `color`. */\n colors: ReadonlyArray<TypeChartStyleColor>;\n /** Override for the default tooltip content. Portal is always rendered — `GlobalChartStyleOverrides` makes Highcharts' native tooltip box transparent. */\n tooltip?: (args: ChartTooltipProps) => ReactNode;\n /**\n * Resolved annotations keyed by numeric x. Drives both the in-chart marker\n * portal and the tooltip-header `annotation` injection. The family component\n * builds this map (resolving category-string positions to indices); the\n * renderer is axis-type agnostic.\n */\n annotationLookup?: ChartAnnotationLookup;\n /** Forwarded into the default tooltip so it can render the click-label footer. */\n hasOnClick?: boolean;\n /** Forwarded into the default tooltip for click-label footer rendering. */\n tooltipClickLabel?: ReactNode;\n /** Resolved chart timezone, forwarded to the tooltip so its date title matches the axis ticks. Undefined on category axes. */\n timezone?: string;\n /** Forwarded into the default tooltip as the null-value override. */\n invalidNumberLabel?: ReactNode;\n /** Forwarded into the default tooltip to format the value cell declaratively. */\n valueFormat?: ValueFormat;\n /**\n * Fired once per chart instance with an opaque {@link ChartExportHandle} for\n * triggering PNG/SVG/PDF/CSV downloads. Re-fires only on a genuine remount,\n * never on data or prop updates.\n */\n onReady?: (handle: ChartExportHandle) => void;\n}\n\n/**\n * Runtime shape of one Highcharts annotation label — only the fields the\n * marker portal reads. Re-exported so the portal stays inside the engine\n * boundary (no direct \"highcharts\" import).\n */\nexport interface ChartAnnotationRuntimeLabel {\n graphic?: { div?: HTMLDivElement };\n options?: { point?: { x?: number } };\n}\n\n/** Runtime shape of one Highcharts annotation block (a group of labels). */\nexport interface ChartAnnotationRuntime {\n labels?: ChartAnnotationRuntimeLabel[];\n}\n\n/** Highcharts doesn't include the `annotations` array on its `Chart` type. */\ninterface ChartWithAnnotations extends Highcharts.Chart {\n annotations?: ChartAnnotationRuntime[];\n}\n\n/**\n * Theme→options map for the `styledMode: false` export clone, which can't see\n * the scoped CSS v2 charts normally style with. Mirrors `styles/chartStyles`.\n */\nfunction buildExportChartOptions(\n theme: TypeTheme,\n colors: ReadonlyArray<TypeChartStyleColor>\n): Highcharts.Options {\n // Line, gridline, and label styling are identical for both axes.\n const axisOptions = {\n lineColor: theme.colors.container.border.base,\n gridLineColor: theme.colors.container.border.base,\n labels: {\n style: {\n color: theme.colors.text.subtext,\n fontFamily: theme.fontFamily,\n fontSize: theme.typography[100].fontSize,\n fontWeight: String(theme.fontWeights.normal),\n },\n },\n };\n return {\n chart: {\n styledMode: false,\n backgroundColor: theme.colors.container.background.base,\n },\n // Series without an explicit `color` fall through to this palette by index.\n colors: [...colors],\n // The on-screen legend is a React sibling (`SeriesLegend`) outside the chart\n // SVG, so the export can't capture it. Turn on Highcharts' native legend for\n // the clone instead, themed to approximate the Seeds `ChartLegend` (centered\n // row of swatch + `text.subtext` label). It can't reproduce per-series Seeds\n // icons — those series show colour + name only.\n legend: {\n enabled: true,\n symbolRadius: 4,\n symbolHeight: 12,\n symbolWidth: 12,\n itemStyle: {\n color: theme.colors.text.subtext,\n fontFamily: theme.fontFamily,\n fontSize: theme.typography[200].fontSize,\n fontWeight: String(theme.fontWeights.normal),\n },\n },\n xAxis: {\n ...axisOptions,\n crosshair: {\n color: theme.colors.container.border.decorative.neutral,\n width: 1,\n },\n },\n // No zero-line: the `y-axis-zero-line` rule in chartStyles is a v1 leftover;\n // the v2 bar adapter never creates that plotLine.\n yAxis: axisOptions,\n } as Highcharts.Options;\n}\n\n/**\n * Build the opaque export handle for a chart instance. Lives here — not in\n * `chartExport.ts` — because it closes over the live `Highcharts.Chart`, which\n * never leaves the engine boundary. The returned {@link ChartExportHandle} is\n * Highcharts-free.\n *\n * PDF lazy-loads jspdf + svg2pdf.js (a deferred chunk) on first use.\n */\nfunction createChartExportHandle(\n chart: Highcharts.Chart,\n getExportChartOptions: () => Highcharts.Options\n): ChartExportHandle {\n const resolveName = (filename?: string) =>\n filename ?? defaultFilename(chart.options.chart?.type, new Date());\n\n const exportImage = async (\n type: Highcharts.ExportingMimeTypeValue,\n filename?: string\n ): Promise<void> => {\n // Read options at call time, not when the handle was built: a light/dark\n // toggle updates the chart in place without re-firing `onReady`, so the\n // export must reflect the current theme. 2nd arg is deep-merged, so\n // `labels.style` here merges with the live axis `formatter`, not clobbers it.\n chart.exportChartLocal(\n { type, filename: resolveName(filename) },\n getExportChartOptions()\n );\n };\n\n return {\n exportPNG: ({ filename } = {}) => exportImage(\"image/png\", filename),\n exportSVG: ({ filename } = {}) => exportImage(\"image/svg+xml\", filename),\n exportPDF: async ({ filename } = {}): Promise<void> => {\n // Lazy-load jspdf + svg2pdf.js (deferred chunk) and expose `window.jspdf`\n // before exporting, so Highcharts' offline-exporting renders the PDF\n // locally rather than fetching the libs from its CDN.\n const { loadPdfExportLibs } = await import(\"./pdfExportLibs\");\n loadPdfExportLibs();\n await exportImage(\"application/pdf\", filename);\n },\n exportCSV: async ({ filename } = {}): Promise<void> => {\n // `downloadCSV()` reads the filename from `chart.options.exporting.filename`\n // via `getFilename()`. Set it transiently (direct mutation — no `update()`,\n // so no redraw) so the per-call override and generated default both apply,\n // then restore the previous value.\n const exporting = (chart.options.exporting ??= {});\n const previous = exporting.filename;\n exporting.filename = resolveName(filename);\n try {\n chart.downloadCSV();\n } finally {\n exporting.filename = previous;\n }\n },\n };\n}\n\nexport function ChartRenderer({\n options,\n series,\n colors,\n tooltip,\n annotationLookup,\n hasOnClick,\n tooltipClickLabel,\n timezone,\n invalidNumberLabel,\n valueFormat,\n onReady,\n}: ChartRendererProps) {\n const [chart, setChart] = useState<Highcharts.Chart | null>(null);\n const [plotHeight, setPlotHeight] = useState(0);\n const renderTooltip = tooltip ?? DefaultChartTooltip;\n const theme = useTheme() as TypeTheme;\n\n // Hold the live theme + palette in a ref so the export handle reads the\n // *current* theme at call time (see `createChartExportHandle`). A dark-mode\n // toggle updates this each render without re-firing `onReady`.\n const exportThemeRef = useRef({ theme, colors });\n exportThemeRef.current = { theme, colors };\n\n // Capture only the live chart. Highcharts reuses a chart's `callback` when it\n // builds the throwaway clone for export (`new chart.constructor(options,\n // chart.callback)` in exporting/offline-exporting, with `chart.forExport:\n // true`). That clone is destroyed the instant its SVG is captured, so binding\n // React state to it would leave a destroyed chart whose next `update()` reads\n // `options.responsive` on `undefined` and throws.\n const captureChart = useCallback((chartInstance: Highcharts.Chart) => {\n const forExport = (\n chartInstance.options.chart as { forExport?: boolean } | undefined\n )?.forExport;\n if (!forExport) {\n setChart(chartInstance);\n // Seed plotHeight in the same commit as the chart so markers render with\n // it, not a frame later (the pop-in). The redraw handler keeps it current.\n setPlotHeight(chartInstance.plotHeight);\n }\n }, []);\n\n // Hold `onReady` in a ref so an inline callback (new identity each render)\n // doesn't re-fire the effect below — it should fire on instance change only.\n const onReadyRef = useRef(onReady);\n onReadyRef.current = onReady;\n\n // Fire `onReady` once per chart instance. The chart callback runs only on\n // instance creation — data/prop changes call `chart.update()` on the same\n // instance and don't re-run it — so keying on `[chart]` gives once-per-instance\n // semantics: re-fires on a genuine remount, never on a data update.\n useEffect(() => {\n if (!chart) return;\n onReadyRef.current?.(\n createChartExportHandle(chart, () =>\n buildExportChartOptions(\n exportThemeRef.current.theme,\n exportThemeRef.current.colors\n )\n )\n );\n }, [chart]);\n\n // Track the chart's actual plot-area height so the annotation marker line\n // spans it. Re-reads on Highcharts' `redraw` event (covers window resizes,\n // data updates, anything that re-lays-out the plot area).\n useEffect(() => {\n if (!chart) return;\n setPlotHeight(chart.plotHeight);\n const unbind = Highcharts.addEvent(chart, \"redraw\", () => {\n setPlotHeight(chart.plotHeight);\n });\n return () => unbind();\n }, [chart]);\n\n // Stable ref across internal re-renders (setChart/setPlotHeight): HighchartsReact\n // keys its update effect on the options ref and redraws on change, so a fresh\n // object each render would redraw — and re-flicker the annotations — every time.\n const highchartsOptions = useMemo(\n () =>\n ({\n ...options,\n // useHTML is load-bearing: the tooltip portal's target div only mounts\n // when the label renders as HTML, not SVG (see `charts/README.md`).\n tooltip: { ...options.tooltip, useHTML: true },\n // Client-side/offline export only; native context button hidden (export\n // is exposed via the `onReady` handle).\n exporting: {\n fallbackToExportServer: false,\n buttons: { contextButton: { enabled: false } },\n },\n } as Highcharts.Options),\n [options]\n );\n\n // Safety net: no series → render nothing. Families are expected to early-return\n // before calling hooks to avoid wasted work, but this guards future families\n // that forget. See `charts/README.md` (\"Empty-data handling\").\n if (series.length === 0) return null;\n\n const chartWithAnnotations = chart as ChartWithAnnotations | null;\n const hasRenderedAnnotations =\n !!chartWithAnnotations?.annotations?.length &&\n !!annotationLookup?.size &&\n plotHeight > 0;\n\n return (\n <>\n <GlobalChartStyleOverrides />\n <HighchartsReact\n highcharts={Highcharts}\n // Structural cast at the engine seam — the only place we touch Highcharts' option types.\n options={highchartsOptions}\n callback={captureChart}\n />\n {hasRenderedAnnotations ? (\n <ChartAnnotationMarkerPortal\n annotationLookup={annotationLookup}\n annotationContext={chartWithAnnotations!.annotations![0]!}\n chartContainer={chartWithAnnotations!.container}\n plotHeight={plotHeight}\n />\n ) : null}\n {chart ? (\n <ChartTooltipPortal\n chart={chart}\n renderContent={(context) => {\n // Drop v1's `readonly` array wrapper and `icon` field at the seam —\n // the v2 surface is mutable and doesn't expose row-level icons.\n const data: ChartTooltipDataRow[] = transformTimeSeriesTooltipData({\n context,\n data: series.map((s, i) => ({\n name: s.name,\n points: [],\n styles: { color: s.color ?? colors[i] ?? \"\" },\n })),\n }).map((row) => ({\n color: row.color,\n name: row.name,\n value: row.value,\n }));\n // `context.x` is Highcharts' field; we expose it to v2 consumers as\n // `position` for the tooltip header (the category name on category\n // axes, the numeric coordinate on time/linear axes). The annotation\n // lookup is keyed numerically, so resolve by `context.point.x`\n // (numeric on every axis type) rather than `context.x`.\n const position = context.x as number | string;\n const resolved = annotationLookup?.get(context.point.x as number);\n const annotation = resolved\n ? {\n icon: resolved.icon,\n color: resolved.color,\n title: resolved.title,\n description: resolved.description,\n }\n : undefined;\n return renderTooltip({\n data,\n position,\n annotation,\n hasOnClick,\n tooltipClickLabel,\n timezone,\n invalidNumberLabel,\n valueFormat,\n });\n }}\n />\n ) : null}\n <Box mt={350}>\n <SeriesLegend\n items={series.map((s, i) => ({\n name: s.name,\n icon: s.icon,\n color: s.color ?? colors[i] ?? \"\",\n }))}\n />\n </Box>\n </>\n );\n}\n","// Portals DS-owned marker content into Highcharts annotation containers. The\n// marker shape (icon + vertical line in the configured color) is rendered\n// internally — consumers don't supply React nodes. See CE-7.\n\nimport { memo, useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Box } from \"@sproutsocial/seeds-react-box\";\nimport { Icon } from \"@sproutsocial/seeds-react-icon\";\nimport type { ChartAnnotationLookup, ChartAnnotation } from \"./annotations\";\nimport type {\n ChartAnnotationRuntime,\n ChartAnnotationRuntimeLabel,\n} from \"./chartBase\";\n\nfunction ChartAnnotationMarker({\n annotation,\n lineHeight,\n}: {\n annotation: ChartAnnotation;\n /** Vertical pixel length of the marker line. Driven by `chart.plotHeight`\n * so the line spans the chart's full plot area regardless of chart size. */\n lineHeight: number;\n}) {\n return (\n <Box display=\"flex\" flexDirection=\"column\" alignItems=\"center\" gap={200}>\n {annotation.icon ? (\n <Box\n display=\"flex\"\n alignItems=\"center\"\n justifyContent=\"center\"\n width=\"20px\"\n height=\"20px\"\n bg=\"icon.base\"\n borderRadius=\"50%\"\n >\n <Icon name={annotation.icon} size=\"mini\" color=\"icon.inverse\" />\n </Box>\n ) : null}\n <Box\n height={`${lineHeight}px`}\n width=\"0.5px\"\n bg={annotation.color ?? \"neutral.200\"}\n />\n </Box>\n );\n}\n\n// v2-specific marker attribute. Distinct from v1's `data-annotation-marker`\n// so v1 and v2 portals don't sweep each other's containers when both render\n// side-by-side (e.g. in the v1↔v2 comparison story).\nconst MARKER_ATTR = \"data-v2-chart-annotation-marker\";\n\nexport const ChartAnnotationMarkerPortal = memo(\n function ChartAnnotationMarkerPortal({\n annotationLookup,\n annotationContext,\n chartContainer,\n plotHeight,\n }: {\n annotationLookup: ChartAnnotationLookup;\n annotationContext: ChartAnnotationRuntime;\n /** The chart's own DOM root — every query is scoped here to keep\n * multi-chart renders from interfering. */\n chartContainer: HTMLElement;\n /** Highcharts' current plot-area height in pixels. Drives the marker\n * line length so it spans the chart's plot area at any chart size. */\n plotHeight: number;\n }) {\n const annotationContainers = useRef<Record<number, HTMLDivElement>>({});\n const [, setRenderCount] = useState(0);\n const forceRender = () => setRenderCount((prev) => prev + 1);\n\n useEffect(() => {\n if (!annotationContext.labels) return;\n\n const newContainers: Record<number, HTMLDivElement> = {};\n const existingAnnotationContainers = chartContainer.querySelectorAll(\n `div[${MARKER_ATTR}='true']`\n );\n\n // 1. Mark this chart's existing markers as stale before updating.\n // Highcharts doesn't clean these up, so we sweep them below.\n existingAnnotationContainers.forEach((annotation) =>\n annotation.setAttribute(MARKER_ATTR, \"false\")\n );\n\n annotationContext.labels.forEach((label: ChartAnnotationRuntimeLabel) => {\n const labelElement = label.graphic?.div;\n if (!labelElement) return;\n\n // 2. Reuse this label's existing marker div when present — Highcharts\n // repositions (rather than recreates) annotation graphics across\n // redraws, so reusing keeps the React portal mounted and avoids the\n // teardown→recreate flash. Only create one when absent.\n let annotationDiv = labelElement.querySelector<HTMLDivElement>(\n `div[${MARKER_ATTR}]`\n );\n if (!annotationDiv) {\n annotationDiv = document.createElement(\"div\");\n labelElement.appendChild(annotationDiv);\n }\n annotationDiv.setAttribute(MARKER_ATTR, \"true\");\n\n const xValue = label.options?.point?.x as number;\n newContainers[xValue] = annotationDiv;\n });\n\n annotationContainers.current = newContainers;\n forceRender();\n\n // 4. Within this chart's container, remove `.highcharts-annotation`\n // parents that no longer have any live v2 marker child.\n requestAnimationFrame(() => {\n chartContainer\n .querySelectorAll(\"div.highcharts-annotation\")\n .forEach((annotationDiv) => {\n const reactAnnotations = annotationDiv.querySelectorAll(\n `div[${MARKER_ATTR}]`\n );\n const hasActiveAnnotations = Array.from(reactAnnotations).some(\n (div) => div.getAttribute(MARKER_ATTR) === \"true\"\n );\n if (!hasActiveAnnotations) annotationDiv.remove();\n });\n });\n }, [annotationContext.labels, annotationLookup, chartContainer]);\n\n return (\n <>\n {Object.entries(annotationContainers.current).map(\n ([xValue, container]) => {\n const annotation = annotationLookup.get(Number(xValue));\n return annotation\n ? createPortal(\n <ChartAnnotationMarker\n annotation={annotation}\n lineHeight={plotHeight}\n />,\n container\n )\n : null;\n }\n )}\n </>\n );\n }\n);\n","// Minimal: no locale / currency / duration formatting. Consumers needing those pass their own `tooltip` render prop.\n\nimport { Box } from \"@sproutsocial/seeds-react-box\";\nimport { Icon, type TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport { Text } from \"@sproutsocial/seeds-react-text\";\n\nimport { ChartLegendLabel } from \"../../components/ChartLegend/components/ChartLegendLabel\";\nimport {\n ChartTooltip,\n ChartTooltipFooter,\n ChartTooltipHeader,\n ChartTooltipTable,\n ChartTooltipTitle,\n type TypeChartTooltipTableProps,\n} from \"../../components/ChartTooltip\";\nimport type { ChartTooltipProps } from \"./chartBase\";\nimport { valueFormatter } from \"./formatters/valueFormatter\";\n\nfunction formatTitle(position: number | string, timezone?: string): string {\n if (typeof position === \"string\") return position;\n // `timeZone` aligns the title with the chart's configured timezone (which\n // governs the axis ticks). Omitting it would format in the browser's local\n // zone and disagree with the ticks by up to a day.\n return new Date(position).toLocaleDateString(undefined, {\n year: \"numeric\",\n month: \"long\",\n day: \"numeric\",\n weekday: \"long\",\n timeZone: timezone,\n });\n}\n\n// Inlined (not v1's `ChartXAnnotationDetails`) because that component requires\n// both iconName and text together — v2's `ChartAnnotation` documents icon,\n// title, and description as independently optional, so the renderer has to\n// match that contract instead of dropping fields silently.\nfunction AnnotationHeader({\n icon,\n title,\n description,\n}: {\n icon?: TypeIconName;\n title?: string;\n description?: string;\n}) {\n const hasIconOrTitle = Boolean(icon || title);\n if (!hasIconOrTitle && !description) return null;\n return (\n <>\n {hasIconOrTitle ? (\n <ChartTooltipHeader>\n <Box display=\"flex\" alignItems=\"center\" gap={300}>\n {icon ? <Icon name={icon} size=\"mini\" color=\"icon.base\" /> : null}\n {title ? (\n <Text color=\"text.body\" fontSize={200}>\n {title}\n </Text>\n ) : null}\n </Box>\n </ChartTooltipHeader>\n ) : null}\n {description ? (\n <ChartTooltipHeader>\n <Text fontSize={200} color=\"text.subtext\">\n {description}\n </Text>\n </ChartTooltipHeader>\n ) : null}\n </>\n );\n}\n\nexport function DefaultChartTooltip({\n data,\n position,\n annotation,\n hasOnClick,\n tooltipClickLabel,\n timezone,\n invalidNumberLabel,\n valueFormat,\n}: ChartTooltipProps) {\n const rows = data.map((d) => ({\n cells: [\n {\n content: (\n <ChartLegendLabel color={d.color}>\n <Text aria-label={`${d.name}: `}>{d.name}</Text>\n </ChartLegendLabel>\n ),\n },\n {\n // Format non-null values through the shared formatter when a\n // `valueFormat` is supplied. Tooltip values are always full precision\n // (`abbreviate: false`) — the axis tick scan never applies here (v1\n // parity: the bar tooltip always passed `abbreviate={false}`).\n content: (\n <Text>\n {d.value == null\n ? invalidNumberLabel ?? \"—\"\n : valueFormat\n ? valueFormatter({\n ...valueFormat,\n value: d.value,\n abbreviate: false,\n })\n : d.value}\n </Text>\n ),\n align: \"right\" as const,\n },\n ],\n }));\n\n return (\n <ChartTooltip>\n {annotation ? (\n <AnnotationHeader\n icon={annotation.icon}\n title={annotation.title}\n description={annotation.description}\n />\n ) : null}\n <ChartTooltipTitle>{formatTitle(position, timezone)}</ChartTooltipTitle>\n <ChartTooltipTable rows={rows as TypeChartTooltipTableProps[\"rows\"]} />\n {hasOnClick && tooltipClickLabel ? (\n <ChartTooltipFooter>\n {typeof tooltipClickLabel === \"string\" ? (\n <Box display=\"flex\" alignItems=\"center\" gap={300}>\n <Icon name=\"hand-pointer-clicking-outline\" color=\"icon.base\" />\n <Text color=\"text.subtext\" fontSize={200}>\n {tooltipClickLabel}\n </Text>\n </Box>\n ) : (\n tooltipClickLabel\n )}\n </ChartTooltipFooter>\n ) : null}\n </ChartTooltip>\n );\n}\n","import { formatDuration } from \"@sproutsocial/seeds-react-duration\";\nimport { formatNumeral } from \"@sproutsocial/seeds-react-numeral\";\n\nimport type { TypeChartNumberFormat } from \"../../../types\";\n\nexport type TypeValuePercentInput = \"decimal\" | \"whole\";\n\nexport type TypeValueFormatterOptions = Readonly<{\n /** The raw numeric value. For duration, milliseconds. */\n value: number;\n /** default \"decimal\" */\n numberFormat?: TypeChartNumberFormat;\n /** Only used when numberFormat === \"currency\". default \"USD\" */\n currency?: string;\n /** true → 10k threshold; number → max(1000, abs(n)); false → never. default true */\n abbreviate?: boolean | number;\n /** \"decimal\" scales 0.42 → \"42%\"; \"whole\" treats 42 → \"42%\". default \"decimal\" */\n percentInput?: TypeValuePercentInput;\n /** locale for decimal/currency/percent (formatNumeral) */\n numberLocale?: Intl.LocalesArgument;\n /** locale for duration (formatDuration) */\n textLocale?: Intl.LocalesArgument;\n}>;\n\n/**\n * Pure value formatter for v2 charts. Turns a numeric value plus declarative\n * config into a display string. Composes `formatNumeral` (decimal/currency/\n * percent) and `formatDuration` (duration). Contains no chart-engine types or\n * imports — it upholds the \"engine boundary is one file\" invariant documented\n * in `src/charts/README.md`.\n *\n * The axis-wide \"smart 1k/10k\" abbreviation scan that v1's `yAxisLabelFormatter`\n * derives from `tickPositions` is not available to a pure per-value function;\n * callers pass the lowered threshold via `abbreviate` (a number) instead.\n */\nexport function valueFormatter({\n value,\n numberFormat = \"decimal\",\n currency = \"USD\",\n abbreviate = true,\n percentInput = \"decimal\",\n numberLocale,\n textLocale,\n}: TypeValueFormatterOptions): string {\n const numberValue = Number(value);\n\n // v1 parity: render 0 as a bare \"0\" for every format (clean axis origin) —\n // not \"$0.00\" / \"0%\" / a duration-zero. Matches v1's yAxisLabelFormatter,\n // which checks zero first, before any format branch. Revisit if design\n // wants per-format zero rendering later.\n if (numberValue === 0) {\n return formatNumeral({ locale: numberLocale as string, number: 0 });\n }\n\n if (numberFormat === \"duration\") {\n return formatDuration({\n display: \"narrow\",\n locale: textLocale,\n milliseconds: numberValue,\n });\n }\n\n if (numberFormat === \"percent\") {\n const whole = percentInput === \"decimal\" ? numberValue * 100 : numberValue;\n return formatNumeral({\n format: \"percent\",\n locale: numberLocale as string,\n number: whole,\n });\n }\n\n // decimal | currency\n return formatNumeral({\n abbreviate,\n currency,\n format: numberFormat,\n locale: numberLocale as string,\n number: numberValue,\n });\n}\n\n/**\n * Declarative value-format config for axis ticks and the default tooltip — the\n * full {@link TypeValueFormatterOptions} surface minus `value`, which is\n * supplied per-tick / per-row by the caller (the adapter and tooltip).\n */\nexport type ValueFormat = Omit<TypeValueFormatterOptions, \"value\">;\n","import { memo } from \"react\";\nimport { Icon, type TypeIconName } from \"@sproutsocial/seeds-react-icon\";\nimport { ChartLegend } from \"../../components/ChartLegend\";\nimport { ChartLegendLabelContentWithIcon } from \"../../components/ChartLegend/components/ChartLegendLabelContentWithIcon\";\n\nexport interface SeriesLegendItem {\n name: string;\n /** Resolved swatch color — caller is responsible for resolving against the active theme. */\n color: string;\n /** Seeds icon or partner-logo name rendered before the series name. */\n icon?: TypeIconName;\n}\n\nexport interface SeriesLegendProps {\n items: ReadonlyArray<SeriesLegendItem>;\n}\n\n// Internal to `ChartRenderer` — not intended for standalone use. Swatch\n// colors must be resolved by the caller (the chart base does this via\n// `useSeedsChartSetup`) so we keep a single source of truth for the\n// theme-aware palette. If this ever becomes a publicly-exposed primitive,\n// add a `useTheme()` fallback here and relax `item.color` to optional.\nexport const SeriesLegend = memo<SeriesLegendProps>(function SeriesLegend({\n items,\n}) {\n const labels = items.map((item) => ({\n content: (\n <ChartLegendLabelContentWithIcon\n icon={\n item.icon ? (\n <Icon name={item.icon} fixedWidth aria-hidden />\n ) : undefined\n }\n >\n {item.name}\n </ChartLegendLabelContentWithIcon>\n ),\n color: item.color,\n }));\n return <ChartLegend legendLabels={labels} />;\n});\n","// Public, Highcharts-free surface for the v2 chart export API. This module\n// imports nothing — it is a leaf so it can never form an import cycle with\n// `chartBase`. The `createChartExportHandle` factory that closes over the live\n// `Highcharts.Chart` lives in `chartBase.tsx` (the one file allowed to import\n// \"highcharts\"); the instance never crosses this boundary.\n//\n/**\n * Opaque export API handed to consumers via `ChartRenderer`'s `onReady`. Each\n * callable closes over the chart instance and triggers a client-side download;\n * an optional `filename` overrides the generated default. No Highcharts type,\n * ref, or method shape crosses this boundary.\n */\nexport interface ChartExportHandle {\n exportPNG: (opts?: { filename?: string }) => Promise<void>;\n exportSVG: (opts?: { filename?: string }) => Promise<void>;\n exportPDF: (opts?: { filename?: string }) => Promise<void>;\n exportCSV: (opts?: { filename?: string }) => Promise<void>;\n}\n\n/**\n * Canonical client-side export formats offered by `ChartExportMenu`. Co-located\n * with `ChartExportHandle` so the format vocabulary lives next to the handle it\n * maps onto; this leaf imports nothing, so re-exporting it carries no cycle risk.\n */\nexport type ChartExportFormat = \"png\" | \"svg\" | \"pdf\" | \"csv\";\n\n/**\n * Default download filename when a consumer doesn't pass a `filename` override:\n * `chart-<type>-<YYYY-MM-DD-HH-mm-ss>`, lowercased with non-alphanumerics\n * collapsed to hyphens. The full datetime (not just the date) avoids collisions\n * between charts exported on the same day. `type` comes from the chart's\n * `chart.type`; it falls back to `chart` when absent.\n */\nexport function defaultFilename(type: string | undefined, now: Date): string {\n const iso = now.toISOString();\n const stamp = `${iso.slice(0, 10)}-${iso.slice(11, 19).replace(/:/g, \"-\")}`;\n return slugify(type ? `chart-${type}-${stamp}` : `chart-${stamp}`);\n}\n\nfunction slugify(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n","// 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 type { SeedsChartOptions, SeedsChartType } from \"./chartBase\";\n\ninterface BaseChartOptionsInput {\n /** Highcharts chart/series type for the family (`column`, `line`, `area`, `pie`, …). */\n type: SeedsChartType;\n /** Accessibility description (Highcharts `accessibility.description`). */\n description: string;\n /** Appended to each tooltip value (e.g. `\" MT\"`, `\"%\"`). */\n valueSuffix?: string;\n /** Reserve top margin for content drawn above the plot area (e.g. annotation markers). */\n reserveTopMargin?: boolean;\n /**\n * Resolved IANA timezone for the chart (`time.timezone`) — governs datetime\n * ticks and the tooltip date. Pass the value from `resolveTooltipTimezone`;\n * `undefined` (a category axis) omits `time` entirely.\n */\n timezone?: string;\n}\n\n/**\n * The chart options shared by *every* v2 chart family, independent of axis type:\n * styled-mode + animation-off, the accessibility description, Highcharts' native\n * title/credits/legend disabled (Seeds renders its own legend), and the tooltip-\n * portal config. Families spread the result and add their own axes, `plotOptions`,\n * `series`, and `annotations`.\n *\n * This is the family-agnostic base layer — donut (no axes) consumes it just as\n * the X/Y families do. Axis/series/X-Y-specific sharing lives elsewhere\n * (`axisOptions` + the X/Y pattern-sharing spike), layered on top of this.\n */\nexport function buildBaseChartOptions({\n type,\n description,\n valueSuffix,\n reserveTopMargin = false,\n timezone,\n}: BaseChartOptionsInput): Pick<\n SeedsChartOptions,\n | \"chart\"\n | \"accessibility\"\n | \"title\"\n | \"credits\"\n | \"legend\"\n | \"tooltip\"\n | \"time\"\n> {\n return {\n chart: {\n type,\n styledMode: true,\n animation: false,\n ...(reserveTopMargin ? { marginTop: 24 } : {}),\n },\n accessibility: { description },\n title: { text: \"\" },\n credits: { enabled: false },\n legend: { enabled: false },\n tooltip: {\n enabled: true,\n outside: true,\n padding: 0,\n shape: \"rect\",\n shared: true,\n hideDelay: 0,\n valueSuffix,\n },\n // Chart-global in Highcharts; only meaningful for datetime axes, so it's\n // present only when a timezone was resolved (omitted for category axes).\n ...(timezone ? { time: { timezone } } : {}),\n };\n}\n","/**\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\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","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"],"mappings":"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","names":["useEffect","useRef","useState","Box","ChartAnnotationMarkerPortal","Box","Icon","Fragment","jsx","jsxs","Box","Icon","memo","Icon","jsx","memo","SeriesLegend","Icon","Fragment","jsx","jsxs","useEffect","useState","useRef","Box","formatNumeral","formatNumeral"]}
|
package/dist/esm/index.js
CHANGED
|
@@ -10,20 +10,11 @@ import {
|
|
|
10
10
|
ChartTooltipTable,
|
|
11
11
|
ChartTooltipTitle,
|
|
12
12
|
ColorBox,
|
|
13
|
-
DONUT_CHART_HALO_SIZE,
|
|
14
|
-
DONUT_CHART_HEIGHT,
|
|
15
|
-
DONUT_CHART_WIDTH,
|
|
16
13
|
DatavizColorBox,
|
|
17
14
|
GlobalChartStyleOverrides,
|
|
18
15
|
NetworkColorBox,
|
|
19
|
-
TIME_SERIES_CHART_HEIGHT,
|
|
20
|
-
VERTICAL_BAR_CHART_DEFAULT_SERIES_LIMIT,
|
|
21
|
-
areaChartOptions,
|
|
22
16
|
areaChartStyles,
|
|
23
|
-
baseChartOptions,
|
|
24
17
|
baseChartStyles,
|
|
25
|
-
columnChartOptions,
|
|
26
|
-
donutChartOptions,
|
|
27
18
|
donutChartStyles,
|
|
28
19
|
generateChartTooltipPortalId,
|
|
29
20
|
getDatavizColor,
|
|
@@ -33,16 +24,13 @@ import {
|
|
|
33
24
|
getStorybookSparseTimelineData,
|
|
34
25
|
isCategoricalHourData,
|
|
35
26
|
isHourlyTimeData,
|
|
36
|
-
lineChartOptions,
|
|
37
27
|
lineChartStyles,
|
|
38
|
-
timeSeriesChartOptions,
|
|
39
28
|
timeSeriesChartStyles,
|
|
40
29
|
transformDataToSeries,
|
|
41
30
|
transformTimeSeriesTooltipData,
|
|
42
|
-
verticalBarChartStyles,
|
|
43
31
|
xAxisLabelFormatter,
|
|
44
32
|
yAxisLabelFormatter
|
|
45
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-LC3HGWDD.js";
|
|
46
34
|
|
|
47
35
|
// src/components/AreaChart/AreaChart.tsx
|
|
48
36
|
import { memo as memo4 } from "react";
|
|
@@ -227,6 +215,163 @@ var ChartXAnnotationMarkerPortal = memo3(
|
|
|
227
215
|
|
|
228
216
|
// src/hooks/useTimeSeriesChartOptions.ts
|
|
229
217
|
import { useState as useState2, useCallback, useMemo } from "react";
|
|
218
|
+
|
|
219
|
+
// src/constants/chartOptions.ts
|
|
220
|
+
import _ from "lodash";
|
|
221
|
+
var baseChartOptions = {
|
|
222
|
+
chart: {
|
|
223
|
+
animation: false,
|
|
224
|
+
styledMode: true
|
|
225
|
+
},
|
|
226
|
+
credits: {
|
|
227
|
+
enabled: false
|
|
228
|
+
},
|
|
229
|
+
exporting: {
|
|
230
|
+
enabled: false,
|
|
231
|
+
fallbackToExportServer: false
|
|
232
|
+
},
|
|
233
|
+
legend: {
|
|
234
|
+
enabled: false
|
|
235
|
+
},
|
|
236
|
+
title: {
|
|
237
|
+
text: void 0
|
|
238
|
+
},
|
|
239
|
+
tooltip: {
|
|
240
|
+
hideDelay: 0,
|
|
241
|
+
outside: true,
|
|
242
|
+
padding: 0,
|
|
243
|
+
shape: "rect",
|
|
244
|
+
shared: true,
|
|
245
|
+
useHTML: true
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
var TIME_SERIES_CHART_HEIGHT = 275;
|
|
249
|
+
var timeSeriesChartOptions = _.merge({}, baseChartOptions, {
|
|
250
|
+
annotations: [
|
|
251
|
+
{
|
|
252
|
+
draggable: "",
|
|
253
|
+
labelOptions: {
|
|
254
|
+
useHTML: true,
|
|
255
|
+
padding: 0
|
|
256
|
+
// removes "left" property padding created by highcharts so that label is centered
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
],
|
|
260
|
+
chart: {
|
|
261
|
+
// events.click is set at the component level because of the optional onClick prop
|
|
262
|
+
height: TIME_SERIES_CHART_HEIGHT,
|
|
263
|
+
spacing: [5, 1, 0, 2]
|
|
264
|
+
},
|
|
265
|
+
plotOptions: {
|
|
266
|
+
series: {
|
|
267
|
+
animation: false,
|
|
268
|
+
clip: false,
|
|
269
|
+
marker: {
|
|
270
|
+
enabled: false,
|
|
271
|
+
states: {
|
|
272
|
+
hover: {
|
|
273
|
+
enabled: false
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
xAxis: {
|
|
280
|
+
crosshair: {
|
|
281
|
+
zIndex: 3
|
|
282
|
+
},
|
|
283
|
+
minPadding: 0,
|
|
284
|
+
// must be handled dynamically instead of css
|
|
285
|
+
maxPadding: 0,
|
|
286
|
+
// must be handled dynamically instead of css
|
|
287
|
+
type: "datetime",
|
|
288
|
+
labels: {
|
|
289
|
+
useHTML: true
|
|
290
|
+
// formatter is set at the component level because of the required text locale prop
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
yAxis: {
|
|
294
|
+
labels: {
|
|
295
|
+
useHTML: true
|
|
296
|
+
// formatter is set at the component level because of the optional yAxisLabelFormatter prop
|
|
297
|
+
},
|
|
298
|
+
softMax: 0,
|
|
299
|
+
softMin: 0,
|
|
300
|
+
title: {
|
|
301
|
+
text: void 0
|
|
302
|
+
},
|
|
303
|
+
plotLines: [
|
|
304
|
+
/* Adds a custom plotLine at y=0 to represent the chart baseline.
|
|
305
|
+
This approach allows full control over the line's appearance (e.g., color, z-index),
|
|
306
|
+
unlike relying on the default xAxis line, which always renders at the bottom of the chart
|
|
307
|
+
even when y=0 appears elsewhere (e.g., with negative values).
|
|
308
|
+
*/
|
|
309
|
+
{
|
|
310
|
+
className: "y-axis-zero-line",
|
|
311
|
+
value: 0,
|
|
312
|
+
zIndex: 3
|
|
313
|
+
// ensures the line appears over the default y=0 line, which we can't seleect as specifically
|
|
314
|
+
}
|
|
315
|
+
]
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
var lineChartOptions = _.merge({}, timeSeriesChartOptions, {
|
|
319
|
+
// plotOptions.spline.events.click is set at the component level because of the optional onClick prop
|
|
320
|
+
});
|
|
321
|
+
var areaChartOptions = _.merge({}, timeSeriesChartOptions, {
|
|
322
|
+
plotOptions: {
|
|
323
|
+
areaspline: {
|
|
324
|
+
// events.click is set at the component level because of the optional onClick prop
|
|
325
|
+
stacking: "normal"
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
var columnChartOptions = _.merge({}, timeSeriesChartOptions, {
|
|
330
|
+
plotOptions: {
|
|
331
|
+
column: {
|
|
332
|
+
stacking: "normal",
|
|
333
|
+
pointPadding: 0.25,
|
|
334
|
+
groupPadding: 0.25,
|
|
335
|
+
borderRadius: 4
|
|
336
|
+
}
|
|
337
|
+
},
|
|
338
|
+
xAxis: {
|
|
339
|
+
crosshair: false
|
|
340
|
+
},
|
|
341
|
+
yAxis: {
|
|
342
|
+
plotLines: [
|
|
343
|
+
{
|
|
344
|
+
// For stacked column charts with visible borders (e.g., white for contrast),
|
|
345
|
+
// we raise the zIndex of the y=0 plotLine to ensure it remains visible
|
|
346
|
+
// and isn't visually covered by overlapping column borders.
|
|
347
|
+
zIndex: 5
|
|
348
|
+
}
|
|
349
|
+
]
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
var VERTICAL_BAR_CHART_DEFAULT_SERIES_LIMIT = 10;
|
|
353
|
+
var DONUT_CHART_HALO_SIZE = 10;
|
|
354
|
+
var DONUT_CHART_HEIGHT = 250 + DONUT_CHART_HALO_SIZE * 2;
|
|
355
|
+
var DONUT_CHART_WIDTH = DONUT_CHART_HEIGHT;
|
|
356
|
+
var donutChartOptions = _.merge({}, baseChartOptions, {
|
|
357
|
+
chart: {
|
|
358
|
+
height: DONUT_CHART_HEIGHT,
|
|
359
|
+
spacing: [0, 0, 0, 0]
|
|
360
|
+
},
|
|
361
|
+
plotOptions: {
|
|
362
|
+
pie: {
|
|
363
|
+
animation: false,
|
|
364
|
+
borderRadius: 0,
|
|
365
|
+
// must be handled here instead of css because of path rendering
|
|
366
|
+
dataLabels: {
|
|
367
|
+
enabled: false
|
|
368
|
+
},
|
|
369
|
+
innerSize: "50%"
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
// src/hooks/useTimeSeriesChartOptions.ts
|
|
230
375
|
import { merge } from "lodash";
|
|
231
376
|
var useTimeSeriesChartOptions = ({
|
|
232
377
|
xAnnotations,
|
|
@@ -1248,6 +1393,27 @@ var VerticalBarChartTooltip = memo15(
|
|
|
1248
1393
|
|
|
1249
1394
|
// src/components/VerticalBarChart/VerticalBarChart.tsx
|
|
1250
1395
|
import { theme as theme10 } from "@sproutsocial/seeds-react-theme";
|
|
1396
|
+
|
|
1397
|
+
// src/components/VerticalBarChart/styles.ts
|
|
1398
|
+
import { css } from "styled-components";
|
|
1399
|
+
var verticalBarChartStyles = css`
|
|
1400
|
+
${timeSeriesChartStyles}
|
|
1401
|
+
|
|
1402
|
+
/*
|
|
1403
|
+
When the chart container is hovered, reduce the opacity of all columns.
|
|
1404
|
+
Then, for the column that is being hovered, restore its opacity.
|
|
1405
|
+
This gives the effect of fading out the non-hovered columns.
|
|
1406
|
+
*/
|
|
1407
|
+
.highcharts-container:hover .highcharts-point {
|
|
1408
|
+
fill-opacity: 0.3;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
.highcharts-point.column-hover {
|
|
1412
|
+
fill-opacity: 1 !important;
|
|
1413
|
+
}
|
|
1414
|
+
`;
|
|
1415
|
+
|
|
1416
|
+
// src/components/VerticalBarChart/VerticalBarChart.tsx
|
|
1251
1417
|
import { Fragment as Fragment5, jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1252
1418
|
highchartsAccessibility4(Highcharts4);
|
|
1253
1419
|
highchartsAnnotations3(Highcharts4);
|