@acronis-platform/ui-react 5.5.3 → 5.5.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"confidence-cone.js","names":[],"sources":["../../../../src/components/ui/confidence-cone/confidence-cone.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Area,\n CartesianGrid,\n ComposedChart,\n Line,\n ReferenceArea,\n ReferenceLine,\n Text,\n XAxis,\n YAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAxisDomain,\n resolveAnimation,\n resolveRotatedTickAnchor,\n resolveXAxisTitle,\n resolveYAxisTitle,\n CHART_LABEL_FONT_SIZE,\n type ChartConfig,\n type ChartLegendFontSize,\n type ChartLegendAriaLabelProps,\n type ChartPalette,\n type ChartLegendContentProps,\n type ChartTooltipContentProps,\n toCssKey,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\nimport {\n mergeXAxisLayoutMargin,\n useXAxisLayout,\n} from '../chart/use-x-axis-layout';\nimport { resolveXAxisTickLabels } from '../chart/chart-format';\n\n// A forecast confidence-cone: a solid line over the known/actual period, a\n// dashed line over the forecast period, and a shaded band (the \"cone\") between\n// a lower and upper bound that typically widens with the horizon — visualizing\n// growing uncertainty. Built on the shared Chart primitives; no new tokens\n// (series colors are caller-supplied via `config`). The whole metric renders in\n// one hue — actual and forecast differ by line style, not color — so the cone\n// band and the forecast line both reuse the actual series' color.\n\n// Each series' band is a synthetic `[lower, upper]` range field per row that a\n// recharts <Area> shades; kept out of the tooltip/legend (see the filters\n// below). One band per series, so the key carries the series' actual key — the\n// whole `__cone` prefix is reserved.\nconst BAND_PREFIX = '__cone';\nconst bandKeyFor = (actualKey: string) => `${BAND_PREFIX}:${actualKey}`;\n\n/**\n * Drop every synthetic cone-band range series from a recharts tooltip/legend\n * payload, keeping the real actual/forecast series (and their order). Applied to\n * both the default tooltip and any caller-supplied `tooltipContent`, so no band\n * surfaces regardless of which path renders or how many series are plotted.\n */\nexport function dropConeBand<T extends { dataKey?: unknown }>(\n payload: readonly T[] | undefined\n): T[] | undefined {\n return payload?.filter(\n (item) =>\n !(\n typeof item.dataKey === 'string' && item.dataKey.startsWith(BAND_PREFIX)\n )\n );\n}\n\n/**\n * Reduce a legend payload to the metrics the chart plots — one entry per series.\n * A series' actual, forecast and cone are three recharts series painting a\n * single metric in a single hue, so the legend names each metric once, with its\n * actual series' swatch, instead of listing line styles as separate series.\n */\nexport function keepMetricSeries<T extends { dataKey?: unknown }>(\n payload: readonly T[] | undefined,\n actualKeys: readonly string[]\n): T[] | undefined {\n return payload?.filter(\n (item) =>\n typeof item.dataKey === 'string' && actualKeys.includes(item.dataKey)\n );\n}\n\n/**\n * Wrap a caller-supplied `tooltipContent` so the synthetic cone band is stripped\n * from the payload before it renders, while preserving recharts' own mount\n * semantics — a function is mounted via `createElement` (its own component\n * identity + hook state), an element via `cloneElement`. This mirrors what the\n * pass-through charts get by handing `content` straight to recharts, so a\n * function-form tooltip keeps its state across re-renders here too. The returned\n * component is a stable content type (memoize it on `tooltipContent`).\n */\ntype TooltipContentType = NonNullable<\n React.ComponentProps<typeof ChartTooltip>['content']\n>;\ntype TooltipContentFn = Extract<\n TooltipContentType,\n (...args: never[]) => unknown\n>;\ntype TooltipRenderProps = Parameters<TooltipContentFn>[0];\n\nexport function createConeTooltip(tooltipContent: TooltipContentType) {\n return function ConeTooltip(props: TooltipRenderProps) {\n const merged = {\n ...props,\n payload: dropConeBand(props.payload),\n } as TooltipRenderProps;\n return typeof tooltipContent === 'function'\n ? React.createElement(\n tooltipContent as React.FunctionComponent<TooltipRenderProps>,\n merged\n )\n : React.cloneElement(tooltipContent, merged);\n };\n}\n\n/**\n * One plotted metric: its actual / forecast columns and, optionally, the two\n * bound columns that shade its cone. Omit `lowerKey`/`upperKey` for a band-less\n * metric — a solid line handing off to a bare dashed projection.\n */\nexport interface ConfidenceConeSeries {\n /** Field for the known/actual values — drawn as a solid line with a filled area. */\n actualKey: string;\n /** Field for the projected values — drawn as a dashed line. */\n forecastKey: string;\n /** Field for the cone's lower bound. Omit (with `upperKey`) for no cone. */\n lowerKey?: string;\n /** Field for the cone's upper bound. Omit (with `lowerKey`) for no cone. */\n upperKey?: string;\n}\n\n/**\n * The x values of the projected period — every row carrying a forecast value for\n * at least one series, in data order. The first is the hand-off point (where the\n * shaded region and divider start); the whole set drives the forecast tick\n * styling, matched by value so tick `interval` can't skew it the way a tick\n * index would. Exported for unit tests; not part of the package's public API.\n */\nexport function forecastPeriodX(\n data: ReadonlyArray<Record<string, string | number | null | undefined>>,\n series: readonly ConfidenceConeSeries[],\n xKey: string\n): Array<string | number | null | undefined> {\n return data\n .filter((row) =>\n series.some(({ forecastKey }) => typeof row[forecastKey] === 'number')\n )\n .map((row) => row[xKey]);\n}\n\n/**\n * Build the X-axis tick renderer that sets the projected columns apart: italic,\n * in the metric's hue. Styled inline rather than through the `fill` attribute\n * recharts hands every tick, so the accent survives the class-based tick color\n * a chart theme may apply. A custom tick owns its own text, so the caller's\n * `xTickFormatter` is applied here — recharts only applies it to default ticks.\n * Exported for unit tests; not part of the package's public API.\n */\nexport function createForecastTick(\n forecastX: ReadonlySet<string | number | null | undefined>,\n color: string,\n tickFormatter?: CartesianChartProps['xTickFormatter']\n) {\n return function ForecastTick({\n payload,\n index,\n ...tickProps\n }: {\n payload?: { value?: string | number };\n index?: number;\n }) {\n const value = payload?.value;\n return (\n <Text\n {...tickProps}\n style={\n value != null && forecastX.has(value)\n ? { fontStyle: 'italic', fill: color }\n : undefined\n }\n >\n {tickFormatter && value != null ? tickFormatter(value, index) : value}\n </Text>\n );\n };\n}\n\n/** A dashed horizontal threshold on the value axis. */\nexport interface ConfidenceConeReferenceLine {\n /** Position on the value (Y) axis. */\n value: number;\n /** Optional caption rendered at the line's right end. */\n label?: string;\n}\n\n/**\n * Every prop except the one-form-or-the-other requirement `ConfidenceConeProps`\n * layers on below. Exported so the stories can type their `Meta` on a single\n * object shape — Storybook can't split a union's required args between `meta.args`\n * and a story's. Not re-exported from `index.ts`; not part of the public API.\n */\nexport interface ConfidenceConeBaseProps\n extends\n Omit<React.ComponentProps<'div'>, 'children'>,\n CartesianChartProps,\n ChartAnimationProps,\n ChartLegendAriaLabelProps {\n /**\n * The dataviz palette this chart's series are painted from. Series that\n * state no `color` of their own take a stop of it. See `ChartPalette`.\n */\n palette?: ChartPalette;\n /**\n * Row-per-point data — the shared x dimension plus each series' actual /\n * forecast / bound fields. Rows are naturally sparse (a point has either an\n * actual or a forecast + bounds), so missing fields are allowed. Avoid fields\n * starting with `__cone` — that prefix is reserved for the internal\n * prediction-band series.\n */\n data: ReadonlyArray<Record<string, string | number | null | undefined>>;\n /**\n * Per-series map of `label` / `icon` / `tone` for the actual + forecast lines\n * (imported from the shared `Chart` primitives). Series take their colour from\n * the container's `palette`; each entry maps a key to a `label` and an optional\n * `tone`. Each metric renders in one hue: its cone band and forecast line both\n * reuse its actual series' color — actual and forecast differ by line style,\n * not hue.\n */\n config: ChartConfig;\n /** Category / time axis key (the shared dimension across rows). */\n xKey: string;\n /**\n * Plot several metrics against one shared axis — each with its own actual /\n * forecast / bound fields and its own hue (from `config[actualKey]`). Takes\n * precedence over the single-series `actualKey`/`forecastKey`/`lowerKey`/\n * `upperKey` shorthand below; pass one form or the other, not both. One of the\n * two forms is required.\n */\n series?: readonly ConfidenceConeSeries[];\n /**\n * Single-series shorthand — field for the known/actual values, drawn as a\n * solid line with a filled area. Required (with `forecastKey`) unless `series`\n * is set, which supersedes it.\n */\n actualKey?: string;\n /**\n * Single-series shorthand — field for the projected values, drawn as a dashed\n * line. Required (with `actualKey`) unless `series` is set, which supersedes\n * it.\n */\n forecastKey?: string;\n /** Field for the cone's lower bound. Omit (with `upperKey`) for no cone. */\n lowerKey?: string;\n /** Field for the cone's upper bound. Omit (with `lowerKey`) for no cone. */\n upperKey?: string;\n /**\n * How the known/actual period is drawn: a filled `area` under the line (the\n * default), or a bare `line` — for a chart where the cone is the only shaded\n * region, or where several metrics' fills would muddy each other.\n */\n actualType?: 'area' | 'line';\n /** Stroke width of the actual + forecast lines. */\n strokeWidth?: number;\n /**\n * Mark each data point: a filled dot on the observed values, a hollow one on\n * the projection — so a point reads as measured or predicted at a glance.\n */\n showDots?: boolean;\n /**\n * Italicize the X-axis ticks over the forecast period and paint them in the\n * first series' hue, so the projected columns read as projected even when the\n * shaded region is off.\n */\n styleForecastTicks?: boolean;\n /**\n * One or more dashed horizontal thresholds on the value axis — e.g. a target\n * or a capacity limit. Pass a single object or an array to draw several.\n */\n referenceLine?: ConfidenceConeReferenceLine | ConfidenceConeReferenceLine[];\n /**\n * Set off the forecast period from the actuals with a dashed divider at the\n * hand-off point (the first row with a forecast value) and a subtle shaded\n * band over the forecast region.\n */\n showForecastRegion?: boolean;\n showLegend?: boolean;\n /**\n * Font size of the legend text. Defaults to `'xs'` — the size the legend has\n * always rendered at. See `ChartLegendFontSize`.\n */\n legendFontSize?: ChartLegendFontSize;\n}\n\n/**\n * Which columns to plot has to be spelled out one way or the other: the `series`\n * array, or the flat `actualKey` + `forecastKey` shorthand. Expressed as a union\n * so a chart with neither is a compile error rather than a silent plot of axes\n * and nothing else. Both forms together stay legal — `series` wins (see\n * `plotted`), which is what the multi-series stories rely on to clear the args\n * table.\n */\nexport type ConfidenceConeProps = ConfidenceConeBaseProps &\n (\n | { series: readonly ConfidenceConeSeries[] }\n | { actualKey: string; forecastKey: string }\n );\n\nconst ConfidenceCone = React.forwardRef<HTMLDivElement, ConfidenceConeProps>(\n (\n {\n className,\n config,\n palette,\n data,\n xKey,\n series,\n actualKey,\n forecastKey,\n lowerKey,\n upperKey,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n actualType = 'area',\n strokeWidth = 2,\n showDots = false,\n styleForecastTicks = false,\n referenceLine,\n showForecastRegion = true,\n showGrid = true,\n showTooltip = true,\n showLegend = true,\n legendFontSize,\n legendAriaLabel,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n ...props\n },\n ref\n ) => {\n // The flat *Key props are the single-series shorthand for `series`.\n const plotted = React.useMemo<readonly ConfidenceConeSeries[]>(() => {\n if (series?.length) return series;\n if (!actualKey || !forecastKey) return [];\n return [{ actualKey, forecastKey, lowerKey, upperKey }];\n }, [series, actualKey, forecastKey, lowerKey, upperKey]);\n\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n // Memoized so recharts sees a stable content type across renders — a fresh\n // wrapper each render would remount the caller's tooltip and reset its state.\n const customTooltip = React.useMemo(\n () => (tooltipContent ? createConeTooltip(tooltipContent) : undefined),\n [tooltipContent]\n );\n\n const xAxisTitle = resolveXAxisTitle(xAxisLabel);\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n const yDomain = resolveAxisDomain(yAxisDomain);\n\n // One hue per metric. Each cone and forecast line already paints with its own\n // series' actual color; re-pointing that series' forecast key's `--color-*`\n // at it too means nothing downstream — a custom tooltip, a caller's\n // `var(--color-<forecastKey>)` — can reintroduce a second color.\n const seriesConfig = React.useMemo(() => {\n let next: ChartConfig | undefined;\n for (const { actualKey: aKey, forecastKey: fKey } of plotted) {\n const actual = config[aKey];\n const forecast = config[fKey];\n if (!actual || !forecast) continue;\n next ??= { ...config };\n next[fKey] = {\n label: forecast.label,\n icon: forecast.icon,\n tone: { sameAs: aKey },\n };\n }\n return next ?? config;\n }, [config, plotted]);\n\n const xAxisTickLabels = resolveXAxisTickLabels(\n data.map((row) => row[xKey]),\n xTickFormatter\n );\n const chartContainerRef = React.useRef<HTMLDivElement>(null);\n const xAxisLayout = useXAxisLayout(\n chartContainerRef,\n xAxisAngle,\n xAxisLabel,\n xAxisTickLabels.join('\\u0000')\n );\n\n // Augment each row with one `[lower, upper]` band tuple per coned series for\n // its Area to shade. Rows missing a numeric bound are left un-coned (the\n // band breaks there); a series without bounds gets no band at all.\n const chartData = data.map((row) => {\n const next: Record<string, unknown> = { ...row };\n for (const {\n actualKey: aKey,\n lowerKey: lKey,\n upperKey: uKey,\n } of plotted) {\n if (!lKey || !uKey) continue;\n const lower = row[lKey];\n const upper = row[uKey];\n next[bandKeyFor(aKey)] =\n typeof lower === 'number' && typeof upper === 'number'\n ? [lower, upper]\n : undefined;\n }\n return next;\n });\n\n const forecastX = forecastPeriodX(data, plotted, xKey);\n // Set the projected period off from the actuals with a shaded band + a\n // divider at the hand-off.\n const forecastStart = showForecastRegion ? forecastX[0] : undefined;\n const lastX = data[data.length - 1]?.[xKey];\n\n const renderForecastTick = createForecastTick(\n new Set(forecastX),\n `var(--color-${toCssKey(plotted[0]?.actualKey ?? '')})`,\n xTickFormatter\n );\n\n const referenceLines = referenceLine\n ? Array.isArray(referenceLine)\n ? referenceLine\n : [referenceLine]\n : [];\n\n // Everything from here to the `return` is lifted out of the returned tree\n // only to keep it readable as a flat list of chart children. Nothing in\n // recharts forces the `render*` helpers to be plain functions: axes and\n // series register themselves with the chart's store, and `<Cell>` is the\n // only child still looked up by element type — a component wrapper renders\n // fine (see AreaChart's `AreaFillGradients`). They stay functions because\n // they are declared inside the render body, where a component would get a\n // fresh element type on every render and remount its subtree.\n\n const renderAxes = () => (\n <>\n <XAxis\n dataKey={xKey}\n type=\"category\"\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickMargin={8}\n tickFormatter={xTickFormatter}\n tick={styleForecastTicks ? renderForecastTick : undefined}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={resolveRotatedTickAnchor(xAxisAngle)}\n height={xAxisLayout.height}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n unit={yUnit}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n </>\n );\n\n // Set the forecast region off from the actuals (behind everything).\n const renderForecastRegion = () => (\n <>\n {forecastStart != null && lastX != null && (\n <ReferenceArea\n x1={forecastStart}\n x2={lastX}\n fill=\"var(--ui-background-surface-secondary)\"\n fillOpacity={0.5}\n ifOverflow=\"extendDomain\"\n />\n )}\n {forecastStart != null && (\n <ReferenceLine\n x={forecastStart}\n stroke=\"var(--ui-border-on-surface-border)\"\n strokeDasharray=\"4 4\"\n />\n )}\n </>\n );\n\n const renderThreshold = (\n threshold: ConfidenceConeReferenceLine,\n index: number\n ) => (\n <ReferenceLine\n key={`${threshold.label ?? 'threshold'}-${index}`}\n y={threshold.value}\n stroke=\"var(--ui-text-on-surface-secondary)\"\n strokeDasharray=\"4 4\"\n // extendDomain so a threshold beyond the data max stays visible.\n ifOverflow=\"extendDomain\"\n label={\n threshold.label\n ? {\n value: threshold.label,\n position: 'insideTopRight',\n fill: 'var(--ui-text-on-surface-secondary)',\n fontSize: CHART_LABEL_FONT_SIZE,\n }\n : undefined\n }\n />\n );\n\n const renderTooltip = () =>\n customTooltip ? (\n // Strips the synthetic band before the caller's tooltip sees it — the\n // `__cone` series feeds the Area, not the tooltip.\n <ChartTooltip content={customTooltip} />\n ) : (\n <ChartTooltip\n content={(tp) => (\n <ChartTooltipContent\n active={tp.active}\n label={tp.label}\n // The synthetic band feeds the Area, not the tooltip.\n payload={\n dropConeBand(tp.payload) as ChartTooltipContentProps['payload']\n }\n />\n )}\n />\n );\n\n const renderLegend = () => (\n <ChartLegend\n content={(lp) => (\n <ChartLegendContent\n verticalAlign={lp.verticalAlign}\n fontSize={legendFontSize}\n ariaLabel={legendAriaLabel}\n payload={\n keepMetricSeries(\n lp.payload,\n plotted.map((s) => s.actualKey)\n ) as ChartLegendContentProps['payload']\n }\n />\n )}\n />\n );\n\n // One color per metric — actual and forecast differ by line style, not hue\n // — so a cone reuses its series' actual color.\n const renderConeBand = ({\n actualKey: aKey,\n lowerKey: lKey,\n upperKey: uKey,\n }: ConfidenceConeSeries) =>\n lKey && uKey ? (\n <Area\n key={bandKeyFor(aKey)}\n // The band paints in the same hue, at the same opacity, as the\n // actual series' own area, so nothing on the rendered path tells\n // the two apart. recharts forwards `data-*` onto the path it\n // draws; the tests select the band through this.\n data-slot=\"confidence-cone-band\"\n dataKey={bandKeyFor(aKey)}\n type=\"monotone\"\n stroke=\"none\"\n fill={`var(--color-${toCssKey(aKey)})`}\n fillOpacity={0.15}\n connectNulls={false}\n dot={false}\n activeDot={false}\n {...animation}\n legendType=\"none\"\n tooltipType=\"none\"\n />\n ) : null;\n\n const renderActualMark = ({ actualKey: aKey }: ConfidenceConeSeries) => {\n // An area and a line take the same props here; only the region under the\n // curve (and the mark recharts draws) differ. A `Line` gets no fill at\n // all — `fillOpacity: 0` would also erase its dots.\n const ActualMark = actualType === 'line' ? Line : Area;\n const areaFill =\n actualType === 'line'\n ? undefined\n : { fill: `var(--color-${toCssKey(aKey)})`, fillOpacity: 0.15 };\n // Observed points read as measured: LineChart's dot geometry (r 3, 2px\n // ring) filled with the metric hue. The ring is that same hue, so the\n // mark is solid — and wide enough against the 2px line not to read as a\n // mere thickening of it. `fillOpacity: 1` is load-bearing: recharts\n // merges the parent mark's own presentation props into every dot it\n // draws, so an `<Area>`'s 0.15 would otherwise wash the dot out to a halo.\n const dot = showDots\n ? {\n r: 3,\n fill: `var(--color-${toCssKey(aKey)})`,\n fillOpacity: 1,\n stroke: `var(--color-${toCssKey(aKey)})`,\n strokeWidth: 2,\n }\n : false;\n return (\n <ActualMark\n key={aKey}\n dataKey={aKey}\n type=\"monotone\"\n stroke={`var(--color-${toCssKey(aKey)})`}\n strokeWidth={strokeWidth}\n {...areaFill}\n dot={dot}\n activeDot={showDots ? { r: 5 } : false}\n connectNulls\n {...animation}\n // The legend names the metric once, so it carries the swatch that\n // stands for the whole series rather than the actual line's style.\n legendType=\"rect\"\n />\n );\n };\n\n const renderForecastLine = ({\n actualKey: aKey,\n forecastKey: fKey,\n }: ConfidenceConeSeries) => {\n // Projected points read as predicted: the same LineChart dot, inverted —\n // the metric's hue as the ring, the surface color as the fill, so the\n // dashed line doesn't show through the middle. (LineChart leaves the fill\n // to recharts, whose `Line` defaults it to `#fff`; the token is that same\n // white in the light theme and also holds up in the dark one.)\n // `strokeDasharray: 'none'` is load-bearing: recharts merges the parent\n // mark's presentation props into every dot, so this line's `5 5` would\n // otherwise break each dot's ring into two arcs.\n const dot = showDots\n ? {\n r: 3,\n fill: 'var(--ui-background-surface-primary)',\n stroke: `var(--color-${toCssKey(aKey)})`,\n strokeWidth: 2,\n strokeDasharray: 'none',\n }\n : false;\n return (\n <Line\n key={fKey}\n dataKey={fKey}\n type=\"monotone\"\n stroke={`var(--color-${toCssKey(aKey)})`}\n strokeWidth={strokeWidth}\n strokeDasharray=\"5 5\"\n dot={dot}\n // Paired with `dot` the way every other chart does it — left unset,\n // the projection would keep recharts' default active dot while the\n // actuals had none (and a different radius when on).\n activeDot={showDots ? { r: 5 } : false}\n connectNulls\n {...animation}\n />\n );\n };\n\n return (\n <div ref={ref} className={cn(className)} {...props}>\n <ChartContainer\n ref={chartContainerRef}\n config={seriesConfig}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <ComposedChart\n data={chartData as readonly unknown[]}\n margin={mergeXAxisLayoutMargin(undefined, xAxisLayout.margin)}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n {renderAxes()}\n {renderForecastRegion()}\n {referenceLines.map(renderThreshold)}\n {showTooltip && renderTooltip()}\n {showLegend && renderLegend()}\n {/* Every cone renders before any line, so the lines draw on top of\n all of them. */}\n {plotted.map(renderConeBand)}\n {plotted.map(renderActualMark)}\n {plotted.map(renderForecastLine)}\n </ComposedChart>\n </ChartContainer>\n </div>\n );\n }\n);\nConfidenceCone.displayName = 'ConfidenceCone';\n\nexport { ConfidenceCone };\n"],"mappings":"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"}
1
+ {"version":3,"file":"confidence-cone.js","names":[],"sources":["../../../../src/components/ui/confidence-cone/confidence-cone.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Area,\n CartesianGrid,\n ComposedChart,\n Line,\n ReferenceArea,\n ReferenceLine,\n Text,\n XAxis,\n YAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartLegend,\n ChartLegendContent,\n ChartTooltip,\n ChartTooltipContent,\n resolveAxisDomain,\n resolveAnimation,\n resolveRotatedTickAnchor,\n resolveXAxisTitle,\n resolveYAxisTitle,\n CHART_LABEL_FONT_SIZE,\n type ChartConfig,\n type ChartLegendFontSize,\n type ChartLegendAriaLabelProps,\n type ChartPalette,\n type ChartLegendContentProps,\n type ChartTooltipContentProps,\n toCssKey,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\nimport {\n mergeXAxisLayoutMargin,\n useXAxisLayout,\n} from '../chart/use-x-axis-layout';\nimport { resolveXAxisTickLabels, resolveYAxisWidth } from '../chart/chart-format';\n\n// A forecast confidence-cone: a solid line over the known/actual period, a\n// dashed line over the forecast period, and a shaded band (the \"cone\") between\n// a lower and upper bound that typically widens with the horizon — visualizing\n// growing uncertainty. Built on the shared Chart primitives; no new tokens\n// (series colors are caller-supplied via `config`). The whole metric renders in\n// one hue — actual and forecast differ by line style, not color — so the cone\n// band and the forecast line both reuse the actual series' color.\n\n// Each series' band is a synthetic `[lower, upper]` range field per row that a\n// recharts <Area> shades; kept out of the tooltip/legend (see the filters\n// below). One band per series, so the key carries the series' actual key — the\n// whole `__cone` prefix is reserved.\nconst BAND_PREFIX = '__cone';\nconst bandKeyFor = (actualKey: string) => `${BAND_PREFIX}:${actualKey}`;\n\n/**\n * Drop every synthetic cone-band range series from a recharts tooltip/legend\n * payload, keeping the real actual/forecast series (and their order). Applied to\n * both the default tooltip and any caller-supplied `tooltipContent`, so no band\n * surfaces regardless of which path renders or how many series are plotted.\n */\nexport function dropConeBand<T extends { dataKey?: unknown }>(\n payload: readonly T[] | undefined\n): T[] | undefined {\n return payload?.filter(\n (item) =>\n !(\n typeof item.dataKey === 'string' && item.dataKey.startsWith(BAND_PREFIX)\n )\n );\n}\n\n/**\n * Reduce a legend payload to the metrics the chart plots — one entry per series.\n * A series' actual, forecast and cone are three recharts series painting a\n * single metric in a single hue, so the legend names each metric once, with its\n * actual series' swatch, instead of listing line styles as separate series.\n */\nexport function keepMetricSeries<T extends { dataKey?: unknown }>(\n payload: readonly T[] | undefined,\n actualKeys: readonly string[]\n): T[] | undefined {\n return payload?.filter(\n (item) =>\n typeof item.dataKey === 'string' && actualKeys.includes(item.dataKey)\n );\n}\n\n/**\n * Wrap a caller-supplied `tooltipContent` so the synthetic cone band is stripped\n * from the payload before it renders, while preserving recharts' own mount\n * semantics — a function is mounted via `createElement` (its own component\n * identity + hook state), an element via `cloneElement`. This mirrors what the\n * pass-through charts get by handing `content` straight to recharts, so a\n * function-form tooltip keeps its state across re-renders here too. The returned\n * component is a stable content type (memoize it on `tooltipContent`).\n */\ntype TooltipContentType = NonNullable<\n React.ComponentProps<typeof ChartTooltip>['content']\n>;\ntype TooltipContentFn = Extract<\n TooltipContentType,\n (...args: never[]) => unknown\n>;\ntype TooltipRenderProps = Parameters<TooltipContentFn>[0];\n\nexport function createConeTooltip(tooltipContent: TooltipContentType) {\n return function ConeTooltip(props: TooltipRenderProps) {\n const merged = {\n ...props,\n payload: dropConeBand(props.payload),\n } as TooltipRenderProps;\n return typeof tooltipContent === 'function'\n ? React.createElement(\n tooltipContent as React.FunctionComponent<TooltipRenderProps>,\n merged\n )\n : React.cloneElement(tooltipContent, merged);\n };\n}\n\n/**\n * One plotted metric: its actual / forecast columns and, optionally, the two\n * bound columns that shade its cone. Omit `lowerKey`/`upperKey` for a band-less\n * metric — a solid line handing off to a bare dashed projection.\n */\nexport interface ConfidenceConeSeries {\n /** Field for the known/actual values — drawn as a solid line with a filled area. */\n actualKey: string;\n /** Field for the projected values — drawn as a dashed line. */\n forecastKey: string;\n /** Field for the cone's lower bound. Omit (with `upperKey`) for no cone. */\n lowerKey?: string;\n /** Field for the cone's upper bound. Omit (with `lowerKey`) for no cone. */\n upperKey?: string;\n}\n\n/**\n * The x values of the projected period — every row carrying a forecast value for\n * at least one series, in data order. The first is the hand-off point (where the\n * shaded region and divider start); the whole set drives the forecast tick\n * styling, matched by value so tick `interval` can't skew it the way a tick\n * index would. Exported for unit tests; not part of the package's public API.\n */\nexport function forecastPeriodX(\n data: ReadonlyArray<Record<string, string | number | null | undefined>>,\n series: readonly ConfidenceConeSeries[],\n xKey: string\n): Array<string | number | null | undefined> {\n return data\n .filter((row) =>\n series.some(({ forecastKey }) => typeof row[forecastKey] === 'number')\n )\n .map((row) => row[xKey]);\n}\n\n/**\n * Build the X-axis tick renderer that sets the projected columns apart: italic,\n * in the metric's hue. Styled inline rather than through the `fill` attribute\n * recharts hands every tick, so the accent survives the class-based tick color\n * a chart theme may apply. A custom tick owns its own text, so the caller's\n * `xTickFormatter` is applied here — recharts only applies it to default ticks.\n * Exported for unit tests; not part of the package's public API.\n */\nexport function createForecastTick(\n forecastX: ReadonlySet<string | number | null | undefined>,\n color: string,\n tickFormatter?: CartesianChartProps['xTickFormatter']\n) {\n return function ForecastTick({\n payload,\n index,\n ...tickProps\n }: {\n payload?: { value?: string | number };\n index?: number;\n }) {\n const value = payload?.value;\n return (\n <Text\n {...tickProps}\n style={\n value != null && forecastX.has(value)\n ? { fontStyle: 'italic', fill: color }\n : undefined\n }\n >\n {tickFormatter && value != null ? tickFormatter(value, index) : value}\n </Text>\n );\n };\n}\n\n/** A dashed horizontal threshold on the value axis. */\nexport interface ConfidenceConeReferenceLine {\n /** Position on the value (Y) axis. */\n value: number;\n /** Optional caption rendered at the line's right end. */\n label?: string;\n}\n\n/**\n * Every prop except the one-form-or-the-other requirement `ConfidenceConeProps`\n * layers on below. Exported so the stories can type their `Meta` on a single\n * object shape — Storybook can't split a union's required args between `meta.args`\n * and a story's. Not re-exported from `index.ts`; not part of the public API.\n */\nexport interface ConfidenceConeBaseProps\n extends\n Omit<React.ComponentProps<'div'>, 'children'>,\n CartesianChartProps,\n ChartAnimationProps,\n ChartLegendAriaLabelProps {\n /**\n * The dataviz palette this chart's series are painted from. Series that\n * state no `color` of their own take a stop of it. See `ChartPalette`.\n */\n palette?: ChartPalette;\n /**\n * Row-per-point data — the shared x dimension plus each series' actual /\n * forecast / bound fields. Rows are naturally sparse (a point has either an\n * actual or a forecast + bounds), so missing fields are allowed. Avoid fields\n * starting with `__cone` — that prefix is reserved for the internal\n * prediction-band series.\n */\n data: ReadonlyArray<Record<string, string | number | null | undefined>>;\n /**\n * Per-series map of `label` / `icon` / `tone` for the actual + forecast lines\n * (imported from the shared `Chart` primitives). Series take their colour from\n * the container's `palette`; each entry maps a key to a `label` and an optional\n * `tone`. Each metric renders in one hue: its cone band and forecast line both\n * reuse its actual series' color — actual and forecast differ by line style,\n * not hue.\n */\n config: ChartConfig;\n /** Category / time axis key (the shared dimension across rows). */\n xKey: string;\n /**\n * Plot several metrics against one shared axis — each with its own actual /\n * forecast / bound fields and its own hue (from `config[actualKey]`). Takes\n * precedence over the single-series `actualKey`/`forecastKey`/`lowerKey`/\n * `upperKey` shorthand below; pass one form or the other, not both. One of the\n * two forms is required.\n */\n series?: readonly ConfidenceConeSeries[];\n /**\n * Single-series shorthand — field for the known/actual values, drawn as a\n * solid line with a filled area. Required (with `forecastKey`) unless `series`\n * is set, which supersedes it.\n */\n actualKey?: string;\n /**\n * Single-series shorthand — field for the projected values, drawn as a dashed\n * line. Required (with `actualKey`) unless `series` is set, which supersedes\n * it.\n */\n forecastKey?: string;\n /** Field for the cone's lower bound. Omit (with `upperKey`) for no cone. */\n lowerKey?: string;\n /** Field for the cone's upper bound. Omit (with `lowerKey`) for no cone. */\n upperKey?: string;\n /**\n * How the known/actual period is drawn: a filled `area` under the line (the\n * default), or a bare `line` — for a chart where the cone is the only shaded\n * region, or where several metrics' fills would muddy each other.\n */\n actualType?: 'area' | 'line';\n /** Stroke width of the actual + forecast lines. */\n strokeWidth?: number;\n /**\n * Mark each data point: a filled dot on the observed values, a hollow one on\n * the projection — so a point reads as measured or predicted at a glance.\n */\n showDots?: boolean;\n /**\n * Italicize the X-axis ticks over the forecast period and paint them in the\n * first series' hue, so the projected columns read as projected even when the\n * shaded region is off.\n */\n styleForecastTicks?: boolean;\n /**\n * One or more dashed horizontal thresholds on the value axis — e.g. a target\n * or a capacity limit. Pass a single object or an array to draw several.\n */\n referenceLine?: ConfidenceConeReferenceLine | ConfidenceConeReferenceLine[];\n /**\n * Set off the forecast period from the actuals with a dashed divider at the\n * hand-off point (the first row with a forecast value) and a subtle shaded\n * band over the forecast region.\n */\n showForecastRegion?: boolean;\n showLegend?: boolean;\n /**\n * Font size of the legend text. Defaults to `'xs'` — the size the legend has\n * always rendered at. See `ChartLegendFontSize`.\n */\n legendFontSize?: ChartLegendFontSize;\n}\n\n/**\n * Which columns to plot has to be spelled out one way or the other: the `series`\n * array, or the flat `actualKey` + `forecastKey` shorthand. Expressed as a union\n * so a chart with neither is a compile error rather than a silent plot of axes\n * and nothing else. Both forms together stay legal — `series` wins (see\n * `plotted`), which is what the multi-series stories rely on to clear the args\n * table.\n */\nexport type ConfidenceConeProps = ConfidenceConeBaseProps &\n (\n | { series: readonly ConfidenceConeSeries[] }\n | { actualKey: string; forecastKey: string }\n );\n\nconst ConfidenceCone = React.forwardRef<HTMLDivElement, ConfidenceConeProps>(\n (\n {\n className,\n config,\n palette,\n data,\n xKey,\n series,\n actualKey,\n forecastKey,\n lowerKey,\n upperKey,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n actualType = 'area',\n strokeWidth = 2,\n showDots = false,\n styleForecastTicks = false,\n referenceLine,\n showForecastRegion = true,\n showGrid = true,\n showTooltip = true,\n showLegend = true,\n legendFontSize,\n legendAriaLabel,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n ...props\n },\n ref\n ) => {\n // The flat *Key props are the single-series shorthand for `series`.\n const plotted = React.useMemo<readonly ConfidenceConeSeries[]>(() => {\n if (series?.length) return series;\n if (!actualKey || !forecastKey) return [];\n return [{ actualKey, forecastKey, lowerKey, upperKey }];\n }, [series, actualKey, forecastKey, lowerKey, upperKey]);\n\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n // Memoized so recharts sees a stable content type across renders — a fresh\n // wrapper each render would remount the caller's tooltip and reset its state.\n const customTooltip = React.useMemo(\n () => (tooltipContent ? createConeTooltip(tooltipContent) : undefined),\n [tooltipContent]\n );\n\n const xAxisTitle = resolveXAxisTitle(xAxisLabel);\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n const yDomain = resolveAxisDomain(yAxisDomain);\n\n // One hue per metric. Each cone and forecast line already paints with its own\n // series' actual color; re-pointing that series' forecast key's `--color-*`\n // at it too means nothing downstream — a custom tooltip, a caller's\n // `var(--color-<forecastKey>)` — can reintroduce a second color.\n const seriesConfig = React.useMemo(() => {\n let next: ChartConfig | undefined;\n for (const { actualKey: aKey, forecastKey: fKey } of plotted) {\n const actual = config[aKey];\n const forecast = config[fKey];\n if (!actual || !forecast) continue;\n next ??= { ...config };\n next[fKey] = {\n label: forecast.label,\n icon: forecast.icon,\n tone: { sameAs: aKey },\n };\n }\n return next ?? config;\n }, [config, plotted]);\n\n const xAxisTickLabels = resolveXAxisTickLabels(\n data.map((row) => row[xKey]),\n xTickFormatter\n );\n const chartContainerRef = React.useRef<HTMLDivElement>(null);\n const xAxisLayout = useXAxisLayout(\n chartContainerRef,\n xAxisAngle,\n xAxisLabel,\n xAxisTickLabels.join('\\u0000')\n );\n\n // Augment each row with one `[lower, upper]` band tuple per coned series for\n // its Area to shade. Rows missing a numeric bound are left un-coned (the\n // band breaks there); a series without bounds gets no band at all.\n const chartData = data.map((row) => {\n const next: Record<string, unknown> = { ...row };\n for (const {\n actualKey: aKey,\n lowerKey: lKey,\n upperKey: uKey,\n } of plotted) {\n if (!lKey || !uKey) continue;\n const lower = row[lKey];\n const upper = row[uKey];\n next[bandKeyFor(aKey)] =\n typeof lower === 'number' && typeof upper === 'number'\n ? [lower, upper]\n : undefined;\n }\n return next;\n });\n\n const forecastX = forecastPeriodX(data, plotted, xKey);\n // Set the projected period off from the actuals with a shaded band + a\n // divider at the hand-off.\n const forecastStart = showForecastRegion ? forecastX[0] : undefined;\n const lastX = data[data.length - 1]?.[xKey];\n\n const renderForecastTick = createForecastTick(\n new Set(forecastX),\n `var(--color-${toCssKey(plotted[0]?.actualKey ?? '')})`,\n xTickFormatter\n );\n\n const referenceLines = referenceLine\n ? Array.isArray(referenceLine)\n ? referenceLine\n : [referenceLine]\n : [];\n\n // Everything from here to the `return` is lifted out of the returned tree\n // only to keep it readable as a flat list of chart children. Nothing in\n // recharts forces the `render*` helpers to be plain functions: axes and\n // series register themselves with the chart's store, and `<Cell>` is the\n // only child still looked up by element type — a component wrapper renders\n // fine (see AreaChart's `AreaFillGradients`). They stay functions because\n // they are declared inside the render body, where a component would get a\n // fresh element type on every render and remount its subtree.\n\n const renderAxes = () => (\n <>\n <XAxis\n dataKey={xKey}\n type=\"category\"\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickMargin={8}\n tickFormatter={xTickFormatter}\n tick={styleForecastTicks ? renderForecastTick : undefined}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={resolveRotatedTickAnchor(xAxisAngle)}\n height={xAxisLayout.height}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n unit={yUnit}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={resolveYAxisWidth(data.length > 0, Boolean(yAxisLabel))}\n label={yAxisTitle}\n />\n </>\n );\n\n // Set the forecast region off from the actuals (behind everything).\n const renderForecastRegion = () => (\n <>\n {forecastStart != null && lastX != null && (\n <ReferenceArea\n x1={forecastStart}\n x2={lastX}\n fill=\"var(--ui-background-surface-secondary)\"\n fillOpacity={0.5}\n ifOverflow=\"extendDomain\"\n />\n )}\n {forecastStart != null && (\n <ReferenceLine\n x={forecastStart}\n stroke=\"var(--ui-border-on-surface-border)\"\n strokeDasharray=\"4 4\"\n />\n )}\n </>\n );\n\n const renderThreshold = (\n threshold: ConfidenceConeReferenceLine,\n index: number\n ) => (\n <ReferenceLine\n key={`${threshold.label ?? 'threshold'}-${index}`}\n y={threshold.value}\n stroke=\"var(--ui-text-on-surface-secondary)\"\n strokeDasharray=\"4 4\"\n // extendDomain so a threshold beyond the data max stays visible.\n ifOverflow=\"extendDomain\"\n label={\n threshold.label\n ? {\n value: threshold.label,\n position: 'insideTopRight',\n fill: 'var(--ui-text-on-surface-secondary)',\n fontSize: CHART_LABEL_FONT_SIZE,\n }\n : undefined\n }\n />\n );\n\n const renderTooltip = () =>\n customTooltip ? (\n // Strips the synthetic band before the caller's tooltip sees it — the\n // `__cone` series feeds the Area, not the tooltip.\n <ChartTooltip content={customTooltip} />\n ) : (\n <ChartTooltip\n content={(tp) => (\n <ChartTooltipContent\n active={tp.active}\n label={tp.label}\n // The synthetic band feeds the Area, not the tooltip.\n payload={\n dropConeBand(tp.payload) as ChartTooltipContentProps['payload']\n }\n />\n )}\n />\n );\n\n const renderLegend = () => (\n <ChartLegend\n content={(lp) => (\n <ChartLegendContent\n verticalAlign={lp.verticalAlign}\n fontSize={legendFontSize}\n ariaLabel={legendAriaLabel}\n payload={\n keepMetricSeries(\n lp.payload,\n plotted.map((s) => s.actualKey)\n ) as ChartLegendContentProps['payload']\n }\n />\n )}\n />\n );\n\n // One color per metric — actual and forecast differ by line style, not hue\n // — so a cone reuses its series' actual color.\n const renderConeBand = ({\n actualKey: aKey,\n lowerKey: lKey,\n upperKey: uKey,\n }: ConfidenceConeSeries) =>\n lKey && uKey ? (\n <Area\n key={bandKeyFor(aKey)}\n // The band paints in the same hue, at the same opacity, as the\n // actual series' own area, so nothing on the rendered path tells\n // the two apart. recharts forwards `data-*` onto the path it\n // draws; the tests select the band through this.\n data-slot=\"confidence-cone-band\"\n dataKey={bandKeyFor(aKey)}\n type=\"monotone\"\n stroke=\"none\"\n fill={`var(--color-${toCssKey(aKey)})`}\n fillOpacity={0.15}\n connectNulls={false}\n dot={false}\n activeDot={false}\n {...animation}\n legendType=\"none\"\n tooltipType=\"none\"\n />\n ) : null;\n\n const renderActualMark = ({ actualKey: aKey }: ConfidenceConeSeries) => {\n // An area and a line take the same props here; only the region under the\n // curve (and the mark recharts draws) differ. A `Line` gets no fill at\n // all — `fillOpacity: 0` would also erase its dots.\n const ActualMark = actualType === 'line' ? Line : Area;\n const areaFill =\n actualType === 'line'\n ? undefined\n : { fill: `var(--color-${toCssKey(aKey)})`, fillOpacity: 0.15 };\n // Observed points read as measured: LineChart's dot geometry (r 3, 2px\n // ring) filled with the metric hue. The ring is that same hue, so the\n // mark is solid — and wide enough against the 2px line not to read as a\n // mere thickening of it. `fillOpacity: 1` is load-bearing: recharts\n // merges the parent mark's own presentation props into every dot it\n // draws, so an `<Area>`'s 0.15 would otherwise wash the dot out to a halo.\n const dot = showDots\n ? {\n r: 3,\n fill: `var(--color-${toCssKey(aKey)})`,\n fillOpacity: 1,\n stroke: `var(--color-${toCssKey(aKey)})`,\n strokeWidth: 2,\n }\n : false;\n return (\n <ActualMark\n key={aKey}\n dataKey={aKey}\n type=\"monotone\"\n stroke={`var(--color-${toCssKey(aKey)})`}\n strokeWidth={strokeWidth}\n {...areaFill}\n dot={dot}\n activeDot={showDots ? { r: 5 } : false}\n connectNulls\n {...animation}\n // The legend names the metric once, so it carries the swatch that\n // stands for the whole series rather than the actual line's style.\n legendType=\"rect\"\n />\n );\n };\n\n const renderForecastLine = ({\n actualKey: aKey,\n forecastKey: fKey,\n }: ConfidenceConeSeries) => {\n // Projected points read as predicted: the same LineChart dot, inverted —\n // the metric's hue as the ring, the surface color as the fill, so the\n // dashed line doesn't show through the middle. (LineChart leaves the fill\n // to recharts, whose `Line` defaults it to `#fff`; the token is that same\n // white in the light theme and also holds up in the dark one.)\n // `strokeDasharray: 'none'` is load-bearing: recharts merges the parent\n // mark's presentation props into every dot, so this line's `5 5` would\n // otherwise break each dot's ring into two arcs.\n const dot = showDots\n ? {\n r: 3,\n fill: 'var(--ui-background-surface-primary)',\n stroke: `var(--color-${toCssKey(aKey)})`,\n strokeWidth: 2,\n strokeDasharray: 'none',\n }\n : false;\n return (\n <Line\n key={fKey}\n dataKey={fKey}\n type=\"monotone\"\n stroke={`var(--color-${toCssKey(aKey)})`}\n strokeWidth={strokeWidth}\n strokeDasharray=\"5 5\"\n dot={dot}\n // Paired with `dot` the way every other chart does it — left unset,\n // the projection would keep recharts' default active dot while the\n // actuals had none (and a different radius when on).\n activeDot={showDots ? { r: 5 } : false}\n connectNulls\n {...animation}\n />\n );\n };\n\n return (\n <div ref={ref} className={cn(className)} {...props}>\n <ChartContainer\n ref={chartContainerRef}\n config={seriesConfig}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <ComposedChart\n data={chartData as readonly unknown[]}\n margin={mergeXAxisLayoutMargin(undefined, xAxisLayout.margin)}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n {renderAxes()}\n {renderForecastRegion()}\n {referenceLines.map(renderThreshold)}\n {showTooltip && renderTooltip()}\n {showLegend && renderLegend()}\n {/* Every cone renders before any line, so the lines draw on top of\n all of them. */}\n {plotted.map(renderConeBand)}\n {plotted.map(renderActualMark)}\n {plotted.map(renderForecastLine)}\n </ComposedChart>\n </ChartContainer>\n </div>\n );\n }\n);\nConfidenceCone.displayName = 'ConfidenceCone';\n\nexport { ConfidenceCone };\n"],"mappings":";;;;;;;;;AAwDA,IAAM,IAAc,UACd,KAAc,MAAsB,GAAG,EAAY,GAAG;AAQ5D,SAAgB,EACd,GACiB;CACjB,OAAO,GAAS,QACb,MACC,EACE,OAAO,EAAK,WAAY,YAAY,EAAK,QAAQ,WAAW,CAAW,EAE7E;AACF;AAQA,SAAgB,EACd,GACA,GACiB;CACjB,OAAO,GAAS,QACb,MACC,OAAO,EAAK,WAAY,YAAY,EAAW,SAAS,EAAK,OAAO,CACxE;AACF;AAoBA,SAAgB,EAAkB,GAAoC;CACpE,OAAO,SAAqB,GAA2B;EACrD,IAAM,IAAS;GACb,GAAG;GACH,SAAS,EAAa,EAAM,OAAO;EACrC;EACA,OAAO,OAAO,KAAmB,aAC7B,EAAM,cACJ,GACA,CACF,IACA,EAAM,aAAa,GAAgB,CAAM;CAC/C;AACF;AAyBA,SAAgB,EACd,GACA,GACA,GAC2C;CAC3C,OAAO,EACJ,QAAQ,MACP,EAAO,MAAM,EAAE,qBAAkB,OAAO,EAAI,MAAiB,QAAQ,CACvE,CAAC,CACA,KAAK,MAAQ,EAAI,EAAK;AAC3B;AAUA,SAAgB,EACd,GACA,GACA,GACA;CACA,OAAO,SAAsB,EAC3B,YACA,UACA,GAAG,KAIF;EACD,IAAM,IAAQ,GAAS;EACvB,OACE,kBAAC,GAAD;GACE,GAAI;GACJ,OACE,KAAS,QAAQ,EAAU,IAAI,CAAK,IAChC;IAAE,WAAW;IAAU,MAAM;GAAM,IACnC,KAAA;GAGL,UAAA,KAAiB,KAAS,OAAO,EAAc,GAAO,CAAK,IAAI;EAC5D,CAAA;CAEV;AACF;AA0HA,IAAM,IAAiB,EAAM,YAEzB,EACE,cACA,WACA,YACA,SACA,SACA,WACA,cACA,gBACA,aACA,aACA,eACA,eACA,WACA,gBAAa,QACb,iBAAc,GACd,cAAW,IACX,wBAAqB,IACrB,kBACA,wBAAqB,IACrB,cAAW,IACX,iBAAc,IACd,iBAAa,IACb,oBACA,qBACA,gBAAY,IACZ,gBAAY,IACZ,mBACA,oBACA,eACA,mBACA,oBACA,iBACA,gBACA,oBACA,kBACA,mBACA,aACA,uBACA,oBACA,qBACA,GAAG,MAEL,OACG;CAEH,IAAM,IAAU,EAAM,cAChB,GAAQ,SAAe,IACvB,CAAC,KAAa,CAAC,IAAoB,CAAC,IACjC,CAAC;EAAE;EAAW;EAAa;EAAU;CAAS,CAAC,GACrD;EAAC;EAAQ;EAAW;EAAa;EAAU;CAAQ,CAAC,GAEjD,IAAY,GAAiB;EACjC;EACA;EACA;EACA;CACF,CAAC,GAGK,IAAgB,EAAM,cACnB,IAAiB,EAAkB,CAAc,IAAI,KAAA,GAC5D,CAAC,CAAc,CACjB,GAEM,KAAa,GAAkB,CAAU,GACzC,KAAa,GAAkB,CAAU,GAEzC,KAAU,EAAkB,EAAW,GAMvC,KAAe,EAAM,cAAc;EACvC,IAAI;EACJ,KAAK,IAAM,EAAE,WAAW,GAAM,aAAa,OAAU,GAAS;GAC5D,IAAM,IAAS,EAAO,IAChB,IAAW,EAAO;GACpB,CAAC,KAAU,CAAC,MAChB,MAAS,EAAE,GAAG,EAAO,GACrB,EAAK,KAAQ;IACX,OAAO,EAAS;IAChB,MAAM,EAAS;IACf,MAAM,EAAE,QAAQ,EAAK;GACvB;EACF;EACA,OAAO,KAAQ;CACjB,GAAG,CAAC,GAAQ,CAAO,CAAC,GAEd,KAAkB,GACtB,EAAK,KAAK,MAAQ,EAAI,EAAK,GAC3B,CACF,GACM,IAAoB,EAAM,OAAuB,IAAI,GACrD,IAAc,GAClB,GACA,GACA,GACA,GAAgB,KAAK,IAAQ,CAC/B,GAKM,KAAY,EAAK,KAAK,MAAQ;EAClC,IAAM,IAAgC,EAAE,GAAG,EAAI;EAC/C,KAAK,IAAM,EACT,WAAW,GACX,UAAU,GACV,UAAU,OACP,GAAS;GACZ,IAAI,CAAC,KAAQ,CAAC,GAAM;GACpB,IAAM,IAAQ,EAAI,IACZ,IAAQ,EAAI;GAClB,EAAK,EAAW,CAAI,KAClB,OAAO,KAAU,YAAY,OAAO,KAAU,WAC1C,CAAC,GAAO,CAAK,IACb,KAAA;EACR;EACA,OAAO;CACT,CAAC,GAEK,IAAY,EAAgB,GAAM,GAAS,CAAI,GAG/C,IAAgB,IAAqB,EAAU,KAAK,KAAA,GACpD,IAAQ,EAAK,EAAK,SAAS,EAAE,GAAG,IAEhC,KAAqB,EACzB,IAAI,IAAI,CAAS,GACjB,eAAe,EAAS,EAAQ,EAAE,EAAE,aAAa,EAAE,EAAE,IACrD,CACF,GAEM,KAAiB,IACnB,MAAM,QAAQ,CAAa,IACzB,IACA,CAAC,CAAa,IAChB,CAAC,GAWC,WACJ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,IAAD;EACE,SAAS;EACT,MAAK;EACL,MAAM,CAAC;EACP,UAAU;EACV,UAAU;EACV,YAAY;EACZ,eAAe;EACf,MAAM,IAAqB,KAAqB,KAAA;EAChD,OAAO;EACP,UAAU;EACV,YAAY,EAAyB,CAAU;EAC/C,QAAQ,EAAY;EACpB,OAAO;CACR,CAAA,GACD,kBAAC,IAAD;EACE,MAAK;EACL,MAAM,CAAC;EACP,UAAU;EACV,UAAU;EACV,MAAM;EACN,eAAe;EACf,WAAW;EACX,QAAQ;EACR,OAAO,GAAkB,EAAK,SAAS,GAAG,EAAQ,CAAW;EAC7D,OAAO;CACR,CAAA,CACD,EAAA,CAAA,GAIE,WACJ,kBAAA,GAAA,EAAA,UAAA,CACG,KAAiB,QAAQ,KAAS,QACjC,kBAAC,IAAD;EACE,IAAI;EACJ,IAAI;EACJ,MAAK;EACL,aAAa;EACb,YAAW;CACZ,CAAA,GAEF,KAAiB,QAChB,kBAAC,GAAD;EACE,GAAG;EACH,QAAO;EACP,iBAAgB;CACjB,CAAA,CAEH,EAAA,CAAA,GAGE,MACJ,GACA,MAEA,kBAAC,GAAD;EAEE,GAAG,EAAU;EACb,QAAO;EACP,iBAAgB;EAEhB,YAAW;EACX,OACE,EAAU,QACN;GACE,OAAO,EAAU;GACjB,UAAU;GACV,MAAM;GACN,UAAA;EACF,IACA,KAAA;CAEP,GAhBM,GAAG,EAAU,SAAS,YAAY,GAAG,GAgB3C,GAGG,UACJ,IAGE,kBAAC,GAAD,EAAc,SAAS,EAAgB,CAAA,IAEvC,kBAAC,GAAD,EACE,UAAU,MACR,kBAAC,GAAD;EACE,QAAQ,EAAG;EACX,OAAO,EAAG;EAEV,SACE,EAAa,EAAG,OAAO;CAE1B,CAAA,EAEJ,CAAA,GAGC,WACJ,kBAAC,GAAD,EACE,UAAU,MACR,kBAAC,GAAD;EACE,eAAe,EAAG;EAClB,UAAU;EACV,WAAW;EACX,SACE,EACE,EAAG,SACH,EAAQ,KAAK,MAAM,EAAE,SAAS,CAChC;CAEH,CAAA,EAEJ,CAAA,GAKG,MAAkB,EACtB,WAAW,GACX,UAAU,GACV,UAAU,QAEV,KAAQ,IACN,kBAAC,GAAD;EAME,aAAU;EACV,SAAS,EAAW,CAAI;EACxB,MAAK;EACL,QAAO;EACP,MAAM,eAAe,EAAS,CAAI,EAAE;EACpC,aAAa;EACb,cAAc;EACd,KAAK;EACL,WAAW;EACX,GAAI;EACJ,YAAW;EACX,aAAY;CACb,GAjBM,EAAW,CAAI,CAiBrB,IACC,MAEA,MAAoB,EAAE,WAAW,QAAiC;EAItE,IAAM,IAAa,MAAe,SAAS,IAAO,GAC5C,IACJ,MAAe,SACX,KAAA,IACA;GAAE,MAAM,eAAe,EAAS,CAAI,EAAE;GAAI,aAAa;EAAK,GAO5D,IAAM,IACR;GACE,GAAG;GACH,MAAM,eAAe,EAAS,CAAI,EAAE;GACpC,aAAa;GACb,QAAQ,eAAe,EAAS,CAAI,EAAE;GACtC,aAAa;EACf,IACA;EACJ,OACE,kBAAC,GAAD;GAEE,SAAS;GACT,MAAK;GACL,QAAQ,eAAe,EAAS,CAAI,EAAE;GACzB;GACb,GAAI;GACC;GACL,WAAW,IAAW,EAAE,GAAG,EAAE,IAAI;GACjC,cAAA;GACA,GAAI;GAGJ,YAAW;EACZ,GAbM,CAaN;CAEL,GAEM,MAAsB,EAC1B,WAAW,GACX,aAAa,QACa;EAS1B,IAAM,IAAM,IACR;GACE,GAAG;GACH,MAAM;GACN,QAAQ,eAAe,EAAS,CAAI,EAAE;GACtC,aAAa;GACb,iBAAiB;EACnB,IACA;EACJ,OACE,kBAAC,GAAD;GAEE,SAAS;GACT,MAAK;GACL,QAAQ,eAAe,EAAS,CAAI,EAAE;GACzB;GACb,iBAAgB;GACX;GAIL,WAAW,IAAW,EAAE,GAAG,EAAE,IAAI;GACjC,cAAA;GACA,GAAI;EACL,GAbM,CAaN;CAEL;CAEA,OACE,kBAAC,OAAD;EAAU;EAAK,WAAW,EAAG,CAAS;EAAG,GAAI;EAC3C,UAAA,kBAAC,GAAD;GACE,KAAK;GACL,QAAQ;GACC;GACT,WAAU;GAEV,UAAA,kBAAC,IAAD;IACE,MAAM;IACN,QAAQ,GAAuB,KAAA,GAAW,EAAY,MAAM;IAF9D,UAAA;KAIG,KACC,kBAAC,IAAD;MACE,YAAY,MAAkB;MAC9B,UAAU,MAAgB;MAC1B,iBAAiB,KAAa,QAAQ,KAAA;KACvC,CAAA;KAEF,GAAW;KACX,GAAqB;KACrB,GAAe,IAAI,EAAe;KAClC,KAAe,EAAc;KAC7B,MAAc,GAAa;KAG3B,EAAQ,IAAI,EAAc;KAC1B,EAAQ,IAAI,EAAgB;KAC5B,EAAQ,IAAI,EAAkB;IAClB;;EACD,CAAA;CACb,CAAA;AAET,CACF;AACA,EAAe,cAAc"}
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  import { cn as e } from "../../../lib/utils.js";
3
3
  import { ChartContainer as t, ChartTooltip as n, ChartTooltipContent as r, toCssKey as i } from "../chart/chart.js";
4
- import { resolveAnimation as a, resolveAxisDomain as o, resolveRotatedTickAnchor as s, resolveXAxisTickLabels as c, resolveXAxisTitle as l, resolveYAxisTitle as u } from "../chart/chart-format.js";
5
- import { mergeXAxisLayoutMargin as d, useXAxisLayout as ee } from "../chart/use-x-axis-layout.js";
4
+ import { resolveAnimation as a, resolveAxisDomain as o, resolveRotatedTickAnchor as s, resolveXAxisTickLabels as c, resolveXAxisTitle as l, resolveYAxisTitle as u, resolveYAxisWidth as ee } from "../chart/chart-format.js";
5
+ import { mergeXAxisLayoutMargin as te, useXAxisLayout as d } from "../chart/use-x-axis-layout.js";
6
6
  import * as f from "react";
7
- import { jsx as p, jsxs as m } from "react/jsx-runtime";
8
- import { Bar as te, BarChart as h, CartesianGrid as g, XAxis as _, YAxis as v } from "recharts";
7
+ import { jsx as p, jsxs as ne } from "react/jsx-runtime";
8
+ import { Bar as m, BarChart as h, CartesianGrid as g, XAxis as _, YAxis as re } from "recharts";
9
9
  //#region src/components/ui/histogram/histogram.tsx
10
- var y = (e) => Number(e.toFixed(2));
11
- function b(e, t, n) {
10
+ var v = (e) => Number(e.toFixed(2));
11
+ function y(e, t, n) {
12
12
  let r = e.filter((e) => typeof e == "number" && Number.isFinite(e));
13
13
  if (r.length === 0 || t < 1) return [];
14
14
  let [i, a] = n ?? [Math.min(...r), Math.max(...r)], o = Math.min(i, a), s = Math.max(i, a), c = o === s ? o + 1 : s, l = (c - o) / t, u = Array.from({ length: t }, (e, n) => {
@@ -16,7 +16,7 @@ function b(e, t, n) {
16
16
  return {
17
17
  x0: r,
18
18
  x1: i,
19
- label: `${y(r)}–${y(i)}`,
19
+ label: `${v(r)}–${v(i)}`,
20
20
  count: 0
21
21
  };
22
22
  });
@@ -27,37 +27,37 @@ function b(e, t, n) {
27
27
  }
28
28
  return u;
29
29
  }
30
- var x = f.forwardRef(({ className: y, config: x, palette: ne, values: S, dataKey: C = "count", binCount: w = 10, domain: T, xAxisLabel: E, yAxisLabel: D, yUnit: O, barRadius: k = 0, showGrid: A = !0, showTooltip: j = !0, showXAxis: M = !0, showYAxis: N = !0, xTickFormatter: P, yTickFormatter: F, xAxisAngle: I, xAxisInterval: L, yAxisTickCount: R, yAxisDomain: z, gridDashed: B, gridHorizontal: V, gridVertical: H, tooltipContent: U, animate: W, animationDuration: G, animationBegin: K, animationEasing: q, ...J }, Y) => {
31
- let X = a({
32
- animate: W,
33
- animationDuration: G,
34
- animationBegin: K,
35
- animationEasing: q
36
- }), re = l(E), ie = u(D), ae = o(z), Z = f.useMemo(() => b(S, w, T), [
30
+ var b = f.forwardRef(({ className: v, config: b, palette: x, values: S, dataKey: C = "count", binCount: w = 10, domain: T, xAxisLabel: E, yAxisLabel: D, yUnit: O, barRadius: k = 0, showGrid: A = !0, showTooltip: j = !0, showXAxis: M = !0, showYAxis: N = !0, xTickFormatter: P, yTickFormatter: F, xAxisAngle: I, xAxisInterval: L, yAxisTickCount: R, yAxisDomain: z, gridDashed: B, gridHorizontal: V, gridVertical: ie, tooltipContent: H, animate: U, animationDuration: W, animationBegin: G, animationEasing: K, ...q }, J) => {
31
+ let Y = a({
32
+ animate: U,
33
+ animationDuration: W,
34
+ animationBegin: G,
35
+ animationEasing: K
36
+ }), ae = l(E), oe = u(D), se = o(z), X = f.useMemo(() => y(S, w, T), [
37
37
  S,
38
38
  w,
39
39
  T
40
- ]).map((e) => ({
40
+ ]), Z = X.map((e) => ({
41
41
  label: e.label,
42
42
  [C]: e.count
43
- })), oe = c(Z.map((e) => e.label), P), Q = f.useRef(null), $ = ee(Q, I, E, oe.join("\0"));
43
+ })), ce = c(Z.map((e) => e.label), P), Q = f.useRef(null), $ = d(Q, I, E, ce.join("\0"));
44
44
  return /* @__PURE__ */ p("div", {
45
- ref: Y,
46
- className: e(y),
47
- ...J,
45
+ ref: J,
46
+ className: e(v),
47
+ ...q,
48
48
  children: /* @__PURE__ */ p(t, {
49
49
  ref: Q,
50
- config: x,
51
- palette: ne,
50
+ config: b,
51
+ palette: x,
52
52
  className: "size-full [&_.recharts-label]:fill-foreground",
53
- children: /* @__PURE__ */ m(h, {
53
+ children: /* @__PURE__ */ ne(h, {
54
54
  data: Z,
55
55
  barCategoryGap: 0,
56
- margin: d(void 0, $.margin),
56
+ margin: te(void 0, $.margin),
57
57
  children: [
58
58
  A && /* @__PURE__ */ p(g, {
59
59
  horizontal: V ?? !0,
60
- vertical: H ?? !1,
60
+ vertical: ie ?? !1,
61
61
  strokeDasharray: B ? "3 3" : void 0
62
62
  }),
63
63
  /* @__PURE__ */ p(_, {
@@ -70,9 +70,9 @@ var x = f.forwardRef(({ className: y, config: x, palette: ne, values: S, dataKey
70
70
  interval: L,
71
71
  textAnchor: s(I),
72
72
  height: $.height,
73
- label: re
73
+ label: ae
74
74
  }),
75
- /* @__PURE__ */ p(v, {
75
+ /* @__PURE__ */ p(re, {
76
76
  type: "number",
77
77
  hide: !N,
78
78
  tickLine: !1,
@@ -81,12 +81,12 @@ var x = f.forwardRef(({ className: y, config: x, palette: ne, values: S, dataKey
81
81
  unit: O,
82
82
  tickFormatter: F,
83
83
  tickCount: R,
84
- domain: ae,
85
- width: D ? 72 : void 0,
86
- label: ie
84
+ domain: se,
85
+ width: ee(X.length > 0, !!D),
86
+ label: oe
87
87
  }),
88
- j && /* @__PURE__ */ p(n, { content: U ?? /* @__PURE__ */ p(r, {}) }),
89
- /* @__PURE__ */ p(te, {
88
+ j && /* @__PURE__ */ p(n, { content: H ?? /* @__PURE__ */ p(r, {}) }),
89
+ /* @__PURE__ */ p(m, {
90
90
  dataKey: C,
91
91
  fill: `var(--color-${i(String(C))})`,
92
92
  stroke: "var(--ui-background-surface-primary)",
@@ -97,15 +97,15 @@ var x = f.forwardRef(({ className: y, config: x, palette: ne, values: S, dataKey
97
97
  0,
98
98
  0
99
99
  ] : void 0,
100
- ...X
100
+ ...Y
101
101
  })
102
102
  ]
103
103
  })
104
104
  })
105
105
  });
106
106
  });
107
- x.displayName = "Histogram";
107
+ b.displayName = "Histogram";
108
108
  //#endregion
109
- export { x as Histogram, b as computeHistogramBins };
109
+ export { b as Histogram, y as computeHistogramBins };
110
110
 
111
111
  //# sourceMappingURL=histogram.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"histogram.js","names":[],"sources":["../../../../src/components/ui/histogram/histogram.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Bar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n XAxis,\n YAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveAxisDomain,\n resolveRotatedTickAnchor,\n resolveXAxisTitle,\n resolveYAxisTitle,\n type ChartConfig,\n toCssKey,\n type ChartPalette,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\nimport {\n mergeXAxisLayoutMargin,\n useXAxisLayout,\n} from '../chart/use-x-axis-layout';\nimport { resolveXAxisTickLabels } from '../chart/chart-format';\n\n// A histogram bins a set of continuous samples into equal-width ranges and plots\n// the frequency of each as contiguous bars — distinct from BarChart, whose bars\n// are pre-categorized. The binning is the component's job (a pure helper), so the\n// consumer passes raw `values`, not pre-aggregated rows. Built on the shared\n// `Chart` primitives; no new tokens (the single series' color is caller-supplied\n// via `config`, same `--color-<key>` mechanism as the other chart types).\n\nexport interface HistogramBin {\n /** Lower bound of the bin (inclusive). */\n x0: number;\n /** Upper bound of the bin (exclusive, except the last bin which is inclusive). */\n x1: number;\n /** Human-readable range label, e.g. `\"0–10\"`. */\n label: string;\n /** How many samples fell in the bin. */\n count: number;\n}\n\nconst roundEdge = (n: number) => Number(n.toFixed(2));\n\n/**\n * Split `values` into `binCount` equal-width bins and count the samples in each.\n * The range is `domain` if given, else the data's [min, max]; values outside the\n * domain are dropped, and the max value lands in the last (inclusive) bin.\n * Returns [] when there's nothing to bin. Exported for unit tests; not part of\n * the package's public API.\n */\nexport function computeHistogramBins(\n values: ReadonlyArray<number>,\n binCount: number,\n domain?: [number, number]\n): HistogramBin[] {\n const nums = values.filter(\n (v): v is number => typeof v === 'number' && Number.isFinite(v)\n );\n if (nums.length === 0 || binCount < 1) return [];\n\n const [d0, d1] = domain ?? [Math.min(...nums), Math.max(...nums)];\n // Normalize an inverted domain ([max, min]) so binning stays robust.\n const min = Math.min(d0, d1);\n const hi = Math.max(d0, d1);\n // A zero-width range (all values equal, or a degenerate domain) can't be\n // divided — widen it by 1 so the single bin has extent.\n const max = min === hi ? min + 1 : hi;\n const width = (max - min) / binCount;\n\n const bins: HistogramBin[] = Array.from({ length: binCount }, (_, i) => {\n const x0 = min + i * width;\n const x1 = i === binCount - 1 ? max : min + (i + 1) * width;\n return { x0, x1, label: `${roundEdge(x0)}–${roundEdge(x1)}`, count: 0 };\n });\n\n for (const v of nums) {\n if (v < min || v > max) continue;\n let idx = Math.floor((v - min) / width);\n if (idx >= binCount) idx = binCount - 1; // the max value\n bins[idx].count += 1;\n }\n return bins;\n}\n\nexport interface HistogramProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n CartesianChartProps,\n ChartAnimationProps {\n /**\n * The dataviz palette this chart's series are painted from. Series that\n * state no `color` of their own take a stop of it. See `ChartPalette`.\n */\n palette?: ChartPalette;\n /** Raw continuous samples to bin (non-finite values are ignored). */\n values: ReadonlyArray<number>;\n /**\n * Single-series map of `label` / `icon` / `tone`, keyed by `dataKey` (imported\n * from the shared `Chart` primitives). Series take their colour from the\n * container's `palette`; each entry maps a key to a `label` and an optional\n * `tone`.\n */\n config: ChartConfig;\n /** `config` key that colors + labels the frequency bars. */\n dataKey?: string;\n /** Number of equal-width bins. */\n binCount?: number;\n /** Fix the binning range instead of deriving it from the data's min/max. */\n domain?: [number, number];\n /** Corner radius on the top of each bar. */\n barRadius?: number;\n}\n\nconst Histogram = React.forwardRef<HTMLDivElement, HistogramProps>(\n (\n {\n className,\n config,\n palette,\n values,\n dataKey = 'count',\n binCount = 10,\n domain,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n barRadius = 0,\n showGrid = true,\n showTooltip = true,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const xAxisTitle = resolveXAxisTitle(xAxisLabel);\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n const yDomain = resolveAxisDomain(yAxisDomain);\n\n const bins = React.useMemo(\n () => computeHistogramBins(values, binCount, domain),\n [values, binCount, domain]\n );\n // Bars carry the bin `label` as the category and `count` under `dataKey`, so\n // the tooltip resolves the frequency from `config[dataKey]`.\n const data = bins.map((bin) => ({ label: bin.label, [dataKey]: bin.count }));\n const xAxisTickLabels = resolveXAxisTickLabels(\n data.map((row) => row.label),\n xTickFormatter\n );\n const chartContainerRef = React.useRef<HTMLDivElement>(null);\n const xAxisLayout = useXAxisLayout(\n chartContainerRef,\n xAxisAngle,\n xAxisLabel,\n xAxisTickLabels.join('\\u0000')\n );\n\n return (\n <div\n ref={ref}\n className={cn(className)}\n {...props}\n >\n <ChartContainer\n ref={chartContainerRef}\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsBarChart\n data={data}\n barCategoryGap={0}\n margin={mergeXAxisLayoutMargin(undefined, xAxisLayout.margin)}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n <XAxis\n dataKey=\"label\"\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickFormatter={xTickFormatter}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={resolveRotatedTickAnchor(xAxisAngle)}\n height={xAxisLayout.height}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n allowDecimals={false}\n unit={yUnit}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n {showTooltip && (\n <ChartTooltip content={tooltipContent ?? <ChartTooltipContent />} />\n )}\n <Bar\n dataKey={dataKey}\n fill={`var(--color-${toCssKey(String(dataKey))})`}\n // A hairline in the surface color separates the contiguous bars so\n // they don't blend into one mass (same trick as the Treemap cells).\n stroke=\"var(--ui-background-surface-primary)\"\n strokeWidth={1}\n radius={barRadius > 0 ? [barRadius, barRadius, 0, 0] : undefined}\n {...animation}\n />\n </RechartsBarChart>\n </ChartContainer>\n </div>\n );\n }\n);\nHistogram.displayName = 'Histogram';\n\nexport { Histogram };\n"],"mappings":"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"}
1
+ {"version":3,"file":"histogram.js","names":[],"sources":["../../../../src/components/ui/histogram/histogram.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Bar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n XAxis,\n YAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n resolveAnimation,\n resolveAxisDomain,\n resolveRotatedTickAnchor,\n resolveXAxisTitle,\n resolveYAxisTitle,\n type ChartConfig,\n toCssKey,\n type ChartPalette,\n type CartesianChartProps,\n type ChartAnimationProps,\n} from '../chart';\nimport {\n mergeXAxisLayoutMargin,\n useXAxisLayout,\n} from '../chart/use-x-axis-layout';\nimport { resolveXAxisTickLabels, resolveYAxisWidth } from '../chart/chart-format';\n\n// A histogram bins a set of continuous samples into equal-width ranges and plots\n// the frequency of each as contiguous bars — distinct from BarChart, whose bars\n// are pre-categorized. The binning is the component's job (a pure helper), so the\n// consumer passes raw `values`, not pre-aggregated rows. Built on the shared\n// `Chart` primitives; no new tokens (the single series' color is caller-supplied\n// via `config`, same `--color-<key>` mechanism as the other chart types).\n\nexport interface HistogramBin {\n /** Lower bound of the bin (inclusive). */\n x0: number;\n /** Upper bound of the bin (exclusive, except the last bin which is inclusive). */\n x1: number;\n /** Human-readable range label, e.g. `\"0–10\"`. */\n label: string;\n /** How many samples fell in the bin. */\n count: number;\n}\n\nconst roundEdge = (n: number) => Number(n.toFixed(2));\n\n/**\n * Split `values` into `binCount` equal-width bins and count the samples in each.\n * The range is `domain` if given, else the data's [min, max]; values outside the\n * domain are dropped, and the max value lands in the last (inclusive) bin.\n * Returns [] when there's nothing to bin. Exported for unit tests; not part of\n * the package's public API.\n */\nexport function computeHistogramBins(\n values: ReadonlyArray<number>,\n binCount: number,\n domain?: [number, number]\n): HistogramBin[] {\n const nums = values.filter(\n (v): v is number => typeof v === 'number' && Number.isFinite(v)\n );\n if (nums.length === 0 || binCount < 1) return [];\n\n const [d0, d1] = domain ?? [Math.min(...nums), Math.max(...nums)];\n // Normalize an inverted domain ([max, min]) so binning stays robust.\n const min = Math.min(d0, d1);\n const hi = Math.max(d0, d1);\n // A zero-width range (all values equal, or a degenerate domain) can't be\n // divided — widen it by 1 so the single bin has extent.\n const max = min === hi ? min + 1 : hi;\n const width = (max - min) / binCount;\n\n const bins: HistogramBin[] = Array.from({ length: binCount }, (_, i) => {\n const x0 = min + i * width;\n const x1 = i === binCount - 1 ? max : min + (i + 1) * width;\n return { x0, x1, label: `${roundEdge(x0)}–${roundEdge(x1)}`, count: 0 };\n });\n\n for (const v of nums) {\n if (v < min || v > max) continue;\n let idx = Math.floor((v - min) / width);\n if (idx >= binCount) idx = binCount - 1; // the max value\n bins[idx].count += 1;\n }\n return bins;\n}\n\nexport interface HistogramProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n CartesianChartProps,\n ChartAnimationProps {\n /**\n * The dataviz palette this chart's series are painted from. Series that\n * state no `color` of their own take a stop of it. See `ChartPalette`.\n */\n palette?: ChartPalette;\n /** Raw continuous samples to bin (non-finite values are ignored). */\n values: ReadonlyArray<number>;\n /**\n * Single-series map of `label` / `icon` / `tone`, keyed by `dataKey` (imported\n * from the shared `Chart` primitives). Series take their colour from the\n * container's `palette`; each entry maps a key to a `label` and an optional\n * `tone`.\n */\n config: ChartConfig;\n /** `config` key that colors + labels the frequency bars. */\n dataKey?: string;\n /** Number of equal-width bins. */\n binCount?: number;\n /** Fix the binning range instead of deriving it from the data's min/max. */\n domain?: [number, number];\n /** Corner radius on the top of each bar. */\n barRadius?: number;\n}\n\nconst Histogram = React.forwardRef<HTMLDivElement, HistogramProps>(\n (\n {\n className,\n config,\n palette,\n values,\n dataKey = 'count',\n binCount = 10,\n domain,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n barRadius = 0,\n showGrid = true,\n showTooltip = true,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n ...props\n },\n ref\n ) => {\n const animation = resolveAnimation({\n animate,\n animationDuration,\n animationBegin,\n animationEasing,\n });\n const xAxisTitle = resolveXAxisTitle(xAxisLabel);\n const yAxisTitle = resolveYAxisTitle(yAxisLabel);\n\n const yDomain = resolveAxisDomain(yAxisDomain);\n\n const bins = React.useMemo(\n () => computeHistogramBins(values, binCount, domain),\n [values, binCount, domain]\n );\n // Bars carry the bin `label` as the category and `count` under `dataKey`, so\n // the tooltip resolves the frequency from `config[dataKey]`.\n const data = bins.map((bin) => ({ label: bin.label, [dataKey]: bin.count }));\n const xAxisTickLabels = resolveXAxisTickLabels(\n data.map((row) => row.label),\n xTickFormatter\n );\n const chartContainerRef = React.useRef<HTMLDivElement>(null);\n const xAxisLayout = useXAxisLayout(\n chartContainerRef,\n xAxisAngle,\n xAxisLabel,\n xAxisTickLabels.join('\\u0000')\n );\n\n return (\n <div\n ref={ref}\n className={cn(className)}\n {...props}\n >\n <ChartContainer\n ref={chartContainerRef}\n config={config}\n palette={palette}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsBarChart\n data={data}\n barCategoryGap={0}\n margin={mergeXAxisLayoutMargin(undefined, xAxisLayout.margin)}\n >\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n <XAxis\n dataKey=\"label\"\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickFormatter={xTickFormatter}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={resolveRotatedTickAnchor(xAxisAngle)}\n height={xAxisLayout.height}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n allowDecimals={false}\n unit={yUnit}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={resolveYAxisWidth(bins.length > 0, Boolean(yAxisLabel))}\n label={yAxisTitle}\n />\n {showTooltip && (\n <ChartTooltip content={tooltipContent ?? <ChartTooltipContent />} />\n )}\n <Bar\n dataKey={dataKey}\n fill={`var(--color-${toCssKey(String(dataKey))})`}\n // A hairline in the surface color separates the contiguous bars so\n // they don't blend into one mass (same trick as the Treemap cells).\n stroke=\"var(--ui-background-surface-primary)\"\n strokeWidth={1}\n radius={barRadius > 0 ? [barRadius, barRadius, 0, 0] : undefined}\n {...animation}\n />\n </RechartsBarChart>\n </ChartContainer>\n </div>\n );\n }\n);\nHistogram.displayName = 'Histogram';\n\nexport { Histogram };\n"],"mappings":"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"}
@@ -2,11 +2,11 @@
2
2
  import { cn as e } from "../../../lib/utils.js";
3
3
  import { cva as t } from "../../../node_modules/.pnpm/class-variance-authority@0.7.1/node_modules/class-variance-authority/dist/index.js";
4
4
  import { ChartContainer as n, ChartLegend as r, ChartLegendContent as i, ChartTooltip as a, ChartTooltipContent as o, toCssKey as s } from "../chart/chart.js";
5
- import { CHART_LABEL_MARGIN as c, dropProjectionPayload as l, resolveAnimation as u, resolveAxisDomain as d, resolveBrushProps as f, resolveChartReferenceValue as p, resolveLabelFillClass as ee, resolveReferenceLineProps as te, resolveRotatedTickAnchor as ne, resolveXAxisTickLabels as re, resolveXAxisTitle as ie, resolveYAxisTitle as ae, toLabelFormatter as oe, toReferenceLineList as se } from "../chart/chart-format.js";
6
- import { mergeXAxisLayoutMargin as ce, useXAxisLayout as le } from "../chart/use-x-axis-layout.js";
5
+ import { CHART_LABEL_MARGIN as c, dropProjectionPayload as l, resolveAnimation as u, resolveAxisDomain as d, resolveBrushProps as f, resolveChartReferenceValue as p, resolveLabelFillClass as ee, resolveReferenceLineProps as te, resolveRotatedTickAnchor as ne, resolveXAxisTickLabels as re, resolveXAxisTitle as ie, resolveYAxisTitle as ae, resolveYAxisWidth as oe, toLabelFormatter as se, toReferenceLineList as ce } from "../chart/chart-format.js";
6
+ import { mergeXAxisLayoutMargin as le, useXAxisLayout as ue } from "../chart/use-x-axis-layout.js";
7
7
  import * as m from "react";
8
8
  import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
9
- import { Area as ue, Brush as de, CartesianGrid as fe, ComposedChart as pe, LabelList as me, Line as v, LineChart as he, ReferenceLine as ge, Text as _e, XAxis as ve, YAxis as ye, usePlotArea as y, useXAxisScale as b } from "recharts";
9
+ import { Area as de, Brush as fe, CartesianGrid as pe, ComposedChart as me, LabelList as he, Line as v, LineChart as ge, ReferenceLine as _e, Text as ve, XAxis as ye, YAxis as be, usePlotArea as y, useXAxisScale as b } from "recharts";
10
10
  //#region src/components/ui/line-chart/line-chart.tsx
11
11
  var x = t("", {
12
12
  variants: {
@@ -29,7 +29,7 @@ var x = t("", {
29
29
  lineStyle: "solid"
30
30
  }
31
31
  });
32
- function be({ projectionStart: e, prevTick: t, clipId: n, dataKeys: r }) {
32
+ function xe({ projectionStart: e, prevTick: t, clipId: n, dataKeys: r }) {
33
33
  let i = b(), a = y();
34
34
  if (!i || !a) return null;
35
35
  let o = i(t), s = i(e);
@@ -77,7 +77,7 @@ function w(e) {
77
77
  return typeof e == "function" ? /* @__PURE__ */ g(e, { ...n }) : m.cloneElement(e, n);
78
78
  };
79
79
  }
80
- function xe(e) {
80
+ function Se(e) {
81
81
  return function(t) {
82
82
  let n = {
83
83
  ...t,
@@ -86,20 +86,20 @@ function xe(e) {
86
86
  return typeof e == "function" ? /* @__PURE__ */ g(e, { ...n }) : m.cloneElement(e, n);
87
87
  };
88
88
  }
89
- var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys: T, comparisonKeys: E, deltaBands: Se, xKey: D, xAxisLabel: O, yAxisLabel: k, yUnit: Ce, curve: A = "monotone", lineStyle: j = "solid", strokeWidth: M = 2, showDots: we = !1, dotSize: Te = 3, showActiveDot: Ee, connectNulls: N = !1, lineSettings: P, referenceLine: De, projectionStart: F, showGrid: Oe = !0, showTooltip: ke = !0, showLegend: Ae = !0, legendFontSize: I, legendAriaLabel: L, showXAxis: je = !0, showYAxis: Me = !0, xTickFormatter: R, yTickFormatter: Ne, xAxisAngle: z, xAxisInterval: Pe, yAxisTickCount: Fe, yAxisDomain: Ie, gridDashed: Le, gridHorizontal: Re, gridVertical: ze, tooltipContent: B, animate: Be, animationDuration: Ve, animationBegin: He, animationEasing: Ue, showLabels: V = !1, labelPosition: We, labelFormatter: Ge, showBrush: Ke = !1, brushHeight: qe, brushAriaLabel: Je, ...Ye }, Xe) => {
89
+ var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys: T, comparisonKeys: E, deltaBands: Ce, xKey: D, xAxisLabel: O, yAxisLabel: k, yUnit: we, curve: A = "monotone", lineStyle: j = "solid", strokeWidth: M = 2, showDots: Te = !1, dotSize: Ee = 3, showActiveDot: De, connectNulls: N = !1, lineSettings: P, referenceLine: Oe, projectionStart: F, showGrid: ke = !0, showTooltip: Ae = !0, showLegend: je = !0, legendFontSize: I, legendAriaLabel: L, showXAxis: Me = !0, showYAxis: Ne = !0, xTickFormatter: R, yTickFormatter: Pe, xAxisAngle: z, xAxisInterval: Fe, yAxisTickCount: Ie, yAxisDomain: Le, gridDashed: Re, gridHorizontal: ze, gridVertical: Be, tooltipContent: B, animate: Ve, animationDuration: He, animationBegin: Ue, animationEasing: We, showLabels: V = !1, labelPosition: Ge, labelFormatter: Ke, showBrush: qe = !1, brushHeight: Je, brushAriaLabel: Ye, ...Xe }, Ze) => {
90
90
  let H = u({
91
- animate: Be,
92
- animationDuration: Ve,
93
- animationBegin: He,
94
- animationEasing: Ue
95
- }), Ze = We ?? "top", Qe = d(Ie), $e = se(De), U = (e) => P?.[e]?.color ?? `var(--color-${s(e)})`, W = (e) => P?.[e]?.curveType ?? A ?? "monotone", et = V || Object.values(P ?? {}).some((e) => e.showLabel), tt = re(b.map((e) => e[D]), R), G = m.useRef(null), K = le(G, z, O, tt.join("\0")), nt = ce(et ? c : void 0, K.margin), q = m.useMemo(() => F === void 0 ? -1 : b.findIndex((e) => e[D] === F), [
91
+ animate: Ve,
92
+ animationDuration: He,
93
+ animationBegin: Ue,
94
+ animationEasing: We
95
+ }), Qe = Ge ?? "top", $e = d(Le), et = ce(Oe), U = (e) => P?.[e]?.color ?? `var(--color-${s(e)})`, W = (e) => P?.[e]?.curveType ?? A ?? "monotone", tt = V || Object.values(P ?? {}).some((e) => e.showLabel), nt = re(b.map((e) => e[D]), R), G = m.useRef(null), K = ue(G, z, O, nt.join("\0")), rt = le(tt ? c : void 0, K.margin), q = m.useMemo(() => F === void 0 ? -1 : b.findIndex((e) => e[D] === F), [
96
96
  F,
97
97
  b,
98
98
  D
99
99
  ]), J = q > 0, Y = m.useMemo(() => {
100
100
  if (!J) return;
101
101
  let e = new Set(b.slice(q).map((e) => e[D]));
102
- return ({ payload: t, index: n, ...r }) => /* @__PURE__ */ g(_e, {
102
+ return ({ payload: t, index: n, ...r }) => /* @__PURE__ */ g(ve, {
103
103
  ...r,
104
104
  fontSize: 12,
105
105
  className: e.has(t.value) ? "fill-[var(--ui-text-on-surface-disabled)]" : "fill-muted-foreground",
@@ -111,32 +111,32 @@ var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys:
111
111
  b,
112
112
  D,
113
113
  R
114
- ]), X = m.useMemo(() => J ? b.map((e) => ({
114
+ ]), it = m.useMemo(() => J ? b.map((e) => ({
115
115
  ...e,
116
116
  ...Object.fromEntries(T.map((t) => [`_proj_${t}`, e[t]]))
117
117
  })) : b, [
118
118
  J,
119
119
  b,
120
120
  T
121
- ]), Z = m.useMemo(() => {
121
+ ]), X = m.useMemo(() => {
122
122
  if (!(q <= 0)) return b[q - 1]?.[D];
123
123
  }, [
124
124
  q,
125
125
  b,
126
126
  D
127
- ]), Q = `line-proj-${m.useId().replace(/:/g, "")}`, rt = m.useMemo(() => {
127
+ ]), Z = `line-proj-${m.useId().replace(/:/g, "")}`, at = m.useMemo(() => {
128
128
  if (!B) return;
129
129
  let e = w(B);
130
- return J ? xe(e) : e;
131
- }, [B, J]), it = ie(O), at = ae(k), $ = (Se ?? []).map(([e, t], n) => ({
130
+ return J ? Se(e) : e;
131
+ }, [B, J]), ot = ie(O), st = ae(k), Q = (Ce ?? []).map(([e, t], n) => ({
132
132
  field: `${S}${n}`,
133
133
  current: e,
134
134
  comparison: t
135
- })), ot = $.length > 0, st = rt ?? (ot || J ? ((e) => /* @__PURE__ */ g(o, {
135
+ })), $ = Q.length > 0, ct = at ?? ($ || J ? ((e) => /* @__PURE__ */ g(o, {
136
136
  active: e.active,
137
137
  label: e.label,
138
138
  payload: l(C(e.payload))
139
- })) : /* @__PURE__ */ g(o, {})), ct = ot || J ? ((e) => /* @__PURE__ */ g(i, {
139
+ })) : /* @__PURE__ */ g(o, {})), lt = $ || J ? ((e) => /* @__PURE__ */ g(i, {
140
140
  verticalAlign: e.verticalAlign,
141
141
  fontSize: I,
142
142
  ariaLabel: L,
@@ -144,73 +144,73 @@ var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys:
144
144
  })) : /* @__PURE__ */ g(i, {
145
145
  fontSize: I,
146
146
  ariaLabel: L
147
- }), lt = $.length ? X.map((e) => {
147
+ }), ut = Q.length ? it.map((e) => {
148
148
  let t = { ...e };
149
- for (let { field: n, current: r, comparison: i } of $) {
149
+ for (let { field: n, current: r, comparison: i } of Q) {
150
150
  let a = e[r], o = e[i];
151
151
  t[n] = typeof a == "number" && typeof o == "number" ? [Math.min(a, o), Math.max(a, o)] : void 0;
152
152
  }
153
153
  return t;
154
- }) : X, ut = $.length > 0 ? pe : he;
154
+ }) : it, dt = Q.length > 0 ? me : ge;
155
155
  return /* @__PURE__ */ g("div", {
156
- ref: Xe,
156
+ ref: Ze,
157
157
  "data-curve": A,
158
158
  "data-line-style": j,
159
159
  className: e(x({
160
160
  curve: A,
161
161
  lineStyle: j
162
162
  }), t),
163
- ...Ye,
163
+ ...Xe,
164
164
  children: /* @__PURE__ */ g(n, {
165
165
  ref: G,
166
166
  config: h,
167
167
  palette: y,
168
168
  className: "size-full [&_.recharts-label]:fill-foreground",
169
- children: /* @__PURE__ */ _(ut, {
170
- data: lt,
171
- margin: nt,
169
+ children: /* @__PURE__ */ _(dt, {
170
+ data: ut,
171
+ margin: rt,
172
172
  children: [
173
- Oe && /* @__PURE__ */ g(fe, {
174
- horizontal: Re ?? !0,
175
- vertical: ze ?? !1,
176
- strokeDasharray: Le ? "3 3" : void 0
173
+ ke && /* @__PURE__ */ g(pe, {
174
+ horizontal: ze ?? !0,
175
+ vertical: Be ?? !1,
176
+ strokeDasharray: Re ? "3 3" : void 0
177
177
  }),
178
- /* @__PURE__ */ g(ve, {
178
+ /* @__PURE__ */ g(ye, {
179
179
  dataKey: D,
180
180
  type: "category",
181
- hide: !je,
181
+ hide: !Me,
182
182
  tickLine: !1,
183
183
  axisLine: !1,
184
184
  tickMargin: 8,
185
185
  tickFormatter: Y ? void 0 : R,
186
186
  tick: Y,
187
187
  angle: z,
188
- interval: Pe,
188
+ interval: Fe,
189
189
  textAnchor: ne(z),
190
190
  height: K.height,
191
- label: it
191
+ label: ot
192
192
  }),
193
- /* @__PURE__ */ g(ye, {
193
+ /* @__PURE__ */ g(be, {
194
194
  type: "number",
195
- hide: !Me,
195
+ hide: !Ne,
196
196
  tickLine: !1,
197
197
  axisLine: !1,
198
- unit: Ce,
199
- tickFormatter: Ne,
200
- tickCount: Fe,
201
- domain: Qe,
202
- width: k ? 72 : void 0,
203
- label: at
198
+ unit: we,
199
+ tickFormatter: Pe,
200
+ tickCount: Ie,
201
+ domain: $e,
202
+ width: oe(b.length > 0, !!k),
203
+ label: st
204
204
  }),
205
- ke && /* @__PURE__ */ g(a, { content: st }),
206
- Ae && /* @__PURE__ */ g(r, { content: ct }),
207
- J && Z != null && /* @__PURE__ */ g(be, {
205
+ Ae && /* @__PURE__ */ g(a, { content: ct }),
206
+ je && /* @__PURE__ */ g(r, { content: lt }),
207
+ J && X != null && /* @__PURE__ */ g(xe, {
208
208
  projectionStart: F,
209
- prevTick: Z,
210
- clipId: Q,
209
+ prevTick: X,
210
+ clipId: Z,
211
211
  dataKeys: T
212
212
  }),
213
- $.map(({ field: e, current: t }) => /* @__PURE__ */ g(ue, {
213
+ Q.map(({ field: e, current: t }) => /* @__PURE__ */ g(de, {
214
214
  dataKey: e,
215
215
  type: W(t),
216
216
  stroke: "none",
@@ -219,15 +219,15 @@ var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys:
219
219
  connectNulls: N,
220
220
  dot: !1,
221
221
  activeDot: !1,
222
- clipPath: J ? `url(#${Q}-actual)` : void 0,
222
+ clipPath: J ? `url(#${Z}-actual)` : void 0,
223
223
  ...H,
224
224
  legendType: "none",
225
225
  tooltipType: "none"
226
226
  }, e)),
227
227
  T.map((e, t) => {
228
- let n = E?.includes(e), r = P?.[e], i = !n && (r?.showDots ?? we), a = r?.dotSize ?? Te, o = !n && (Ee ?? i), s = r?.dashed ?? j === "dashed", c = r?.showLabel ?? V, l = r?.labelPosition ?? Ze;
228
+ let n = E?.includes(e), r = P?.[e], i = !n && (r?.showDots ?? Te), a = r?.dotSize ?? Ee, o = !n && (De ?? i), s = r?.dashed ?? j === "dashed", c = r?.showLabel ?? V, l = r?.labelPosition ?? Qe;
229
229
  return /* @__PURE__ */ g(v, {
230
- className: J && !n ? `actual-${Q}-${t}` : void 0,
230
+ className: J && !n ? `actual-${Z}-${t}` : void 0,
231
231
  type: W(e),
232
232
  dataKey: e,
233
233
  stroke: U(e),
@@ -238,10 +238,10 @@ var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys:
238
238
  activeDot: o ? { r: a + 2 } : !1,
239
239
  connectNulls: N,
240
240
  ...H,
241
- children: c && /* @__PURE__ */ g(me, {
241
+ children: c && /* @__PURE__ */ g(he, {
242
242
  dataKey: e,
243
243
  position: l,
244
- formatter: oe(Ge),
244
+ formatter: se(Ke),
245
245
  className: ee(l),
246
246
  fontSize: 12
247
247
  })
@@ -251,7 +251,7 @@ var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys:
251
251
  if (E?.includes(e)) return null;
252
252
  let n = P?.[e];
253
253
  return /* @__PURE__ */ g(v, {
254
- className: `proj-${Q}-${t}`,
254
+ className: `proj-${Z}-${t}`,
255
255
  type: W(e),
256
256
  dataKey: `_proj_${e}`,
257
257
  name: e,
@@ -265,19 +265,19 @@ var T = m.forwardRef(({ className: t, config: h, palette: y, data: b, dataKeys:
265
265
  ...H
266
266
  }, `_proj_${e}`);
267
267
  }),
268
- $e.map((e, t) => {
268
+ et.map((e, t) => {
269
269
  let n = p(e, b, T);
270
- return n === void 0 ? null : /* @__PURE__ */ g(ge, {
270
+ return n === void 0 ? null : /* @__PURE__ */ g(_e, {
271
271
  y: n,
272
272
  ...te(e.label, e.labelPosition)
273
273
  }, `${e.label ?? "ref"}-${t}`);
274
274
  }),
275
- Ke && /* @__PURE__ */ g(de, {
275
+ qe && /* @__PURE__ */ g(fe, {
276
276
  dataKey: D,
277
277
  tickFormatter: R,
278
278
  ...f({
279
- brushHeight: qe,
280
- brushAriaLabel: Je
279
+ brushHeight: Je,
280
+ brushAriaLabel: Ye
281
281
  })
282
282
  })
283
283
  ]