@sproutsocial/seeds-react-data-viz 0.27.2 → 0.28.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/{annotations-CjFoRPXf.d.mts → annotations-YfJndb5S.d.mts} +2 -2
- package/dist/{annotations-CjFoRPXf.d.ts → annotations-YfJndb5S.d.ts} +2 -2
- package/dist/{axis-DVx6Mn1k.d.mts → axis-Byl9vNMR.d.mts} +9 -9
- package/dist/{axis-DQXvjzBs.d.ts → axis-Cn8NAgwb.d.ts} +9 -9
- package/dist/bar/index.d.mts +25 -47
- package/dist/bar/index.d.ts +25 -47
- package/dist/bar/index.js +14 -14
- package/dist/bar/index.js.map +1 -1
- package/dist/bubble/index.d.mts +29 -40
- package/dist/bubble/index.d.ts +29 -40
- package/dist/bubble/index.js +18 -20
- package/dist/bubble/index.js.map +1 -1
- package/dist/{chartExport-CKYpuhik.d.mts → chartExport-B0imEQ8Y.d.mts} +4 -4
- package/dist/{chartExport-CKYpuhik.d.ts → chartExport-B0imEQ8Y.d.ts} +4 -4
- package/dist/{chartBase-Cd405GIA.d.mts → chartProps-BgGx1GTo.d.mts} +67 -23
- package/dist/{chartBase-BYipK7MZ.d.ts → chartProps-C2Lxty-_.d.ts} +67 -23
- package/dist/{chunk-WMKO3RGT.js → chunk-2S7XMWJ4.js} +3 -3
- package/dist/chunk-2S7XMWJ4.js.map +1 -0
- package/dist/{chunk-6EIJCJCN.js → chunk-I72SSPMX.js} +1 -1
- package/dist/chunk-I72SSPMX.js.map +1 -0
- package/dist/{chunk-CV45MD47.js → chunk-RDS2VCPO.js} +3 -3
- package/dist/chunk-RDS2VCPO.js.map +1 -0
- package/dist/{chunk-5TWNMPQU.js → chunk-V5EXL244.js} +73 -63
- package/dist/chunk-V5EXL244.js.map +1 -0
- package/dist/{chunk-34OKRQET.js → chunk-XH7ZKGHD.js} +5 -5
- package/dist/{chunk-34OKRQET.js.map → chunk-XH7ZKGHD.js.map} +1 -1
- package/dist/donut/index.d.mts +21 -36
- package/dist/donut/index.d.ts +21 -36
- package/dist/donut/index.js +8 -8
- package/dist/donut/index.js.map +1 -1
- package/dist/esm/bar/index.js +5 -5
- package/dist/esm/bar/index.js.map +1 -1
- package/dist/esm/bubble/index.js +10 -12
- package/dist/esm/bubble/index.js.map +1 -1
- package/dist/esm/{chunk-P3MVYSHX.js → chunk-37QVUJXM.js} +1 -1
- package/dist/esm/chunk-37QVUJXM.js.map +1 -0
- package/dist/esm/{chunk-332X77M5.js → chunk-JNQC3ZRQ.js} +3 -3
- package/dist/esm/chunk-JNQC3ZRQ.js.map +1 -0
- package/dist/esm/{chunk-MVNO5UV6.js → chunk-NBMVFYDJ.js} +2 -2
- package/dist/esm/chunk-NBMVFYDJ.js.map +1 -0
- package/dist/esm/{chunk-AL3OTBTT.js → chunk-THDIQMFN.js} +2 -2
- package/dist/esm/chunk-THDIQMFN.js.map +1 -0
- package/dist/esm/{chunk-CYCKJ5ML.js → chunk-YCYACOQU.js} +34 -24
- package/dist/esm/chunk-YCYACOQU.js.map +1 -0
- package/dist/esm/donut/index.js +3 -3
- package/dist/esm/donut/index.js.map +1 -1
- package/dist/esm/export/index.js.map +1 -1
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/line-area/index.js +5 -5
- package/dist/esm/line-area/index.js.map +1 -1
- package/dist/esm/sparkline/index.js +3 -3
- package/dist/esm/sparkline/index.js.map +1 -1
- package/dist/esm/wordcloud/index.js +4 -3
- package/dist/esm/wordcloud/index.js.map +1 -1
- package/dist/export/index.d.mts +5 -5
- package/dist/export/index.d.ts +5 -5
- package/dist/export/index.js.map +1 -1
- package/dist/index.js +92 -92
- package/dist/index.js.map +1 -1
- package/dist/{interactions-pEXA1XxF.d.ts → interactions-D2a4O6iM.d.mts} +8 -8
- package/dist/{interactions-pEXA1XxF.d.mts → interactions-D2a4O6iM.d.ts} +8 -8
- package/dist/line-area/index.d.mts +22 -48
- package/dist/line-area/index.d.ts +22 -48
- package/dist/line-area/index.js +14 -14
- package/dist/line-area/index.js.map +1 -1
- package/dist/pointerClick-4LUDwS3L.d.mts +15 -0
- package/dist/pointerClick-4LUDwS3L.d.ts +15 -0
- package/dist/sparkline/index.d.mts +24 -33
- package/dist/sparkline/index.d.ts +24 -33
- package/dist/sparkline/index.js +7 -7
- package/dist/sparkline/index.js.map +1 -1
- package/dist/wordcloud/index.d.mts +22 -20
- package/dist/wordcloud/index.d.ts +22 -20
- package/dist/wordcloud/index.js +11 -10
- package/dist/wordcloud/index.js.map +1 -1
- package/package.json +11 -11
- package/dist/chunk-5TWNMPQU.js.map +0 -1
- package/dist/chunk-6EIJCJCN.js.map +0 -1
- package/dist/chunk-CV45MD47.js.map +0 -1
- package/dist/chunk-WMKO3RGT.js.map +0 -1
- package/dist/esm/chunk-332X77M5.js.map +0 -1
- package/dist/esm/chunk-AL3OTBTT.js.map +0 -1
- package/dist/esm/chunk-CYCKJ5ML.js.map +0 -1
- package/dist/esm/chunk-MVNO5UV6.js.map +0 -1
- package/dist/esm/chunk-P3MVYSHX.js.map +0 -1
|
@@ -2,22 +2,22 @@ import {
|
|
|
2
2
|
buildAnnotationConfig,
|
|
3
3
|
defaultValueAxisLabelFormatter,
|
|
4
4
|
makeValueAxisLabelFormatter
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-NBMVFYDJ.js";
|
|
6
6
|
import {
|
|
7
7
|
buildDimensionalAxis,
|
|
8
8
|
resolveTooltipOptions
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-THDIQMFN.js";
|
|
10
10
|
import {
|
|
11
11
|
getChartContainerProps
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-37QVUJXM.js";
|
|
13
13
|
import {
|
|
14
14
|
ChartRenderer,
|
|
15
15
|
buildBaseChartOptions,
|
|
16
16
|
useSeedsChartSetup
|
|
17
|
-
} from "../chunk-
|
|
17
|
+
} from "../chunk-YCYACOQU.js";
|
|
18
18
|
import {
|
|
19
19
|
TIME_SERIES_CHART_HEIGHT
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-JNQC3ZRQ.js";
|
|
21
21
|
|
|
22
22
|
// src/charts/line-area/LineAreaChart.tsx
|
|
23
23
|
import { memo, useMemo } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/charts/line-area/LineAreaChart.tsx","../../../src/charts/line-area/adapter.ts"],"sourcesContent":["import { memo, useMemo } from \"react\";\nimport { useSeedsChartSetup, ChartRenderer } from \"../shared/chartBase\";\nimport { getChartContainerProps } from \"../shared/chartContainer\";\nimport { buildLineAreaChartOptions } from \"./adapter\";\nimport type { LineAreaChartProps, LineAreaVariant } from \"./types\";\n\nconst AREA_VARIANTS = new Set<LineAreaVariant>([\"area\", \"areaspline\"]);\n\n/**\n * LineAreaChart — the v2 time-series line/area family.\n *\n * Like SparklineChart, the wrapper carries no styled-components: it is a plain\n * <div> whose className / inline custom properties / data-attributes come from\n * the shared getChartContainerProps contract (CE-164), and its Highcharts\n * styling ships as a static line-area.css. chart-styles.css owns the shared\n * base (background, per-series color fallback, click cursor, tooltip, legend)\n * AND the shared cross-family .seeds-chart-time-series layer (crosshair,\n * grid/axis lines, ticks, zero line, axis-label typography) that bar also uses;\n * line-area.css owns only the .seeds-chart-line / .seeds-chart-area selectors.\n * Neither is imported here — matching the Sparkline/bar convention, the component never\n * self-imports its stylesheet; consumers import both explicitly (see\n * charts/README.md).\n */\nexport const LineAreaChart = memo(function LineAreaChart(\n props: LineAreaChartProps\n) {\n const { colors, patterns } = useSeedsChartSetup({\n series: props.series,\n includePatterns: true,\n });\n const { options, annotationLookup, tooltipOptions } = useMemo(\n () => buildLineAreaChartOptions(props),\n [props]\n );\n const hasOnClick = Boolean(props.onClick);\n const isArea = AREA_VARIANTS.has(props.variant);\n\n return (\n <div\n {...getChartContainerProps({\n familyClasses: [\n \"seeds-chart-time-series\",\n isArea ? \"seeds-chart-area\" : \"seeds-chart-line\",\n ],\n // RAW per-series colors: only an explicit consumer override is inlined\n // as --highcharts-color-N; an unset series falls through to the DS\n // palette default in chart-styles.css. ChartRenderer below still gets\n // the palette-RESOLVED `colors` for its own styled-components engine.\n colors: props.series.map((s) => s.color),\n patterns,\n hasOnClick,\n className: props.className,\n })}\n >\n <ChartRenderer\n options={options}\n series={props.series}\n colors={colors}\n tooltip={props.tooltip}\n annotationLookup={annotationLookup}\n hasOnClick={hasOnClick}\n tooltipClickLabel={props.tooltipClickLabel}\n tooltipOptions={tooltipOptions}\n invalidNumberLabel={props.invalidNumberLabel}\n valueFormat={props.yAxis?.format}\n exportTitle={props.exportTitle}\n onReady={props.onReady}\n />\n </div>\n );\n});\n","import { buildAnnotationConfig } from \"../shared/annotations\";\nimport type { ChartAnnotationLookup } from \"../shared/annotations\";\nimport type {\n ChartTooltipProps,\n SeedsChartDataPoint,\n SeedsChartOptions,\n} from \"../shared/chartBase\";\nimport { buildBaseChartOptions } from \"../shared/baseChartOptions\";\nimport { TIME_SERIES_CHART_HEIGHT } from \"../../constants/chartOptions\";\nimport {\n buildDimensionalAxis,\n resolveTooltipOptions,\n} from \"../shared/axisOptions\";\nimport {\n defaultValueAxisLabelFormatter,\n makeValueAxisLabelFormatter,\n} from \"../shared/valueAxisLabelFormatter\";\nimport type { ChartDataPoint } from \"../shared/axis\";\nimport type { LineAreaChartProps, LineAreaVariant } from \"./types\";\n\n// `stacking` is meaningful only for filled variants; on `line`/`spline` it's a\n// no-op, so the adapter drops it rather than emitting a misleading option.\nconst AREA_VARIANTS = new Set<LineAreaVariant>([\"area\", \"areaspline\"]);\n\ntype SeriesPoint =\n | number\n | null\n | [number, number | null]\n | SeedsChartDataPoint;\n\nfunction pointY(point: ChartDataPoint): number | null {\n if (point === null) return null;\n if (typeof point === \"number\") return point;\n if (Array.isArray(point)) return point[1];\n return point.y;\n}\n\n// Point markers are hidden by default (set on `plotOptions.series`), but an\n// *isolated* non-null point — one with a null (or the chart edge) on both\n// sides — gets a circle marker so a point with no connecting line segment\n// stays visible. Connected points pass through unchanged so the line/area\n// renders dot-free, matching the designs.\nfunction withIsolatedPointMarkers(\n data: ReadonlyArray<ChartDataPoint>\n): SeriesPoint[] {\n return data.map((point, i): SeriesPoint => {\n if (point === null) return null; // explicit gap\n if (pointY(point) === null) return point; // tuple/object with null y — a gap\n const prevY = i === 0 ? null : pointY(data[i - 1]!);\n const nextY = i === data.length - 1 ? null : pointY(data[i + 1]!);\n if (prevY !== null || nextY !== null) return point; // connected → no marker\n const marker = { enabled: true, symbol: \"circle\" as const };\n if (typeof point === \"number\") return { y: point, marker };\n if (Array.isArray(point)) return { x: point[0], y: point[1], marker };\n return { ...point, marker };\n });\n}\n\nexport function buildLineAreaChartOptions(props: LineAreaChartProps): {\n options: SeedsChartOptions;\n annotationLookup: ChartAnnotationLookup | undefined;\n /** Resolved datetime-derived tooltip options (timezone / timeFormat / textLocale); all undefined on category axes. */\n tooltipOptions: Pick<\n ChartTooltipProps,\n \"timezone\" | \"timeFormat\" | \"textLocale\"\n >;\n} {\n const tooltipOptions = resolveTooltipOptions(props);\n const isStacked = AREA_VARIANTS.has(props.variant) && Boolean(props.stacking);\n const { annotations, lookup: annotationLookup } = buildAnnotationConfig(\n props.annotations\n );\n\n const base = buildBaseChartOptions({\n type: props.variant,\n description: props.description,\n reserveTopMargin: Boolean(annotations),\n timezone: tooltipOptions.timezone,\n });\n\n const options: SeedsChartOptions = {\n ...base,\n // Default height baseline (overridable via `props.height`) so consumers\n // who don't configure sizing keep the design-reviewed default.\n chart: {\n ...base.chart,\n // Re-assert the definite `type` so spreading the optionally-typed\n // `base.chart` doesn't widen the required `type` field to optional.\n type: props.variant,\n height: props.height ?? TIME_SERIES_CHART_HEIGHT,\n // Tight time-series spacing (from constants/chartOptions.ts) so the plot\n // area fills the 275px container; without it Highcharts' larger default\n // spacing ([10, 10, 15, 10]) shrinks the plot area.\n spacing: [5, 1, 0, 2],\n },\n xAxis: buildDimensionalAxis(props.xAxis, tooltipOptions.timezone ?? \"UTC\"),\n yAxis: {\n min: props.yAxis?.min,\n max: props.yAxis?.max,\n // Anchor the value axis to 0 (as the bar/area families do): line/spline otherwise\n // auto-scale above 0, which truncates the axis and pushes the annotation\n // anchor (y: 0) out of range. `soft` still extends for negative data.\n softMin: 0,\n softMax: 0,\n gridLineWidth: props.yAxis?.showGridLines === false ? 0 : 1,\n // A dedicated plotLine at 0, styled distinctly from regular gridlines\n // (see chartStyles.ts).\n plotLines: [{ value: 0, className: \"y-axis-zero-line\", zIndex: 3 }],\n title: { text: props.yAxis?.title ?? \"\" },\n // Zero-config default: abbreviate value-axis ticks (1.20K / 1.20M / 1.20B).\n labels: {\n // A declarative `format` drives ticks through the shared valueFormatter;\n // absent it, the zero-config decimal default (1.20K / 1.20M / 1.20B).\n formatter: props.yAxis?.format\n ? makeValueAxisLabelFormatter(props.yAxis.format)\n : defaultValueAxisLabelFormatter,\n },\n },\n plotOptions: {\n series: {\n animation: false,\n // Hide point markers by default (per the designs); isolated points\n // re-enable their own marker via `withIsolatedPointMarkers`.\n marker: { enabled: false },\n ...(props.onClick || props.onMouseEnter || props.onMouseLeave\n ? {\n point: {\n events: {\n click: props.onClick\n ? (event) => props.onClick!({ position: event.point.x })\n : undefined,\n mouseOver: props.onMouseEnter\n ? function (this: { x: number | string }) {\n props.onMouseEnter!({ position: this.x });\n }\n : undefined,\n mouseOut: props.onMouseLeave\n ? function (this: { x: number | string }) {\n props.onMouseLeave!({ position: this.x });\n }\n : undefined,\n },\n },\n }\n : {}),\n },\n // Type-scoped stacking: only the (area) variant stacks. `isStacked` already\n // guarantees `props.variant` is an area variant here, so the computed key is\n // always a valid plotOptions slot. Matches bar's per-type placement and keeps\n // line/spline unstacked.\n ...(isStacked ? { [props.variant]: { stacking: props.stacking } } : {}),\n },\n series: props.series.map((s) => ({\n type: props.variant,\n name: s.name,\n data: withIsolatedPointMarkers(s.data),\n })),\n ...(annotations ? { annotations } : {}),\n };\n\n return { options, annotationLookup, tooltipOptions };\n}\n"],"mappings":"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","names":["AREA_VARIANTS","LineAreaChart"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/line-area/LineAreaChart.tsx","../../../src/charts/line-area/adapter.ts"],"sourcesContent":["import { memo, useMemo } from \"react\";\nimport { useSeedsChartSetup, ChartRenderer } from \"../shared/chartBase\";\nimport { getChartContainerProps } from \"../shared/chartContainer\";\nimport { buildLineAreaChartOptions } from \"./adapter\";\nimport type { TypeLineAreaChartProps, TypeLineAreaVariant } from \"./types\";\n\nconst AREA_VARIANTS = new Set<TypeLineAreaVariant>([\"area\", \"areaspline\"]);\n\n/**\n * LineAreaChart — the v2 time-series line/area family.\n *\n * Like SparklineChart, the wrapper carries no styled-components: it is a plain\n * <div> whose className / inline custom properties / data-attributes come from\n * the shared getChartContainerProps contract (CE-164), and its Highcharts\n * styling ships as a static line-area.css. chart-styles.css owns the shared\n * base (background, per-series color fallback, click cursor, tooltip, legend)\n * AND the shared cross-family .seeds-chart-time-series layer (crosshair,\n * grid/axis lines, ticks, zero line, axis-label typography) that bar also uses;\n * line-area.css owns only the .seeds-chart-line / .seeds-chart-area selectors.\n * Neither is imported here — matching the Sparkline/bar convention, the component never\n * self-imports its stylesheet; consumers import both explicitly (see\n * charts/README.md).\n */\nexport const LineAreaChart = memo(function LineAreaChart(\n props: TypeLineAreaChartProps\n) {\n const { colors, patterns } = useSeedsChartSetup({\n series: props.series,\n includePatterns: true,\n });\n const { options, annotationLookup, tooltipOptions } = useMemo(\n () => buildLineAreaChartOptions(props),\n [props]\n );\n const hasOnClick = Boolean(props.onClick);\n const isArea = AREA_VARIANTS.has(props.variant);\n\n return (\n <div\n {...getChartContainerProps({\n familyClasses: [\n \"seeds-chart-time-series\",\n isArea ? \"seeds-chart-area\" : \"seeds-chart-line\",\n ],\n // RAW per-series colors: only an explicit consumer override is inlined\n // as --highcharts-color-N; an unset series falls through to the DS\n // palette default in chart-styles.css. ChartRenderer below still gets\n // the palette-RESOLVED `colors` for its own styled-components engine.\n colors: props.series.map((s) => s.color),\n patterns,\n hasOnClick,\n className: props.className,\n })}\n >\n <ChartRenderer\n options={options}\n series={props.series}\n colors={colors}\n tooltip={props.tooltip}\n annotationLookup={annotationLookup}\n hasOnClick={hasOnClick}\n tooltipClickLabel={props.tooltipClickLabel}\n tooltipOptions={tooltipOptions}\n invalidNumberLabel={props.invalidNumberLabel}\n valueFormat={props.yAxis?.format}\n exportTitle={props.exportTitle}\n onReady={props.onReady}\n />\n </div>\n );\n});\n","import { buildAnnotationConfig } from \"../shared/annotations\";\nimport type { TypeChartAnnotationLookup } from \"../shared/annotations\";\nimport type {\n TypeSeedsChartDataPoint,\n TypeSeedsChartOptions,\n} from \"../shared/chartBase\";\nimport type { TypeChartTooltipRenderProps } from \"../shared/chartTooltip\";\nimport { buildBaseChartOptions } from \"../shared/baseChartOptions\";\nimport { TIME_SERIES_CHART_HEIGHT } from \"../../constants/chartOptions\";\nimport {\n buildDimensionalAxis,\n resolveTooltipOptions,\n} from \"../shared/axisOptions\";\nimport {\n defaultValueAxisLabelFormatter,\n makeValueAxisLabelFormatter,\n} from \"../shared/valueAxisLabelFormatter\";\nimport type { TypeChartDataPoint } from \"../shared/axis\";\nimport type { TypeLineAreaChartProps, TypeLineAreaVariant } from \"./types\";\n\n// `stacking` is meaningful only for filled variants; on `line`/`spline` it's a\n// no-op, so the adapter drops it rather than emitting a misleading option.\nconst AREA_VARIANTS = new Set<TypeLineAreaVariant>([\"area\", \"areaspline\"]);\n\ntype SeriesPoint =\n | number\n | null\n | [number, number | null]\n | TypeSeedsChartDataPoint;\n\nfunction pointY(point: TypeChartDataPoint): number | null {\n if (point === null) return null;\n if (typeof point === \"number\") return point;\n if (Array.isArray(point)) return point[1];\n return point.y;\n}\n\n// Point markers are hidden by default (set on `plotOptions.series`), but an\n// *isolated* non-null point — one with a null (or the chart edge) on both\n// sides — gets a circle marker so a point with no connecting line segment\n// stays visible. Connected points pass through unchanged so the line/area\n// renders dot-free, matching the designs.\nfunction withIsolatedPointMarkers(\n data: readonly TypeChartDataPoint[]\n): SeriesPoint[] {\n return data.map((point, i): SeriesPoint => {\n if (point === null) return null; // explicit gap\n if (pointY(point) === null) return point; // tuple/object with null y — a gap\n const prevY = i === 0 ? null : pointY(data[i - 1]!);\n const nextY = i === data.length - 1 ? null : pointY(data[i + 1]!);\n if (prevY !== null || nextY !== null) return point; // connected → no marker\n const marker = { enabled: true, symbol: \"circle\" as const };\n if (typeof point === \"number\") return { y: point, marker };\n if (Array.isArray(point)) return { x: point[0], y: point[1], marker };\n return { ...point, marker };\n });\n}\n\nexport function buildLineAreaChartOptions(props: TypeLineAreaChartProps): {\n options: TypeSeedsChartOptions;\n annotationLookup: TypeChartAnnotationLookup | undefined;\n /** Resolved datetime-derived tooltip options (timezone / timeFormat / textLocale); all undefined on category axes. */\n tooltipOptions: Pick<\n TypeChartTooltipRenderProps,\n \"timezone\" | \"timeFormat\" | \"textLocale\"\n >;\n} {\n const tooltipOptions = resolveTooltipOptions(props);\n const isStacked = AREA_VARIANTS.has(props.variant) && Boolean(props.stacking);\n const { annotations, lookup: annotationLookup } = buildAnnotationConfig(\n props.annotations\n );\n\n const base = buildBaseChartOptions({\n type: props.variant,\n description: props.description,\n reserveTopMargin: Boolean(annotations),\n timezone: tooltipOptions.timezone,\n });\n\n const options: TypeSeedsChartOptions = {\n ...base,\n // Default height baseline (overridable via `props.height`) so consumers\n // who don't configure sizing keep the design-reviewed default.\n chart: {\n ...base.chart,\n // Re-assert the definite `type` so spreading the optionally-typed\n // `base.chart` doesn't widen the required `type` field to optional.\n type: props.variant,\n height: props.height ?? TIME_SERIES_CHART_HEIGHT,\n // Tight time-series spacing (from constants/chartOptions.ts) so the plot\n // area fills the 275px container; without it Highcharts' larger default\n // spacing ([10, 10, 15, 10]) shrinks the plot area.\n spacing: [5, 1, 0, 2],\n },\n xAxis: buildDimensionalAxis(props.xAxis, tooltipOptions.timezone ?? \"UTC\"),\n yAxis: {\n min: props.yAxis?.min,\n max: props.yAxis?.max,\n // Anchor the value axis to 0 (as the bar/area families do): line/spline otherwise\n // auto-scale above 0, which truncates the axis and pushes the annotation\n // anchor (y: 0) out of range. `soft` still extends for negative data.\n softMin: 0,\n softMax: 0,\n gridLineWidth: props.yAxis?.showGridLines === false ? 0 : 1,\n // A dedicated plotLine at 0, styled distinctly from regular gridlines\n // (see chartStyles.ts).\n plotLines: [{ value: 0, className: \"y-axis-zero-line\", zIndex: 3 }],\n title: { text: props.yAxis?.title ?? \"\" },\n // Zero-config default: abbreviate value-axis ticks (1.20K / 1.20M / 1.20B).\n labels: {\n // A declarative `format` drives ticks through the shared valueFormatter;\n // absent it, the zero-config decimal default (1.20K / 1.20M / 1.20B).\n formatter: props.yAxis?.format\n ? makeValueAxisLabelFormatter(props.yAxis.format)\n : defaultValueAxisLabelFormatter,\n },\n },\n plotOptions: {\n series: {\n animation: false,\n // Hide point markers by default (per the designs); isolated points\n // re-enable their own marker via `withIsolatedPointMarkers`.\n marker: { enabled: false },\n ...(props.onClick || props.onMouseEnter || props.onMouseLeave\n ? {\n point: {\n events: {\n click: props.onClick\n ? (event) => props.onClick!({ position: event.point.x })\n : undefined,\n mouseOver: props.onMouseEnter\n ? function (this: { x: number | string }) {\n props.onMouseEnter!({ position: this.x });\n }\n : undefined,\n mouseOut: props.onMouseLeave\n ? function (this: { x: number | string }) {\n props.onMouseLeave!({ position: this.x });\n }\n : undefined,\n },\n },\n }\n : {}),\n },\n // Type-scoped stacking: only the (area) variant stacks. `isStacked` already\n // guarantees `props.variant` is an area variant here, so the computed key is\n // always a valid plotOptions slot. Matches bar's per-type placement and keeps\n // line/spline unstacked.\n ...(isStacked ? { [props.variant]: { stacking: props.stacking } } : {}),\n },\n series: props.series.map((s) => ({\n type: props.variant,\n name: s.name,\n data: withIsolatedPointMarkers(s.data),\n })),\n ...(annotations ? { annotations } : {}),\n };\n\n return { options, annotationLookup, tooltipOptions };\n}\n"],"mappings":"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","names":["AREA_VARIANTS","LineAreaChart"]}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
buildDimensionalAxis,
|
|
3
3
|
resolveTooltipOptions
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-THDIQMFN.js";
|
|
5
5
|
import {
|
|
6
6
|
ChartRenderer,
|
|
7
7
|
buildBaseChartOptions
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-YCYACOQU.js";
|
|
9
|
+
import "../chunk-JNQC3ZRQ.js";
|
|
10
10
|
|
|
11
11
|
// src/charts/sparkline/SparklineChart.tsx
|
|
12
12
|
import { memo } from "react";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/charts/sparkline/SparklineChart.tsx","../../../src/charts/sparkline/adapter.ts","../../../src/charts/shared/trend.ts"],"sourcesContent":["import { memo, type CSSProperties } from \"react\";\nimport { useTheme } from \"styled-components\";\nimport type { TypeTheme } from \"@sproutsocial/seeds-react-theme\";\nimport { ChartRenderer } from \"../shared/chartBase\";\nimport { buildSparklineChartOptions, SPARKLINE_SERIES_NAME } from \"./adapter\";\nimport { computeTrend, resolveTrendColor } from \"./trend\";\nimport type {
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/sparkline/SparklineChart.tsx","../../../src/charts/sparkline/adapter.ts","../../../src/charts/shared/trend.ts"],"sourcesContent":["import { memo, type CSSProperties } from \"react\";\nimport { useTheme } from \"styled-components\";\nimport type { TypeTheme } from \"@sproutsocial/seeds-react-theme\";\nimport { ChartRenderer } from \"../shared/chartBase\";\nimport { buildSparklineChartOptions, SPARKLINE_SERIES_NAME } from \"./adapter\";\nimport { computeTrend, resolveTrendColor } from \"./trend\";\nimport type { TypeSparklineChartProps } from \"./types\";\n\n/**\n * SparklineChart — a compact, axis-less inline micro-chart in a `\"line\"` or\n * `\"bar\"` variant. The whole sparkline is colored by trend (auto-computed from\n * the data): green when rising, red when falling, neutral-gray when flat.\n *\n * Unlike the other v2 chart families this one carries no `styled-components`:\n * the wrapper is a plain `<div>` that accepts `className` (Tailwind sizing), and\n * the Highcharts styling lives in `sparkline.css`. Consumers must import\n * `@sproutsocial/seeds-react-data-viz/sparkline.css` once. The single trend\n * color is resolved from the JS theme and passed down as the\n * `--seeds-sparkline-color` CSS variable, so light/dark works without depending\n * on the theme's CSS-variable stylesheet.\n */\nexport const SparklineChart = memo(function SparklineChart(\n props: TypeSparklineChartProps\n) {\n // The active theme resolves the single trend color. We read it directly rather\n // than via useSeedsChartSetup — the sparkline has no categorical palette or\n // series-limit concerns, so the hook's series machinery (and its dummy series\n // input) would be dead weight. ChartRenderer below is itself a styled-\n // component, so this adds no new dependency; the \"no styled-components\" trait\n // of this family is about the wrapper being a plain <div> + static CSS.\n const theme = useTheme() as TypeTheme;\n\n const trend = computeTrend(props.data);\n const trendColor = resolveTrendColor(theme, trend);\n\n const { options, tooltipOptions } = buildSparklineChartOptions(props);\n\n const className = [\n \"seeds-sparkline\",\n `seeds-sparkline-${props.variant}`,\n props.className,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={className}\n style={{ \"--seeds-sparkline-color\": trendColor } as CSSProperties}\n >\n <ChartRenderer\n options={options}\n series={[{ name: SPARKLINE_SERIES_NAME, color: trendColor }]}\n colors={[trendColor]}\n tooltip={props.tooltip}\n tooltipOptions={tooltipOptions}\n invalidNumberLabel={props.invalidNumberLabel}\n hideLegend\n exportTitle={props.exportTitle}\n onReady={props.onReady}\n />\n </div>\n );\n});\n","import type {\n TypeSeedsChartOptions,\n TypeSeedsChartType,\n} from \"../shared/chartBase\";\nimport type { TypeChartTooltipRenderProps } from \"../shared/chartTooltip\";\nimport { buildBaseChartOptions } from \"../shared/baseChartOptions\";\nimport {\n buildDimensionalAxis,\n resolveTooltipOptions,\n} from \"../shared/axisOptions\";\nimport type { TypeSparklineChartProps, TypeSparklineVariant } from \"./types\";\n\n// A sparkline line is a `line`; a sparkline bar is a `column` (vertical bars).\nfunction highchartsType(variant: TypeSparklineVariant): TypeSeedsChartType {\n return variant === \"bar\" ? \"column\" : \"line\";\n}\n\nconst SPARKLINE_SERIES_NAME = \"sparkline\";\n\nexport function buildSparklineChartOptions(props: TypeSparklineChartProps): {\n options: TypeSeedsChartOptions;\n /** Resolved datetime-derived tooltip options (timezone / timeFormat / textLocale); all undefined without a datetime axis. */\n tooltipOptions: Pick<\n TypeChartTooltipRenderProps,\n \"timezone\" | \"timeFormat\" | \"textLocale\"\n >;\n} {\n const type = highchartsType(props.variant);\n // `resolveTooltipOptions` handles the optional `xAxis` internally (all-undefined\n // when absent), so the sparkline passes its props straight in like the other\n // families.\n const tooltipOptions = resolveTooltipOptions(props);\n\n // A configured axis is placed but hidden (labels/line/ticks off). Without one\n // we fall back to a hidden linear index axis.\n const xAxis = props.xAxis\n ? {\n ...buildDimensionalAxis(props.xAxis, tooltipOptions.timezone ?? \"UTC\"),\n visible: false,\n }\n : { type: \"linear\" as const, visible: false };\n\n const base = buildBaseChartOptions({\n type,\n description: props.description,\n timezone: tooltipOptions.timezone,\n });\n\n const options: TypeSeedsChartOptions = {\n ...base,\n // Zero the outer spacing so the plot fills the (consumer-sized) wrapper.\n chart: { type, styledMode: true, animation: false, spacing: [0, 0, 0, 0] },\n xAxis,\n yAxis: { visible: false },\n plotOptions: {\n series: {\n animation: false,\n // Decorative micro-chart: no per-point markers on the line.\n marker: { enabled: false },\n },\n // Tight padding so bars read as a compact cluster.\n column: {\n pointPadding: 0.05,\n groupPadding: 0.05,\n borderWidth: 0,\n borderRadius: 3,\n },\n },\n series: [\n {\n type,\n name: SPARKLINE_SERIES_NAME,\n data: [...props.data],\n },\n ],\n };\n\n return { options, tooltipOptions };\n}\n\nexport { SPARKLINE_SERIES_NAME };\n","import type { TypeTheme } from \"@sproutsocial/seeds-react-theme\";\nimport type { TypeChartDataPoint } from \"./axis\";\n\n// Family-agnostic trend helpers, shared across chart families. First used by the\n// sparkline (colored entirely by its trend direction); reusable by any chart\n// that wants a sentiment/directional color from a single series (e.g. a\n// sentiment chart).\n\n/**\n * Trend direction derived from a series (first vs. last finite value): rising →\n * `\"positive\"`, falling → `\"negative\"`, flat → `\"neutral\"`.\n */\nexport type TypeTrend = \"positive\" | \"negative\" | \"neutral\";\n\n/** Extract the numeric y-value from a bare number, tuple, or `{ x, y }` point. */\nfunction yValue(point: TypeChartDataPoint): number | null {\n if (point == null) return null;\n if (typeof point === \"number\") return point;\n if (Array.isArray(point)) return point[1];\n return point.y;\n}\n\n/**\n * Derive the trend from the series by comparing the first finite value to the\n * last finite value: rising → `\"positive\"`, falling → `\"negative\"`, equal (or\n * fewer than two finite values) → `\"neutral\"`.\n */\nexport function computeTrend(data: readonly TypeChartDataPoint[]): TypeTrend {\n const finite = data\n .map(yValue)\n .filter((v): v is number => v != null && Number.isFinite(v));\n\n if (finite.length < 2) return \"neutral\";\n\n const first = finite[0]!;\n const last = finite[finite.length - 1]!;\n\n if (last > first) return \"positive\";\n if (last < first) return \"negative\";\n return \"neutral\";\n}\n\n/**\n * Resolve the trend to a Seeds decorative highlight/accent color: positive →\n * vibrant green (green-500), negative → vibrant red (red-600), neutral → middle\n * gray (neutral-600). These highlight tones are theme-stable — the same value in\n * light and dark — and are designed to read as accents on either surface.\n */\nexport function resolveTrendColor(theme: TypeTheme, trend: TypeTrend): string {\n const decorative = theme.colors.container.border.decorative;\n if (trend === \"positive\") return decorative.green;\n if (trend === \"negative\") return decorative.red;\n return decorative.neutral;\n}\n"],"mappings":"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","names":["SparklineChart"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getChartContainerProps
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-37QVUJXM.js";
|
|
4
4
|
import {
|
|
5
5
|
ChartRenderer,
|
|
6
6
|
buildWordCloudOptions,
|
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
deriveMaxWordCount,
|
|
9
9
|
deriveWordPadding,
|
|
10
10
|
useSeedsChartSetup
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-YCYACOQU.js";
|
|
12
|
+
import "../chunk-JNQC3ZRQ.js";
|
|
13
13
|
|
|
14
14
|
// src/charts/wordcloud/WordCloud.tsx
|
|
15
15
|
import { memo, useMemo, useRef } from "react";
|
|
@@ -98,6 +98,7 @@ var WordCloud = memo(function WordCloud2(props) {
|
|
|
98
98
|
series: options.series?.length ? [{ name: "Word Cloud" }] : [],
|
|
99
99
|
colors,
|
|
100
100
|
hideLegend: true,
|
|
101
|
+
exportTitle: props.exportTitle,
|
|
101
102
|
onReady: props.onReady
|
|
102
103
|
}
|
|
103
104
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/charts/wordcloud/WordCloud.tsx"],"sourcesContent":["import { memo, useMemo, useRef } from \"react\";\nimport { useMeasure } from \"@sproutsocial/seeds-react-hooks\";\nimport { useSeedsChartSetup, ChartRenderer } from \"../shared/chartBase\";\nimport { getChartContainerProps } from \"../shared/chartContainer\";\nimport {\n buildWordCloudOptions,\n deriveMaxFontSize,\n deriveMaxWordCount,\n deriveWordPadding,\n} from \"./adapter\";\nimport type {\n SeedsChartWordCloudSeriesOptions,\n WordCloudGroup,\n WordCloudProps,\n} from \"./types\";\n\n/**\n * Resolves `activeGroupId` to its index in `groups` for the container's\n * `data-active-group-index` attribute (layer 2 CSS dimming, wordcloud.css).\n * An unresolvable id (unknown, or no `groups`) is treated the same as\n * null/undefined — no dimming — rather than falling back to group 0, which\n * would incorrectly mark group 0 as \"active\" and dim everything else.\n */\nfunction resolveActiveGroupIndex(\n activeGroupId: string | null | undefined,\n groups: ReadonlyArray<WordCloudGroup> | undefined\n): number | undefined {\n if (activeGroupId == null || !groups?.length) return undefined;\n const index = groups.findIndex((group) => group.id === activeGroupId);\n return index === -1 ? undefined : index;\n}\n\n/**\n * Resolves `activeNames` to the rendered indices of matching points, for the\n * container's `data-active-word-indices` attribute. Reads `points` off the\n * already-built options (not a fresh transform) so indices match what's\n * actually on screen, including `allocateWordsAcrossGroups`'s reordering.\n * Names are unbounded, unlike `activeGroupId`'s small `groups` list, so this\n * keys off each point's bounded position instead — see wordcloud.css's\n * `--index-N` rules (bounded by `WORD_CLOUD_MAXIMUM_WORD_COUNT`).\n */\nfunction resolveActiveWordIndices(\n activeNames: ReadonlyArray<string> | null | undefined,\n points: ReadonlyArray<{ name: string }> | undefined\n): ReadonlyArray<number> | undefined {\n if (!activeNames?.length || !points?.length) return undefined;\n const activeSet = new Set(activeNames);\n const indices = points\n .map((point, i) => (activeSet.has(point.name) ? i : -1))\n .filter((i) => i !== -1);\n return indices.length ? indices : undefined;\n}\n\n/**\n * WordCloud renders a Highcharts wordcloud chart from a flat list of weighted\n * words, optionally grouped (competitive coloring + externally-driven dimming\n * via `activeGroupId` or `activeNames`).\n *\n * Like BubbleChart/DonutChart, it carries no `styled-components`: the wrapper\n * is a plain `<div>` and the Highcharts styling ships as static CSS. Consumers\n * import both `@sproutsocial/seeds-react-data-viz/chart-styles.css` and\n * `.../wordcloud.css` once (the component never self-imports its CSS).\n */\nexport const WordCloud = memo(function WordCloud(props: WordCloudProps) {\n // One \"series\" input per group (or a single default entry when ungrouped),\n // matching bubble/donut's convention: colorIndex slots map 1:1 to entries\n // here, so the resolved `colors` array sizes and resolves correctly for\n // both the live chart and the styledMode:false export clone.\n const { colors } = useSeedsChartSetup({\n series: props.groups?.length\n ? props.groups.map((group) => ({ color: group.color }))\n : [{ color: undefined }],\n });\n\n const containerRef = useRef<HTMLDivElement>(null);\n // `synchronous: true` reads the container's bounds before first paint\n // instead of waiting on ResizeObserver's own (always-async) first\n // callback — otherwise every derive* below sees a false `width: 0` on\n // mount and renders the widest-case guess before snapping to the real\n // layout a tick later (the flash this family shipped with through Slice\n // 8). An explicit `props.width` skips measurement entirely.\n const { width: measuredWidth } = useMeasure(containerRef, true);\n const width = props.width ?? measuredWidth;\n // These derived values, not raw `width`, drive the memo dependency below.\n // Each is a step function of width (`deriveMaxFontSize`/`deriveMaxWordCount`/\n // `deriveWordPadding` in adapter.ts), so a resize tick that lands in the\n // same bucket for all three — most of them, during a drag-resize — leaves\n // the dependency array unchanged and the options object keeps its identity\n // instead of forcing Highcharts to re-lay out the cloud on every\n // ResizeObserver callback.\n const derivedMaxFontSize = deriveMaxFontSize(width);\n const derivedMaxWordCount = deriveMaxWordCount(width);\n const derivedWordPadding = deriveWordPadding(width);\n // Whether `activeNames` is supplied at all, not its current null/array\n // value — see `buildWordCloudOptions`'s `hasActiveNames` doc comment.\n // Stable across hover transitions, so it's safe in the memo deps below.\n const hasActiveNames = props.activeNames !== undefined;\n const options = useMemo(\n () => buildWordCloudOptions(props, width, hasActiveNames),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `width` excluded (see above); the rest is only what `buildWordCloudOptions` reads, not `props` wholesale, so an activeGroupId/activeNames/className/onReady change doesn't rebuild this.\n [\n props.data,\n props.groups,\n props.opacityRange,\n props.description,\n props.height,\n props.minFontSize,\n props.maxFontSize,\n props.wordPadding,\n props.onClick,\n props.onWordHover,\n hasActiveNames,\n derivedMaxFontSize,\n derivedMaxWordCount,\n derivedWordPadding,\n ]\n );\n const activeGroupIndex = resolveActiveGroupIndex(\n props.activeGroupId,\n props.groups\n );\n const renderedPoints = (\n options.series?.[0] as SeedsChartWordCloudSeriesOptions | undefined\n )?.data;\n const activeWordIndices = resolveActiveWordIndices(\n props.activeNames,\n renderedPoints\n );\n\n const containerProps = getChartContainerProps({\n familyClasses: [\"seeds-chart-wordcloud\"],\n // RAW per-group colors only — an unset group falls through to\n // chart-styles.css's --highcharts-color-N default, matching the\n // bubble/bar convention. Only an explicit consumer override is inlined.\n colors: props.groups?.map((group) => group.color) ?? [],\n hasOnClick: Boolean(props.onClick),\n className: props.className,\n });\n\n return (\n <div\n ref={containerRef}\n {...containerProps}\n {...(activeGroupIndex !== undefined\n ? { \"data-active-group-index\": activeGroupIndex }\n : {})}\n {...(activeWordIndices !== undefined\n ? { \"data-active-word-indices\": activeWordIndices.join(\" \") }\n : {})}\n >\n {\n // Gate the chart's one-and-only real mount on a genuinely measured\n // width. This container `<div>` still always renders (measuring it\n // is what produces `measuredWidth` in the first place) — but a\n // `width` of 0 means \"no room to lay out yet,\" not \"assume the\n // widest case,\" so nothing else renders until it's positive. This\n // is also what makes Highcharts' native center-burst entrance\n // animation (plotOptions.wordcloud.animation, above) fire on first\n // paint: `chart.hasRendered` never gets set by a wrong-then-corrected\n // double render.\n width > 0 && (\n <ChartRenderer\n options={options}\n // A single Highcharts series (all words), so a single entry here —\n // its only job is satisfying ChartRenderer's non-empty-series check,\n // since hideLegend suppresses the legend this would otherwise feed.\n series={options.series?.length ? [{ name: \"Word Cloud\" }] : []}\n colors={colors}\n hideLegend\n onReady={props.onReady}\n />\n )\n }\n </div>\n );\n});\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,MAAM,SAAS,cAAc;AACtC,SAAS,kBAAkB;AAgKjB;AA1IV,SAAS,wBACP,eACA,QACoB;AACpB,MAAI,iBAAiB,QAAQ,CAAC,QAAQ,OAAQ,QAAO;AACrD,QAAM,QAAQ,OAAO,UAAU,CAAC,UAAU,MAAM,OAAO,aAAa;AACpE,SAAO,UAAU,KAAK,SAAY;AACpC;AAWA,SAAS,yBACP,aACA,QACmC;AACnC,MAAI,CAAC,aAAa,UAAU,CAAC,QAAQ,OAAQ,QAAO;AACpD,QAAM,YAAY,IAAI,IAAI,WAAW;AACrC,QAAM,UAAU,OACb,IAAI,CAAC,OAAO,MAAO,UAAU,IAAI,MAAM,IAAI,IAAI,IAAI,EAAG,EACtD,OAAO,CAAC,MAAM,MAAM,EAAE;AACzB,SAAO,QAAQ,SAAS,UAAU;AACpC;AAYO,IAAM,YAAY,KAAK,SAASA,WAAU,OAAuB;AAKtE,QAAM,EAAE,OAAO,IAAI,mBAAmB;AAAA,IACpC,QAAQ,MAAM,QAAQ,SAClB,MAAM,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,MAAM,MAAM,EAAE,IACpD,CAAC,EAAE,OAAO,OAAU,CAAC;AAAA,EAC3B,CAAC;AAED,QAAM,eAAe,OAAuB,IAAI;AAOhD,QAAM,EAAE,OAAO,cAAc,IAAI,WAAW,cAAc,IAAI;AAC9D,QAAM,QAAQ,MAAM,SAAS;AAQ7B,QAAM,qBAAqB,kBAAkB,KAAK;AAClD,QAAM,sBAAsB,mBAAmB,KAAK;AACpD,QAAM,qBAAqB,kBAAkB,KAAK;AAIlD,QAAM,iBAAiB,MAAM,gBAAgB;AAC7C,QAAM,UAAU;AAAA,IACd,MAAM,sBAAsB,OAAO,OAAO,cAAc;AAAA;AAAA,IAExD;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,mBAAmB;AAAA,IACvB,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACA,QAAM,iBACJ,QAAQ,SAAS,CAAC,GACjB;AACH,QAAM,oBAAoB;AAAA,IACxB,MAAM;AAAA,IACN;AAAA,EACF;AAEA,QAAM,iBAAiB,uBAAuB;AAAA,IAC5C,eAAe,CAAC,uBAAuB;AAAA;AAAA;AAAA;AAAA,IAIvC,QAAQ,MAAM,QAAQ,IAAI,CAAC,UAAU,MAAM,KAAK,KAAK,CAAC;AAAA,IACtD,YAAY,QAAQ,MAAM,OAAO;AAAA,IACjC,WAAW,MAAM;AAAA,EACnB,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACJ,GAAG;AAAA,MACH,GAAI,qBAAqB,SACtB,EAAE,2BAA2B,iBAAiB,IAC9C,CAAC;AAAA,MACJ,GAAI,sBAAsB,SACvB,EAAE,4BAA4B,kBAAkB,KAAK,GAAG,EAAE,IAC1D,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYH,kBAAQ,KACN;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UAIA,QAAQ,QAAQ,QAAQ,SAAS,CAAC,EAAE,MAAM,aAAa,CAAC,IAAI,CAAC;AAAA,UAC7D;AAAA,UACA,YAAU;AAAA,UACV,SAAS,MAAM;AAAA;AAAA,MACjB;AAAA;AAAA,EAGN;AAEJ,CAAC;","names":["WordCloud"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/charts/wordcloud/WordCloud.tsx"],"sourcesContent":["import { memo, useMemo, useRef } from \"react\";\nimport { useMeasure } from \"@sproutsocial/seeds-react-hooks\";\nimport { useSeedsChartSetup, ChartRenderer } from \"../shared/chartBase\";\nimport { getChartContainerProps } from \"../shared/chartContainer\";\nimport {\n buildWordCloudOptions,\n deriveMaxFontSize,\n deriveMaxWordCount,\n deriveWordPadding,\n} from \"./adapter\";\nimport type {\n TypeSeedsChartWordCloudSeriesOptions,\n TypeWordCloudGroup,\n TypeWordCloudProps,\n} from \"./types\";\n\n/**\n * Resolves `activeGroupId` to its index in `groups` for the container's\n * `data-active-group-index` attribute (layer 2 CSS dimming, wordcloud.css).\n * An unresolvable id (unknown, or no `groups`) is treated the same as\n * null/undefined — no dimming — rather than falling back to group 0, which\n * would incorrectly mark group 0 as \"active\" and dim everything else.\n */\nfunction resolveActiveGroupIndex(\n activeGroupId: string | null | undefined,\n groups: readonly TypeWordCloudGroup[] | undefined\n): number | undefined {\n if (activeGroupId == null || !groups?.length) return undefined;\n const index = groups.findIndex((group) => group.id === activeGroupId);\n return index === -1 ? undefined : index;\n}\n\n/**\n * Resolves `activeNames` to the rendered indices of matching points, for the\n * container's `data-active-word-indices` attribute. Reads `points` off the\n * already-built options (not a fresh transform) so indices match what's\n * actually on screen, including `allocateWordsAcrossGroups`'s reordering.\n * Names are unbounded, unlike `activeGroupId`'s small `groups` list, so this\n * keys off each point's bounded position instead — see wordcloud.css's\n * `--index-N` rules (bounded by `WORD_CLOUD_MAXIMUM_WORD_COUNT`).\n */\nfunction resolveActiveWordIndices(\n activeNames: readonly string[] | null | undefined,\n points: readonly { name: string }[] | undefined\n): readonly number[] | undefined {\n if (!activeNames?.length || !points?.length) return undefined;\n const activeSet = new Set(activeNames);\n const indices = points\n .map((point, i) => (activeSet.has(point.name) ? i : -1))\n .filter((i) => i !== -1);\n return indices.length ? indices : undefined;\n}\n\n/**\n * WordCloud renders a Highcharts wordcloud chart from a flat list of weighted\n * words, optionally grouped (competitive coloring + externally-driven dimming\n * via `activeGroupId` or `activeNames`).\n *\n * Like BubbleChart/DonutChart, it carries no `styled-components`: the wrapper\n * is a plain `<div>` and the Highcharts styling ships as static CSS. Consumers\n * import both `@sproutsocial/seeds-react-data-viz/chart-styles.css` and\n * `.../wordcloud.css` once (the component never self-imports its CSS).\n */\nexport const WordCloud = memo(function WordCloud(props: TypeWordCloudProps) {\n // One \"series\" input per group (or a single default entry when ungrouped),\n // matching bubble/donut's convention: colorIndex slots map 1:1 to entries\n // here, so the resolved `colors` array sizes and resolves correctly for\n // both the live chart and the styledMode:false export clone.\n const { colors } = useSeedsChartSetup({\n series: props.groups?.length\n ? props.groups.map((group) => ({ color: group.color }))\n : [{ color: undefined }],\n });\n\n const containerRef = useRef<HTMLDivElement>(null);\n // `synchronous: true` reads the container's bounds before first paint\n // instead of waiting on ResizeObserver's own (always-async) first\n // callback — otherwise every derive* below sees a false `width: 0` on\n // mount and renders the widest-case guess before snapping to the real\n // layout a tick later (the flash this family shipped with through Slice\n // 8). An explicit `props.width` skips measurement entirely.\n const { width: measuredWidth } = useMeasure(containerRef, true);\n const width = props.width ?? measuredWidth;\n // These derived values, not raw `width`, drive the memo dependency below.\n // Each is a step function of width (`deriveMaxFontSize`/`deriveMaxWordCount`/\n // `deriveWordPadding` in adapter.ts), so a resize tick that lands in the\n // same bucket for all three — most of them, during a drag-resize — leaves\n // the dependency array unchanged and the options object keeps its identity\n // instead of forcing Highcharts to re-lay out the cloud on every\n // ResizeObserver callback.\n const derivedMaxFontSize = deriveMaxFontSize(width);\n const derivedMaxWordCount = deriveMaxWordCount(width);\n const derivedWordPadding = deriveWordPadding(width);\n // Whether `activeNames` is supplied at all, not its current null/array\n // value — see `buildWordCloudOptions`'s `hasActiveNames` doc comment.\n // Stable across hover transitions, so it's safe in the memo deps below.\n const hasActiveNames = props.activeNames !== undefined;\n const options = useMemo(\n () => buildWordCloudOptions(props, width, hasActiveNames),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- `width` excluded (see above); the rest is only what `buildWordCloudOptions` reads, not `props` wholesale, so an activeGroupId/activeNames/className/onReady change doesn't rebuild this.\n [\n props.data,\n props.groups,\n props.opacityRange,\n props.description,\n props.height,\n props.minFontSize,\n props.maxFontSize,\n props.wordPadding,\n props.onClick,\n props.onWordHover,\n hasActiveNames,\n derivedMaxFontSize,\n derivedMaxWordCount,\n derivedWordPadding,\n ]\n );\n const activeGroupIndex = resolveActiveGroupIndex(\n props.activeGroupId,\n props.groups\n );\n const renderedPoints = (\n options.series?.[0] as TypeSeedsChartWordCloudSeriesOptions | undefined\n )?.data;\n const activeWordIndices = resolveActiveWordIndices(\n props.activeNames,\n renderedPoints\n );\n\n const containerProps = getChartContainerProps({\n familyClasses: [\"seeds-chart-wordcloud\"],\n // RAW per-group colors only — an unset group falls through to\n // chart-styles.css's --highcharts-color-N default, matching the\n // bubble/bar convention. Only an explicit consumer override is inlined.\n colors: props.groups?.map((group) => group.color) ?? [],\n hasOnClick: Boolean(props.onClick),\n className: props.className,\n });\n\n return (\n <div\n ref={containerRef}\n {...containerProps}\n {...(activeGroupIndex !== undefined\n ? { \"data-active-group-index\": activeGroupIndex }\n : {})}\n {...(activeWordIndices !== undefined\n ? { \"data-active-word-indices\": activeWordIndices.join(\" \") }\n : {})}\n >\n {\n // Gate the chart's one-and-only real mount on a genuinely measured\n // width. This container `<div>` still always renders (measuring it\n // is what produces `measuredWidth` in the first place) — but a\n // `width` of 0 means \"no room to lay out yet,\" not \"assume the\n // widest case,\" so nothing else renders until it's positive. This\n // is also what makes Highcharts' native center-burst entrance\n // animation (plotOptions.wordcloud.animation, above) fire on first\n // paint: `chart.hasRendered` never gets set by a wrong-then-corrected\n // double render.\n width > 0 && (\n <ChartRenderer\n options={options}\n // A single Highcharts series (all words), so a single entry here —\n // its only job is satisfying ChartRenderer's non-empty-series check,\n // since hideLegend suppresses the legend this would otherwise feed.\n series={options.series?.length ? [{ name: \"Word Cloud\" }] : []}\n colors={colors}\n hideLegend\n exportTitle={props.exportTitle}\n onReady={props.onReady}\n />\n )\n }\n </div>\n );\n});\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,MAAM,SAAS,cAAc;AACtC,SAAS,kBAAkB;AAgKjB;AA1IV,SAAS,wBACP,eACA,QACoB;AACpB,MAAI,iBAAiB,QAAQ,CAAC,QAAQ,OAAQ,QAAO;AACrD,QAAM,QAAQ,OAAO,UAAU,CAAC,UAAU,MAAM,OAAO,aAAa;AACpE,SAAO,UAAU,KAAK,SAAY;AACpC;AAWA,SAAS,yBACP,aACA,QAC+B;AAC/B,MAAI,CAAC,aAAa,UAAU,CAAC,QAAQ,OAAQ,QAAO;AACpD,QAAM,YAAY,IAAI,IAAI,WAAW;AACrC,QAAM,UAAU,OACb,IAAI,CAAC,OAAO,MAAO,UAAU,IAAI,MAAM,IAAI,IAAI,IAAI,EAAG,EACtD,OAAO,CAAC,MAAM,MAAM,EAAE;AACzB,SAAO,QAAQ,SAAS,UAAU;AACpC;AAYO,IAAM,YAAY,KAAK,SAASA,WAAU,OAA2B;AAK1E,QAAM,EAAE,OAAO,IAAI,mBAAmB;AAAA,IACpC,QAAQ,MAAM,QAAQ,SAClB,MAAM,OAAO,IAAI,CAAC,WAAW,EAAE,OAAO,MAAM,MAAM,EAAE,IACpD,CAAC,EAAE,OAAO,OAAU,CAAC;AAAA,EAC3B,CAAC;AAED,QAAM,eAAe,OAAuB,IAAI;AAOhD,QAAM,EAAE,OAAO,cAAc,IAAI,WAAW,cAAc,IAAI;AAC9D,QAAM,QAAQ,MAAM,SAAS;AAQ7B,QAAM,qBAAqB,kBAAkB,KAAK;AAClD,QAAM,sBAAsB,mBAAmB,KAAK;AACpD,QAAM,qBAAqB,kBAAkB,KAAK;AAIlD,QAAM,iBAAiB,MAAM,gBAAgB;AAC7C,QAAM,UAAU;AAAA,IACd,MAAM,sBAAsB,OAAO,OAAO,cAAc;AAAA;AAAA,IAExD;AAAA,MACE,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,mBAAmB;AAAA,IACvB,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACA,QAAM,iBACJ,QAAQ,SAAS,CAAC,GACjB;AACH,QAAM,oBAAoB;AAAA,IACxB,MAAM;AAAA,IACN;AAAA,EACF;AAEA,QAAM,iBAAiB,uBAAuB;AAAA,IAC5C,eAAe,CAAC,uBAAuB;AAAA;AAAA;AAAA;AAAA,IAIvC,QAAQ,MAAM,QAAQ,IAAI,CAAC,UAAU,MAAM,KAAK,KAAK,CAAC;AAAA,IACtD,YAAY,QAAQ,MAAM,OAAO;AAAA,IACjC,WAAW,MAAM;AAAA,EACnB,CAAC;AAED,SACE;AAAA,IAAC;AAAA;AAAA,MACC,KAAK;AAAA,MACJ,GAAG;AAAA,MACH,GAAI,qBAAqB,SACtB,EAAE,2BAA2B,iBAAiB,IAC9C,CAAC;AAAA,MACJ,GAAI,sBAAsB,SACvB,EAAE,4BAA4B,kBAAkB,KAAK,GAAG,EAAE,IAC1D,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYH,kBAAQ,KACN;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UAIA,QAAQ,QAAQ,QAAQ,SAAS,CAAC,EAAE,MAAM,aAAa,CAAC,IAAI,CAAC;AAAA,UAC7D;AAAA,UACA,YAAU;AAAA,UACV,aAAa,MAAM;AAAA,UACnB,SAAS,MAAM;AAAA;AAAA,MACjB;AAAA;AAAA,EAGN;AAEJ,CAAC;","names":["WordCloud"]}
|
package/dist/export/index.d.mts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
2
|
+
import { T as TypeChartExportHandle, a as TypeChartExportFormat } from '../chartExport-B0imEQ8Y.mjs';
|
|
3
3
|
|
|
4
4
|
interface ChartExportMenuProps {
|
|
5
5
|
/** The opaque export handle surfaced by a v2 chart's `onReady` callback. */
|
|
6
|
-
exportHandle:
|
|
6
|
+
exportHandle: TypeChartExportHandle;
|
|
7
7
|
/**
|
|
8
8
|
* Visible labels per format. Only formats with a non-empty label render an
|
|
9
9
|
* item; an empty object (or all-falsy labels) renders nothing — no dead
|
|
10
10
|
* trigger. Items always render in canonical order, never in key-insertion
|
|
11
11
|
* order.
|
|
12
12
|
*/
|
|
13
|
-
labels: Partial<Record<
|
|
13
|
+
labels: Partial<Record<TypeChartExportFormat, string>>;
|
|
14
14
|
/** Accessible name for the icon-only trigger button. */
|
|
15
15
|
triggerAriaLabel: string;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Icon-only overflow button that opens a dropdown of chart export actions
|
|
19
19
|
* (PNG/SVG/PDF/CSV) for greenfield consumers, so they don't have to wire up
|
|
20
|
-
* their own menu around the `
|
|
20
|
+
* their own menu around the `TypeChartExportHandle` from `onReady`. Consumes only
|
|
21
21
|
* the opaque handle — no Highcharts type crosses this boundary.
|
|
22
22
|
*/
|
|
23
23
|
declare function ChartExportMenu({ exportHandle, labels, triggerAriaLabel, }: ChartExportMenuProps): react_jsx_runtime.JSX.Element | null;
|
|
24
24
|
|
|
25
|
-
export {
|
|
25
|
+
export { ChartExportMenu, type ChartExportMenuProps, TypeChartExportFormat, TypeChartExportHandle };
|
package/dist/export/index.d.ts
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
2
|
+
import { T as TypeChartExportHandle, a as TypeChartExportFormat } from '../chartExport-B0imEQ8Y.js';
|
|
3
3
|
|
|
4
4
|
interface ChartExportMenuProps {
|
|
5
5
|
/** The opaque export handle surfaced by a v2 chart's `onReady` callback. */
|
|
6
|
-
exportHandle:
|
|
6
|
+
exportHandle: TypeChartExportHandle;
|
|
7
7
|
/**
|
|
8
8
|
* Visible labels per format. Only formats with a non-empty label render an
|
|
9
9
|
* item; an empty object (or all-falsy labels) renders nothing — no dead
|
|
10
10
|
* trigger. Items always render in canonical order, never in key-insertion
|
|
11
11
|
* order.
|
|
12
12
|
*/
|
|
13
|
-
labels: Partial<Record<
|
|
13
|
+
labels: Partial<Record<TypeChartExportFormat, string>>;
|
|
14
14
|
/** Accessible name for the icon-only trigger button. */
|
|
15
15
|
triggerAriaLabel: string;
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
18
|
* Icon-only overflow button that opens a dropdown of chart export actions
|
|
19
19
|
* (PNG/SVG/PDF/CSV) for greenfield consumers, so they don't have to wire up
|
|
20
|
-
* their own menu around the `
|
|
20
|
+
* their own menu around the `TypeChartExportHandle` from `onReady`. Consumes only
|
|
21
21
|
* the opaque handle — no Highcharts type crosses this boundary.
|
|
22
22
|
*/
|
|
23
23
|
declare function ChartExportMenu({ exportHandle, labels, triggerAriaLabel, }: ChartExportMenuProps): react_jsx_runtime.JSX.Element | null;
|
|
24
24
|
|
|
25
|
-
export {
|
|
25
|
+
export { ChartExportMenu, type ChartExportMenuProps, TypeChartExportFormat, TypeChartExportHandle };
|
package/dist/export/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/export/index.js","../../src/export/ChartExportMenu.tsx"],"names":[],"mappings":"AAAA;ACAA,2DAAqC;AACrC,oEAAuB;AACvB,gEAAqB;AAiDX,+CAAA;AA5BV,IAAM,MAAA,
|
|
1
|
+
{"version":3,"sources":["/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/export/index.js","../../src/export/ChartExportMenu.tsx"],"names":[],"mappings":"AAAA;ACAA,2DAAqC;AACrC,oEAAuB;AACvB,gEAAqB;AAiDX,+CAAA;AA5BV,IAAM,MAAA,EAAiC,CAAC,KAAA,EAAO,KAAA,EAAO,KAAA,EAAO,KAAK,CAAA;AAGlE,IAAM,OAAA,EAAqE;AAAA,EACzE,GAAA,EAAK,WAAA;AAAA,EACL,GAAA,EAAK,WAAA;AAAA,EACL,GAAA,EAAK,WAAA;AAAA,EACL,GAAA,EAAK;AACP,CAAA;AAQO,SAAS,eAAA,CAAgB;AAAA,EAC9B,YAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAyB;AACvB,EAAA,MAAM,QAAA,EAAU,KAAA,CAAM,MAAA,CAAO,CAAC,MAAA,EAAA,GAAW,MAAA,CAAO,MAAM,CAAC,CAAA;AACvD,EAAA,GAAA,CAAI,OAAA,CAAQ,OAAA,IAAW,CAAA,EAAG,OAAO,IAAA;AAEjC,EAAA,uBACE,6BAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,OAAA,kBACE,6BAAA,wBAAC,EAAA,EAAO,UAAA,EAAW,WAAA,EAAY,SAAA,EAAW,gBAAA,EACxC,QAAA,kBAAA,6BAAA,oBAAC,EAAA,EAAK,IAAA,EAAK,+BAAA,EAAgC,UAAA,EAAU,IAAA,EAAC,aAAA,EAAW,KAAA,CAAC,EAAA,CACpE,CAAA;AAAA,MAGD,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,EAAA,mBACZ,6BAAA;AAAA,QAAC,cAAA;AAAA,QAAA;AAAA,UAEC,OAAA,EAAS,CAAA,EAAA,GAAM;AAKb,YAAA,KAAK,YAAA,CAAa,MAAA,CAAO,MAAM,CAAC,CAAA,CAAE,CAAA,CAAE,KAAA,CAAM,CAAA,EAAA,GAAM;AAAA,YAEhD,CAAC,CAAA;AAAA,UACH,CAAA;AAAA,UAEC,QAAA,EAAA,MAAA,CAAO,MAAM;AAAA,QAAA,CAAA;AAAA,QAXT;AAAA,MAYP,CACD;AAAA,IAAA;AAAA,EACH,CAAA;AAEJ;ADpCA;AACE;AACF,0CAAC","file":"/home/runner/_work/seeds/seeds/seeds-react/seeds-react-data-viz/dist/export/index.js","sourcesContent":[null,"import { ActionMenu, MenuItem } from \"@sproutsocial/seeds-react-menu/base\";\nimport { Button } from \"@sproutsocial/seeds-react-button\";\nimport { Icon } from \"@sproutsocial/seeds-react-icon\";\nimport type {\n TypeChartExportFormat,\n TypeChartExportHandle,\n} from \"../charts/shared/chartExport\";\n\nexport interface ChartExportMenuProps {\n /** The opaque export handle surfaced by a v2 chart's `onReady` callback. */\n exportHandle: TypeChartExportHandle;\n /**\n * Visible labels per format. Only formats with a non-empty label render an\n * item; an empty object (or all-falsy labels) renders nothing — no dead\n * trigger. Items always render in canonical order, never in key-insertion\n * order.\n */\n labels: Partial<Record<TypeChartExportFormat, string>>;\n /** Accessible name for the icon-only trigger button. */\n triggerAriaLabel: string;\n}\n\n// Canonical render order, independent of `labels` key order.\nconst ORDER: TypeChartExportFormat[] = [\"png\", \"svg\", \"pdf\", \"csv\"];\n\n// Maps each format to the matching handle callable.\nconst METHOD: Record<TypeChartExportFormat, keyof TypeChartExportHandle> = {\n png: \"exportPNG\",\n svg: \"exportSVG\",\n pdf: \"exportPDF\",\n csv: \"exportCSV\",\n};\n\n/**\n * Icon-only overflow button that opens a dropdown of chart export actions\n * (PNG/SVG/PDF/CSV) for greenfield consumers, so they don't have to wire up\n * their own menu around the `TypeChartExportHandle` from `onReady`. Consumes only\n * the opaque handle — no Highcharts type crosses this boundary.\n */\nexport function ChartExportMenu({\n exportHandle,\n labels,\n triggerAriaLabel,\n}: ChartExportMenuProps) {\n const formats = ORDER.filter((format) => labels[format]);\n if (formats.length === 0) return null;\n\n return (\n <ActionMenu\n trigger={\n <Button appearance=\"secondary\" ariaLabel={triggerAriaLabel}>\n <Icon name=\"arrow-down-to-bracket-outline\" fixedWidth aria-hidden />\n </Button>\n }\n >\n {formats.map((format) => (\n <MenuItem\n key={format}\n onClick={() => {\n // The handle is fire-and-forget by design (opaque, consumer owns no\n // UI here). Attach a no-op catch so a rejected export (e.g. a PDF\n // dynamic-import failure) is a deliberate swallow, not an unhandled\n // promise rejection.\n void exportHandle[METHOD[format]]().catch(() => {\n // no-op: deliberate swallow of fire-and-forget export rejection (see comment above)\n });\n }}\n >\n {labels[format]}\n </MenuItem>\n ))}\n </ActionMenu>\n );\n}\n"]}
|