@shapesos/clay 0.17.0 → 0.19.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/ai-elements.cjs +3 -1
- package/dist/ai-elements.cjs.map +1 -1
- package/dist/ai-elements.js +4 -4
- package/dist/artifacts.cjs +1010 -60
- package/dist/artifacts.cjs.map +1 -1
- package/dist/artifacts.d.cts +20 -3
- package/dist/artifacts.d.ts +20 -3
- package/dist/artifacts.js +15 -6
- package/dist/badge.cjs +70 -0
- package/dist/badge.cjs.map +1 -0
- package/dist/badge.d.cts +28 -0
- package/dist/badge.d.ts +28 -0
- package/dist/badge.js +9 -0
- package/dist/blocks.cjs +981 -96
- package/dist/blocks.cjs.map +1 -1
- package/dist/blocks.css +1 -1
- package/dist/blocks.d.cts +15 -4
- package/dist/blocks.d.ts +15 -4
- package/dist/blocks.js +20 -8
- package/dist/button.cjs +3 -1
- package/dist/button.cjs.map +1 -1
- package/dist/button.js +2 -2
- package/dist/capture.cjs +3 -1
- package/dist/capture.cjs.map +1 -1
- package/dist/capture.js +2 -2
- package/dist/chart.cjs +3 -1
- package/dist/chart.cjs.map +1 -1
- package/dist/chart.js +2 -2
- package/dist/chat.cjs +986 -151
- package/dist/chat.cjs.map +1 -1
- package/dist/chat.d.cts +2 -2
- package/dist/chat.d.ts +2 -2
- package/dist/chat.js +13 -8
- package/dist/{chunk-JGMN6W72.js → chunk-2X4KUXYP.js} +1 -1
- package/dist/chunk-BHHJOG5X.js +1 -0
- package/dist/{chunk-B4U37WIH.js → chunk-CFCLVJIO.js} +2 -2
- package/dist/chunk-CSTCTO3B.js +161 -0
- package/dist/chunk-CSTCTO3B.js.map +1 -0
- package/dist/{chunk-6YZ65KPW.js → chunk-DC5KYT2G.js} +669 -171
- package/dist/chunk-DC5KYT2G.js.map +1 -0
- package/dist/{chunk-PYDVANWI.js → chunk-E36VI2HA.js} +2 -2
- package/dist/chunk-EIAWZXE4.js +69 -0
- package/dist/chunk-EIAWZXE4.js.map +1 -0
- package/dist/chunk-EXRNGIQ2.js +41 -0
- package/dist/chunk-EXRNGIQ2.js.map +1 -0
- package/dist/{chunk-B6GAPZ2R.js → chunk-FCSYVF4Z.js} +12 -46
- package/dist/chunk-FCSYVF4Z.js.map +1 -0
- package/dist/{chunk-PUVZ2S3F.js → chunk-G4NXVFXU.js} +2 -2
- package/dist/{chunk-JAGNXEWK.js → chunk-GK4XW4BC.js} +2 -2
- package/dist/{chunk-4MZZH3WX.js → chunk-HU5W7CGE.js} +37 -2
- package/dist/chunk-HU5W7CGE.js.map +1 -0
- package/dist/chunk-JMHE3Q5K.js +406 -0
- package/dist/chunk-JMHE3Q5K.js.map +1 -0
- package/dist/{chunk-4VE6ZXXW.js → chunk-MQP57DOP.js} +3 -3
- package/dist/{chunk-JF3P66JF.js → chunk-SN3ORQSJ.js} +4 -2
- package/dist/{chunk-JF3P66JF.js.map → chunk-SN3ORQSJ.js.map} +1 -1
- package/dist/{chunk-PGR2MDDU.js → chunk-W66OJM55.js} +2 -2
- package/dist/{chunk-7OYIDM42.js → chunk-XKURJ72I.js} +2 -2
- package/dist/copy-button.cjs +439 -0
- package/dist/copy-button.cjs.map +1 -0
- package/dist/copy-button.d.cts +20 -0
- package/dist/copy-button.d.ts +20 -0
- package/dist/copy-button.js +12 -0
- package/dist/copy-button.js.map +1 -0
- package/dist/{dom-to-image-NATF3446.js → dom-to-image-QB7KMTAE.js} +3 -3
- package/dist/dom-to-image-QB7KMTAE.js.map +1 -0
- package/dist/icon.cjs +3 -1
- package/dist/icon.cjs.map +1 -1
- package/dist/icon.js +2 -2
- package/dist/index.cjs +1070 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.js +42 -17
- package/dist/keyboard-shortcut.cjs +3 -1
- package/dist/keyboard-shortcut.cjs.map +1 -1
- package/dist/keyboard-shortcut.js +2 -2
- package/dist/table.cjs +40 -0
- package/dist/table.cjs.map +1 -1
- package/dist/table.d.cts +37 -2
- package/dist/table.d.ts +37 -2
- package/dist/table.js +11 -1
- package/dist/text-area.cjs +3 -1
- package/dist/text-area.cjs.map +1 -1
- package/dist/text-area.js +2 -2
- package/dist/tokens.cjs +3 -1
- package/dist/tokens.cjs.map +1 -1
- package/dist/tokens.d.cts +1 -0
- package/dist/tokens.d.ts +1 -0
- package/dist/tokens.js +1 -1
- package/dist/{types-CW45GBXl.d.cts → types-Bhg0_ES8.d.cts} +75 -3
- package/dist/{types-GCkXbyFm.d.ts → types-C8JtnwNY.d.ts} +200 -4
- package/dist/{types-BzXPBy6s.d.cts → types-DTdDFU3O.d.cts} +200 -4
- package/dist/{types-D1b8v7EY.d.ts → types-orOQcI2z.d.ts} +75 -3
- package/package.json +11 -1
- package/dist/chunk-46ZYTBX5.js +0 -250
- package/dist/chunk-46ZYTBX5.js.map +0 -1
- package/dist/chunk-4MZZH3WX.js.map +0 -1
- package/dist/chunk-6YZ65KPW.js.map +0 -1
- package/dist/chunk-B6GAPZ2R.js.map +0 -1
- package/dist/chunk-RSRNSWJN.js +0 -1
- /package/dist/{chunk-RSRNSWJN.js.map → badge.js.map} +0 -0
- /package/dist/{chunk-JGMN6W72.js.map → chunk-2X4KUXYP.js.map} +0 -0
- /package/dist/{dom-to-image-NATF3446.js.map → chunk-BHHJOG5X.js.map} +0 -0
- /package/dist/{chunk-B4U37WIH.js.map → chunk-CFCLVJIO.js.map} +0 -0
- /package/dist/{chunk-PYDVANWI.js.map → chunk-E36VI2HA.js.map} +0 -0
- /package/dist/{chunk-PUVZ2S3F.js.map → chunk-G4NXVFXU.js.map} +0 -0
- /package/dist/{chunk-JAGNXEWK.js.map → chunk-GK4XW4BC.js.map} +0 -0
- /package/dist/{chunk-4VE6ZXXW.js.map → chunk-MQP57DOP.js.map} +0 -0
- /package/dist/{chunk-PGR2MDDU.js.map → chunk-W66OJM55.js.map} +0 -0
- /package/dist/{chunk-7OYIDM42.js.map → chunk-XKURJ72I.js.map} +0 -0
package/dist/capture.js
CHANGED
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
copyNodeAsPng,
|
|
3
3
|
downloadNodeAsPng,
|
|
4
4
|
nodeToPngBlob
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GK4XW4BC.js";
|
|
6
6
|
import {
|
|
7
7
|
CAPTURE_EXCLUDE_ATTRIBUTE
|
|
8
8
|
} from "./chunk-LXYCT4YO.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-SN3ORQSJ.js";
|
|
10
10
|
import "./chunk-5WRI5ZAA.js";
|
|
11
11
|
export {
|
|
12
12
|
CAPTURE_EXCLUDE_ATTRIBUTE,
|
package/dist/chart.cjs
CHANGED
package/dist/chart.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chart/index.ts","../src/components/chart/bar-chart/bar-chart.tsx","../src/components/chart/chart-container.tsx","../src/lib/utils.ts","../src/components/chart/chart-legend-content.tsx","../src/components/chart/chart-tooltip-content.tsx","../src/tokens/colors.ts","../src/components/chart/chart-palette.ts","../src/components/chart/chart-styles.ts","../src/components/chart/chart-tick-utils.ts","../src/components/chart/coerce-numeric.ts","../src/components/chart/line-chart/line-chart.tsx","../src/components/chart/pie-chart/pie-chart.tsx","../src/components/chart/pie-chart/utils.ts"],"sourcesContent":["/**\n * Public surface for `@shapesos/clay/chart`.\n *\n * Two layers:\n *\n * 1. **High-level components** — single-call convenience renderers with sensible defaults.\n * Use these for ~90% of cases:\n *\n * ```tsx\n * import { BarChart, LineChart, PieChart } from \"@shapesos/clay/chart\";\n *\n * <BarChart data={rows} xKey=\"month\" series={[...]} stacked />\n * <LineChart data={rows} xKey=\"month\" series={[...]} smooth />\n * <PieChart data={rows} categoryKey=\"dept\" valueKey=\"count\" />\n * ```\n *\n * 2. **Composable primitives** — for custom recharts trees (mixed-type charts, radar, scatter,\n * or anything the high-level components don't cover):\n *\n * ```tsx\n * import { ChartContainer, ChartTooltipContent, ChartLegendContent,\n * CHART_AXIS_PROPS, CHART_GRID_PROPS, CHART_PALETTE } from \"@shapesos/clay/chart\";\n * import { LineChart, Line, XAxis, YAxis, Tooltip, Legend, CartesianGrid } from \"recharts\";\n *\n * <ChartContainer height={320}>\n * <LineChart data={data}>\n * <CartesianGrid {...CHART_GRID_PROPS} />\n * <XAxis dataKey=\"month\" {...CHART_AXIS_PROPS} />\n * <YAxis {...CHART_AXIS_PROPS} />\n * <Tooltip content={<ChartTooltipContent />} />\n * <Legend content={<ChartLegendContent iconType=\"line\" />} />\n * <Line dataKey=\"value\" stroke={CHART_PALETTE[0]} />\n * </LineChart>\n * </ChartContainer>\n * ```\n *\n * **Required CSS** — consumers must import the compiled Tailwind bundle:\n *\n * import \"@shapesos/clay/blocks/styles.css\";\n *\n * (The stylesheet name is `blocks/styles.css` for historical reasons — it's the single bundle\n * that compiles all clay-side Tailwind output, including the chart components.)\n */\n\n// ── high-level components ─────────────────────────────────────────────────────────────────\nexport { BarChart } from \"./bar-chart/bar-chart\";\nexport type { BarChartProps } from \"./bar-chart/bar-chart\";\n\nexport { LineChart } from \"./line-chart/line-chart\";\nexport type { LineChartProps } from \"./line-chart/line-chart\";\n\nexport { PieChart } from \"./pie-chart/pie-chart\";\nexport type { PieChartProps } from \"./pie-chart/pie-chart\";\n\n// ── composable primitives ─────────────────────────────────────────────────────────────────\nexport { ChartContainer } from \"./chart-container\";\nexport type { ChartContainerProps } from \"./chart-container\";\n\nexport { ChartTooltipContent } from \"./chart-tooltip-content\";\nexport type { ChartTooltipContentProps } from \"./chart-tooltip-content\";\n\nexport { ChartLegendContent } from \"./chart-legend-content\";\nexport type { ChartLegendContentProps } from \"./chart-legend-content\";\n\n// ── shared types ──────────────────────────────────────────────────────────────────────────\nexport type { ChartSeries, ChartVariant } from \"./types\";\n\n// ── styling presets (spreadable into recharts primitives) ────────────────────────────────\n//\n// Only the two preset bundles are public — they're the documented composable surface for\n// custom chart trees. The raw color/margin constants behind them (`AXIS_STROKE`, `GRID_STROKE`,\n// `CHART_MARGIN`, etc.) stay internal to `chart-styles.ts`; promote them if a third-party\n// consumer ever needs a single constant without the preset bundle.\nexport { CHART_AXIS_PROPS, CHART_GRID_PROPS } from \"./chart-styles\";\n\n// ── palette + helpers ─────────────────────────────────────────────────────────────────────\n// CHART_PALETTE — shared blue + indigo graduated palette, default for every chart variant\n// (BarChart, LineChart, PieChart). One palette keeps adjacent charts on a dashboard reading\n// as a unified design system rather than three independently-themed components.\nexport { CHART_PALETTE, colorForSeriesIndex } from \"./chart-palette\";\nexport { coerceNumericColumns } from \"./coerce-numeric\";\n","import { type ReactNode, useMemo } from \"react\";\nimport { Bar, BarChart as RechartsBarChart, CartesianGrid, Legend, Tooltip, XAxis, YAxis } from \"recharts\";\n\nimport { ChartContainer } from \"../chart-container\";\nimport { ChartLegendContent } from \"../chart-legend-content\";\nimport { ChartTooltipContent } from \"../chart-tooltip-content\";\nimport { CHART_PALETTE, colorForSeriesIndex } from \"../chart-palette\";\nimport {\n BAR_TOOLTIP_CURSOR_FILL,\n CHART_AXIS_PROPS,\n CHART_GRID_PROPS,\n CHART_MARGIN,\n} from \"../chart-styles\";\nimport { compactNumberTickFormatter, defaultBarTickFormatter } from \"../chart-tick-utils\";\nimport { coerceNumericColumns } from \"../coerce-numeric\";\nimport type { ChartSeries } from \"../types\";\n\nexport interface BarChartProps {\n /** Rows to plot. Each row should carry the `xKey` column and one column per `series[].key`. */\n data: ReadonlyArray<Record<string, unknown>>;\n /** CSV/data column to use for the categorical x-axis (e.g. `\"month\"`, `\"quarter\"`). */\n xKey: string;\n /** One descriptor per bar series. Length 1 = single-series chart; 2+ = grouped or stacked. */\n series: ChartSeries[];\n /**\n * When true, all series stack on one stack-id (vertical sum). When false (default), bars\n * group side-by-side per x-tick.\n */\n stacked?: boolean;\n /** Container height. Number = px, string = any CSS length. Default 320. */\n height?: number | string;\n /** Container width. Default `\"100%\"`. */\n width?: number | string;\n /** Optional className on the outer container. */\n className?: string;\n /** Override the default palette (`CHART_PALETTE`). Colors are assigned by series index. */\n palette?: readonly string[];\n /** Show the tooltip on hover. Default true. */\n showTooltip?: boolean;\n /**\n * Show the legend at the top. **Default behavior**: auto-hidden for single-series charts\n * (the legend would just label the one and only color, which is noise). Pass `true` to force\n * the legend even with one series; pass `false` to suppress for multi-series.\n */\n showLegend?: boolean;\n /** Show horizontal dashed grid lines. Default true. */\n showGrid?: boolean;\n /** Show the x-axis. Default true. */\n showXAxis?: boolean;\n /** Show the y-axis. Default true. */\n showYAxis?: boolean;\n /**\n * Recharts XAxis tick `interval`. Default `0` — every category gets a label (no info loss\n * from auto-skipping). Use `\"preserveStartEnd\"` to let recharts drop colliding labels but\n * keep the first and last. For long category names, prefer `xAxisAngle` to rotate the labels\n * rather than dropping them.\n */\n xAxisInterval?: number | \"preserveStart\" | \"preserveEnd\" | \"preserveStartEnd\";\n /**\n * Rotate x-axis tick labels by this many degrees. **Default**: auto — `0` (horizontal) for\n * ≤7 categories; `-30` for 8+ categories so longer labels fit diagonally without overlapping\n * their neighbours. Pass `0` explicitly to force horizontal labels even at high counts; pass\n * any other number to set a custom angle.\n *\n * When the resolved angle is non-zero the chart auto-bumps its bottom margin and right-\n * anchors the labels so they don't run off the axis. The container `height` budget should\n * accommodate the angled labels (~40-60px more).\n */\n xAxisAngle?: number;\n /**\n * Custom formatter for x-axis tick labels. **Default**: clay auto-truncates labels based on\n * the number of categories so no labels overlap (see `getDefaultTickFormatter`). Pass an\n * explicit formatter to override — e.g. for word-boundary truncation, locale-aware\n * abbreviations, or to opt out of truncation entirely with `(v) => String(v)`.\n *\n * The tooltip continues to show the full unformatted value on hover regardless.\n */\n xAxisTickFormatter?: (value: unknown) => string;\n}\n\n/**\n * Pre-composed bar chart. Single-call usage for the common case; for custom recharts trees\n * compose `<ChartContainer>` + recharts primitives directly.\n *\n * ```tsx\n * <BarChart\n * data={[{ month: \"Jan\", us: 120, uk: 60 }, { month: \"Feb\", us: 132, uk: 64 }]}\n * xKey=\"month\"\n * series={[\n * { key: \"us\", label: \"US\" },\n * { key: \"uk\", label: \"UK\" },\n * ]}\n * stacked\n * />\n * ```\n *\n * **Smart defaults**: legend auto-hides for single-series charts; all x-axis ticks are shown\n * by default (no recharts auto-skip). Override any of these via the named props.\n *\n * Numeric coercion: `data` rows may carry string values for the series columns (e.g. when\n * derived from CSV) — recharts needs numbers, so we coerce in-place. Already-numeric data\n * passes through unchanged.\n */\nexport function BarChart({\n data,\n xKey,\n series,\n stacked = false,\n height = 320,\n width = \"100%\",\n className,\n palette = CHART_PALETTE,\n showTooltip = true,\n showLegend,\n showGrid = true,\n showXAxis = true,\n showYAxis = true,\n xAxisInterval = 0,\n xAxisAngle,\n xAxisTickFormatter,\n}: BarChartProps): ReactNode {\n const seriesKeys = useMemo(() => series.map((s) => s.key), [series]);\n // Memoised so non-artifact consumers passing inline `data` arrays don't re-allocate the\n // coerced copy on every parent render. For the artifact path `data` is already stable from\n // `useRowsArtifactData`, so this is a no-op there.\n const coercedData = useMemo(\n () => coerceNumericColumns(data as ReadonlyArray<Record<string, unknown>>, seriesKeys),\n [data, seriesKeys]\n );\n\n // Smart defaults — see prop JSDoc for rationale.\n const resolvedShowLegend = showLegend ?? series.length > 1;\n // Auto-angle for dense bar charts: at 8+ categories the horizontal slot per label is too\n // narrow for full-text labels to fit. Rotating to -30° lets labels extend diagonally below\n // the axis without overlapping their neighbours. Consumer can override with `xAxisAngle={0}`.\n const resolvedAngle = xAxisAngle ?? (coercedData.length >= 8 ? -30 : 0);\n // Auto-truncating tick formatter — keeps every bar labeled while preventing overlap. The\n // tooltip shows the full unformatted value on hover, so no information is lost. Consumer\n // can opt out with `(v) => String(v)`.\n const resolvedTickFormatter = useMemo(\n () => xAxisTickFormatter ?? defaultBarTickFormatter(coercedData.length),\n [xAxisTickFormatter, coercedData.length]\n );\n\n // Angled labels need extra bottom margin so they don't clip the chart. ~0.7px per degree\n // covers up to -45° comfortably; we cap to avoid runaway when callers pass aggressive angles.\n const angledLabelPad = resolvedAngle === 0 ? 0 : Math.min(Math.abs(resolvedAngle) * 0.7, 40);\n const chartMargin = { ...CHART_MARGIN, bottom: CHART_MARGIN.bottom + angledLabelPad };\n\n return (\n <ChartContainer height={height} width={width} className={className}>\n <RechartsBarChart data={coercedData} margin={chartMargin} barCategoryGap=\"22%\">\n {showGrid ? <CartesianGrid {...CHART_GRID_PROPS} /> : null}\n {showXAxis ? (\n <XAxis\n dataKey={xKey}\n {...CHART_AXIS_PROPS}\n interval={xAxisInterval}\n angle={resolvedAngle}\n // Right-anchor angled labels so the end of each label aligns with its tick, rather\n // than the centre running off the axis. Middle-anchor for horizontal labels.\n textAnchor={resolvedAngle !== 0 ? \"end\" : \"middle\"}\n tickMargin={resolvedAngle === 0 ? 8 : 12}\n height={resolvedAngle !== 0 ? 60 : undefined}\n tickFormatter={resolvedTickFormatter}\n />\n ) : null}\n {showYAxis ? <YAxis {...CHART_AXIS_PROPS} width={40} tickFormatter={compactNumberTickFormatter} /> : null}\n {showTooltip ? <Tooltip cursor={{ fill: BAR_TOOLTIP_CURSOR_FILL }} content={<ChartTooltipContent />} /> : null}\n {resolvedShowLegend ? (\n <Legend\n verticalAlign=\"top\"\n align=\"center\"\n // Pin the absolutely-positioned wrapper flush to the chart's top edge. Recharts'\n // default `top` for a top-aligned legend leaves a gap above the swatches; we'd\n // rather let `CHART_MARGIN.top` control the breathing room below the legend.\n wrapperStyle={{ top: 0 }}\n // Recharts 3.x defaults `itemSorter` to `'value'`, which alphabetically sorts legend\n // entries by label. The tooltip, the stack, and our chart's series colours all follow\n // declaration order — sorting the legend silently breaks correspondence (an \"Others\"\n // series declared last ends up mid-legend alphabetically). `null` disables the sort.\n itemSorter={null}\n content={<ChartLegendContent iconType=\"square\" />}\n />\n ) : null}\n {series.map((s, i) => (\n <Bar\n key={s.key}\n dataKey={s.key}\n name={s.label}\n fill={colorForSeriesIndex(i, palette)}\n stackId={stacked ? \"default\" : s.key}\n radius={barRadius(stacked, i, series.length)}\n />\n ))}\n </RechartsBarChart>\n </ChartContainer>\n );\n}\n\n/**\n * Per-corner border radius for a bar at position `seriesIndex` in `seriesCount` total series.\n *\n * - **Grouped (non-stacked)** — every series rounded at the top (`[6, 6, 0, 0]`). Bottom sits\n * on the X-axis, so flat bottom looks correct.\n * - **Stacked** — only the top-most segment gets `[6, 6, 0, 0]`; bottom + middle segments are\n * squared so the rect joins look seamless. Bottom segment is flat too because the chart's\n * X-axis is its base.\n */\nfunction barRadius(stacked: boolean, seriesIndex: number, seriesCount: number): [number, number, number, number] {\n if (!stacked) return [6, 6, 0, 0];\n const isTopSegment = seriesIndex === seriesCount - 1;\n return isTopSegment ? [6, 6, 0, 0] : [0, 0, 0, 0];\n}\n","import { type CSSProperties, type ReactElement, type ReactNode } from \"react\";\nimport { ResponsiveContainer } from \"recharts\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface ChartContainerProps {\n /** A single recharts chart element — `<LineChart>`, `<BarChart>`, `<PieChart>`, etc. */\n children: ReactElement;\n /**\n * Container height. Recharts' `ResponsiveContainer` measures its parent, so we need a\n * concrete value here (not \"auto\"). Accepts a number (px) or any CSS length string.\n * Defaults to `320` — a sensible mid-density chart height.\n */\n height?: number | string;\n /**\n * Container width. Defaults to `\"100%\"` so the chart flexes to its parent. Pass a fixed\n * number when embedding in a layout that doesn't have a definite width (e.g. an auto-sized\n * flex column).\n */\n width?: number | string;\n /** Optional className spread on the outer wrapper. */\n className?: string;\n /** Optional inline style merged into the outer wrapper. `width`/`height` here take precedence. */\n style?: CSSProperties;\n}\n\n/**\n * The composable foundation for every clay chart. Wraps recharts' `ResponsiveContainer` in a\n * sized `<div>` so the chart has a definite parent box to measure against — without this, charts\n * silently collapse to 0×0 inside flex containers (see the `flex-basis` gotcha documented in\n * the chart-artifact orchestrator).\n *\n * Use directly when composing a chart from recharts primitives:\n *\n * ```tsx\n * <ChartContainer height={320}>\n * <LineChart data={data} margin={{ top: 8, right: 16, left: 0, bottom: 4 }}>\n * <CartesianGrid {...CHART_GRID_PROPS} />\n * <XAxis dataKey=\"month\" {...CHART_AXIS_PROPS} />\n * <YAxis {...CHART_AXIS_PROPS} />\n * <Tooltip content={<ChartTooltipContent />} />\n * <Legend content={<ChartLegendContent />} />\n * <Line dataKey=\"value\" stroke={CHART_PALETTE[0]} />\n * </LineChart>\n * </ChartContainer>\n * ```\n *\n * For common shapes, prefer the pre-composed `<BarChart>` / `<LineChart>` / `<PieChart>` —\n * they call `ChartContainer` under the hood with sensible defaults.\n */\nexport function ChartContainer({\n children,\n height = 320,\n width = \"100%\",\n className,\n style,\n}: ChartContainerProps): ReactNode {\n return (\n <div className={cn(\"text-xs text-foreground\", className)} style={{ width, height, ...style }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n {children}\n </ResponsiveContainer>\n </div>\n );\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Combines class names using clsx and tailwind-merge — the standard shadcn/ui helper.\n * Tailwind classes that conflict (e.g. `p-2 p-4`) get merged so the last one wins.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { type ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Single entry in recharts' legend payload — one per series. Typed locally because recharts'\n * `LegendProps['payload']` is overly tagged-generic.\n */\ninterface LegendPayloadEntry {\n value?: string | number;\n color?: string;\n dataKey?: string | number;\n type?: string;\n}\n\n/**\n * Recharts injects `payload` at runtime when this component is used as the `content` slot on\n * `<Legend>`. Consumer-facing props (`className`, `iconType`) survive the cloneElement merge.\n */\nexport interface ChartLegendContentProps {\n /** Set by recharts at runtime — one entry per series. */\n payload?: LegendPayloadEntry[];\n /** Optional className merged onto the legend list. */\n className?: string;\n /** Visual indicator next to each label. `square` for bars/pies; `line` for line/area. Default `square`. */\n iconType?: \"square\" | \"line\";\n}\n\n/**\n * The default legend body for clay charts. Drop into any recharts `<Legend>`:\n *\n * ```tsx\n * <Legend content={<ChartLegendContent iconType=\"square\" />} />\n * <Legend content={<ChartLegendContent iconType=\"line\" />} />\n * ```\n *\n * Recharts also accepts `verticalAlign` / `align` on `<Legend>` itself for positioning —\n * `<ChartLegendContent>` is just the body. Style stays consistent regardless of position.\n */\nexport function ChartLegendContent({ payload, className, iconType = \"square\" }: ChartLegendContentProps): ReactNode {\n if (!payload || payload.length === 0) return null;\n\n return (\n <ul\n // No padding on this `<ul>`. Recharts wraps it in a `.recharts-legend-wrapper` div that's\n // positioned `absolute` with an inline `top` — padding here doesn't shift the wrapper's\n // anchor point, it only inflates the wrapper's height. The \"gap above the legend\" must be\n // controlled by the wrapper's inline `top`, set via each chart's `<Legend wrapperStyle>`.\n className={cn(\"flex flex-wrap items-center justify-center gap-x-4 gap-y-2 text-xs text-brown-80\", className)}\n >\n {payload.map((entry: LegendPayloadEntry, i: number) => {\n const swatchColor = typeof entry.color === \"string\" ? entry.color : \"transparent\";\n const label = entry.value !== undefined ? String(entry.value) : \"\";\n return (\n <li key={`${label}-${i}`} className=\"flex items-center gap-1.5\">\n {iconType === \"square\" ? (\n <span className=\"inline-block h-2.5 w-2.5 shrink-0 rounded-sm\" style={{ background: swatchColor }} />\n ) : (\n <span className=\"inline-block h-[3px] w-4 shrink-0 rounded-full\" style={{ background: swatchColor }} />\n )}\n <span>{label}</span>\n </li>\n );\n })}\n </ul>\n );\n}\n","import { type ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Single entry in recharts' tooltip payload — one per series at the hovered x-tick.\n * Typed locally because recharts' `TooltipProps['payload']` is overly tagged-generic for this use.\n */\ninterface TooltipPayloadEntry {\n name?: string | number;\n value?: number | string;\n color?: string;\n dataKey?: string | number;\n}\n\n/**\n * Recharts injects `active`, `payload`, and `label` at runtime when this component is used as\n * the `content` slot on `<Tooltip>`. Consumer-facing props (`className`, `showLabel`,\n * `formatValue`) survive the cloneElement merge.\n */\nexport interface ChartTooltipContentProps {\n /** Set by recharts at runtime — true when the tooltip is hovered open. */\n active?: boolean;\n /** Set by recharts at runtime — one entry per series. */\n payload?: TooltipPayloadEntry[];\n /** Set by recharts at runtime — the x-tick label for the hovered column. */\n label?: string | number;\n /** Optional className merged onto the tooltip card. */\n className?: string;\n /** When false, the row label (typically the x-tick value) is hidden. Default true. */\n showLabel?: boolean;\n /** Override the formatter used on each entry's value. Defaults to `String(value)`. */\n formatValue?: (value: number | string | undefined, name: string | undefined) => string;\n}\n\n/**\n * The default tooltip card for clay charts. Drop into any recharts `<Tooltip>`:\n *\n * ```tsx\n * <Tooltip content={<ChartTooltipContent />} />\n * <Tooltip content={<ChartTooltipContent formatValue={(v) => `$${v}`} />} />\n * ```\n *\n * Renders a soft brown card with one row per series, swatch left, name center, value right.\n * Returns `null` when recharts says the tooltip is inactive — recharts mounts the content\n * component unconditionally and toggles it via the `active` prop.\n */\nexport function ChartTooltipContent({\n active,\n payload,\n label,\n className,\n showLabel = true,\n formatValue,\n}: ChartTooltipContentProps): ReactNode {\n if (!active || !payload || payload.length === 0) return null;\n\n return (\n <div\n className={cn(\n \"rounded-lg border border-brown-40 bg-brown-10 px-3 py-2 text-xs shadow-sm\",\n \"min-w-32 text-foreground\",\n className\n )}\n >\n {showLabel && label !== undefined && label !== null ? (\n <div className=\"mb-1.5 font-medium text-brown-90\">{String(label)}</div>\n ) : null}\n <ul className=\"space-y-1\">\n {payload.map((entry: TooltipPayloadEntry, i: number) => {\n const name = entry.name !== undefined ? String(entry.name) : \"\";\n const rawValue = entry.value;\n const display = formatValue ? formatValue(rawValue, name) : rawValue === undefined ? \"\" : String(rawValue);\n const swatch = typeof entry.color === \"string\" ? entry.color : \"transparent\";\n return (\n <li key={`${name}-${i}`} className=\"flex items-center gap-2\">\n <span className=\"inline-block h-2.5 w-2.5 shrink-0 rounded-sm\" style={{ background: swatch }} />\n <span className=\"text-brown-70\">{name}</span>\n <span className=\"ml-auto font-semibold tabular-nums text-brown-90\">{display}</span>\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n","export const colors = {\n // White\n white: \"#FFFFFF\",\n \"white-alpha-85\": \"rgba(255, 255, 255, 0.85)\",\n \"white-alpha-40\": \"rgba(255, 255, 255, 0.40)\",\n\n // Brown\n \"brown-10\": \"#FAF9F8\",\n \"brown-20\": \"#F5F3F0\",\n \"brown-30\": \"#EEEBE5\",\n \"brown-40\": \"#E6E2DA\",\n \"brown-50\": \"#CFCBC4\",\n \"brown-60\": \"#A19E99\",\n \"brown-70\": \"#73716D\",\n \"brown-80\": \"#5C5A57\",\n \"brown-90\": \"#2E2D2C\",\n \"brown-100\": \"#171716\",\n \"brown-alpha-12\": \"rgba(23, 23, 22, 0.12)\",\n \"brown-alpha-20\": \"rgba(23, 23, 22, 0.20)\",\n \"brown-alpha-55\": \"rgba(23, 23, 22, 0.55)\",\n \"brown-alpha-70\": \"rgba(23, 23, 22, 0.70)\",\n \"brown-alpha-80\": \"rgba(23, 23, 22, 0.80)\",\n \"brown-alpha-90\": \"rgba(23, 23, 22, 0.90)\",\n\n // Fuchsia\n \"fuchsia-50\": \"#FAF5FF\",\n \"fuchsia-300\": \"#F0ABFC\",\n \"fuchsia-500\": \"#D946EF\",\n \"fuchsia-600\": \"#C026D3\",\n \"fuchsia-800\": \"#86198F\",\n\n // Pink\n \"pink-50\": \"#FDF2F8\",\n \"pink-400\": \"#F472B6\",\n \"pink-600\": \"#DB2777\",\n \"pink-800\": \"#9D174D\",\n\n // Violet\n \"violet-50\": \"#F5F3FF\",\n \"violet-400\": \"#A78BFA\",\n \"violet-600\": \"#7C3AED\",\n \"violet-800\": \"#5B21B6\",\n\n // Indigo\n \"indigo-50\": \"#EEF2FF\",\n \"indigo-400\": \"#818CF8\",\n \"indigo-500\": \"#6366F1\",\n \"indigo-600\": \"#4F46E5\",\n \"indigo-800\": \"#3730A3\",\n\n // Cyan\n \"cyan-50\": \"#E7FEFF\",\n \"cyan-300\": \"#67E8F9\",\n \"cyan-600\": \"#0891B2\",\n \"cyan-900\": \"#164E63\",\n\n // Teal\n \"teal-50\": \"#EBFDF9\",\n \"teal-300\": \"#5EEAD4\",\n \"teal-600\": \"#0D9488\",\n\n // Rose\n \"rose-400\": \"#FB7185\",\n\n // Purple\n \"purple-400\": \"#C084FC\",\n\n // Blue\n \"blue-50\": \"#EFF6FF\",\n \"blue-100\": \"#DBEAFE\",\n \"blue-300\": \"#93C5FD\",\n \"blue-400\": \"#60A5FA\",\n \"blue-600\": \"#2563EB\",\n \"blue-800\": \"#1E40AF\",\n\n // Sky\n \"sky-300\": \"#7DD3FC\",\n\n // Green\n \"green-50\": \"#ECF9F0\",\n \"green-100\": \"#D4F1D9\",\n \"green-400\": \"#3DC269\",\n \"green-700\": \"#277C43\",\n \"green-800\": \"#1C5930\",\n\n // Orange\n \"orange-50\": \"#FFF7ED\",\n \"orange-100\": \"#FFEDD5\",\n \"orange-200\": \"#FED7AA\",\n \"orange-500\": \"#F97316\",\n \"orange-600\": \"#EA580C\",\n\n // Red\n \"red-50\": \"#FEF2F2\",\n \"red-100\": \"#FEE2E2\",\n \"red-200\": \"#FECACA\",\n \"red-400\": \"#F7776C\",\n \"red-500\": \"#EF4444\",\n \"red-600\": \"#DC2626\",\n} as const;\n\nexport type ColorToken = keyof typeof colors;\n","import { colors } from \"@/tokens\";\n\n/**\n * Single ordered color palette shared by every chart variant (`BarChart`, `LineChart`,\n * `PieChart`). A graduated walk down the blue family (`blue-600` → `blue-400` → `blue-300` →\n * `blue-100`), pivot into the indigo family (`indigo-400` → `indigo-500` → `indigo-600` →\n * `indigo-800`), and close on the deepest blue (`blue-800`).\n *\n * Design intent: every chart in the product sits in the same cool blue / indigo family so\n * adjacent charts on a dashboard read as a unified system rather than a kaleidoscope. The\n * deliberately narrow hue range (blue + indigo only — no warm accents) is the point: it\n * forecloses on rainbow-coded multi-series charts where the visual noise outweighs the\n * series-distinction it tries to provide.\n *\n * **Same palette for pie too**: pie slices read as parts of a whole, but they also share a\n * dashboard with bar/line charts — keeping one palette across every variant means a single\n * chat surface containing all three variants looks like one design system, not three.\n *\n * Nine entries — the v1 series cap. The palette cycles modulo its length for series counts\n * past nine via `colorForSeriesIndex`.\n */\nexport const CHART_PALETTE = [\n colors[\"blue-600\"], // #2563EB — primary\n colors[\"blue-400\"], // #60A5FA — mid\n colors[\"blue-300\"], // #93C5FD — light\n colors[\"blue-100\"], // #DBEAFE — very light\n colors[\"indigo-400\"], // #818CF8\n colors[\"indigo-500\"], // #6366F1\n colors[\"indigo-600\"], // #4F46E5\n colors[\"indigo-800\"], // #3730A3\n colors[\"blue-800\"], // #1E40AF — deepest\n] as const;\n\n/**\n * Slice color reserved for the \"Others\" bucket in pie charts. Neutral warm grey so it reads as\n * \"leftover / unattributed\" rather than a peer category. Pinning to a constant (rather than the\n * tail of `CHART_PALETTE`) means an Others slice always renders identically regardless of how\n * many named categories the data carries before it.\n */\nexport const OTHERS_SLICE_COLOR = colors[\"brown-60\"];\n\n/**\n * English fallback labels treated as the \"Others\" bucket — case-insensitive match.\n *\n * Consumers should pass their own localized list to `<PieChart>` via the `othersCategoryLabels`\n * prop (or via the artifact's `labels.othersCategoryLabels`) — in non-English UIs the agent\n * writes a translated bucket name (e.g. \"אחרים\", \"Otros\", \"Anderen\") and the consumer's i18n\n * layer is the only place that knows which strings to map to grey/last.\n */\nexport const DEFAULT_OTHERS_CATEGORY_LABELS: readonly string[] = [\"others\", \"other\"];\n\n/**\n * Category values that read as \"missing\" rather than a real category — `null`, `undefined`,\n * empty string, and the common placeholder strings a data source emits for an absent value\n * (e.g. a null employee gender surfacing as the literal `\"(none)\"`). Matched case-insensitively\n * after trimming. Folded into the grey \"Others\" bucket by `<PieChart>` so a missing-value slice\n * reads as \"unattributed leftover\" instead of a peer category in the palette.\n */\n// Deliberately excludes bare \"na\" — it collides with real category abbreviations like \"NA\"\n// (North America / Namibia). \"n/a\" (with the slash) is unambiguous and kept.\nconst NONE_CATEGORY_VALUES: readonly string[] = [\"\", \"(none)\", \"none\", \"null\", \"undefined\", \"n/a\", \"-\"];\n\n/**\n * True when `value` represents a missing/empty category (see `NONE_CATEGORY_VALUES`). `null` and\n * `undefined` always count; non-empty real category names never do.\n */\nexport function isNoneCategory(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n return NONE_CATEGORY_VALUES.includes(String(value).trim().toLowerCase());\n}\n\n/**\n * True when `value` matches one of `labels` (case-insensitive, trims whitespace). `labels` is\n * required — consumers pass either `DEFAULT_OTHERS_CATEGORY_LABELS` (English fallback) or their\n * own translated list. Pass an empty array to disable Others detection entirely.\n */\nexport function isOthersCategory(value: unknown, labels: readonly string[]): boolean {\n if (value === null || value === undefined) return false;\n if (labels.length === 0) return false;\n const normalized = String(value).trim().toLowerCase();\n for (const label of labels) {\n if (normalized === label.toLowerCase()) return true;\n }\n return false;\n}\n\n/**\n * Resolves the color for a series at `index`. Cycles deterministically past the palette length\n * so configurations with more series than colors still render rather than throwing. Pass an\n * alternate `palette` (e.g. a brand-specific override) to use something other than the default\n * `CHART_PALETTE`.\n */\nexport function colorForSeriesIndex(index: number, palette: readonly string[] = CHART_PALETTE): string {\n return palette[index % palette.length] ?? CHART_PALETTE[0];\n}\n","import { colors } from \"@/tokens\";\n\n/**\n * Shared visual constants for every chart variant. Two flavours of export:\n *\n * 1. Raw constants (`GRID_STROKE`, `AXIS_STROKE`, …) — for one-off uses or custom recharts trees.\n * 2. Preset prop bundles (`CHART_AXIS_PROPS`, `CHART_GRID_PROPS`) — spreadable into recharts\n * primitives so consumers can build composable charts without restating defaults:\n *\n * ```tsx\n * <CartesianGrid {...CHART_GRID_PROPS} />\n * <XAxis dataKey=\"x\" {...CHART_AXIS_PROPS} tickMargin={8} />\n * ```\n *\n * Recharts primitives must be inlined inside the chart tree — recharts identifies its slot\n * children by component reference (`child.type === XAxis`), so wrapping them in a custom React\n * component breaks dispatch. Constants and preset props are the right shape to share.\n */\n\n// ── raw color constants ──────────────────────────────────────────────────────────────────────\n\n/** Horizontal grid line color — kept soft so the data dominates the visual hierarchy. */\nexport const GRID_STROKE = colors[\"brown-40\"];\n\n/** Axis-line + axis-tick color. Lighter than the tick text so the axis frames rather than competes. */\nexport const AXIS_STROKE = colors[\"brown-50\"];\n\n/** Axis tick label text style. */\nexport const AXIS_TICK_STYLE = {\n fill: colors[\"brown-70\"],\n fontSize: 12,\n fontWeight: 500,\n} as const;\n\n/**\n * Text style for data-point value labels — bars (`<LabelList position=\"top\">`), line\n * data-point labels, and pie slice value labels all use this so labels read as one visual\n * family regardless of chart variant. Matches `AXIS_TICK_STYLE` for color/weight/size so\n * every secondary text element in a chart sits at the same hierarchy level.\n */\nexport const CHART_VALUE_LABEL_STYLE = {\n fill: colors[\"brown-70\"],\n fontSize: 12,\n fontWeight: 500,\n} as const;\n\n/** Cursor (hover guide) fill for bar tooltips. */\nexport const BAR_TOOLTIP_CURSOR_FILL = colors[\"brown-alpha-12\"];\n\n/** Active-dot ring fill on hovered line points — matches the chart background so the dot reads raised. */\nexport const LINE_ACTIVE_DOT_STROKE = colors[\"brown-10\"];\n\n/** Default recharts margin — leaves room for axis ticks/labels and the bottom legend. */\nexport const CHART_MARGIN = { top: 8, right: 16, left: 0, bottom: 4 } as const;\n\n/** Pie-specific margin — extra horizontal room to absorb outside slice labels. */\nexport const PIE_CHART_MARGIN = { top: 0, right: 24, left: 24, bottom: 4 } as const;\n\n// ── preset prop bundles ──────────────────────────────────────────────────────────────────────\n\n/**\n * Spreadable defaults for `<XAxis>` and `<YAxis>` — no axis line, no tick line, soft brown ticks.\n * Pass `dataKey` explicitly on `<XAxis>`; leave it off `<YAxis>`. Override anything per-instance.\n */\nexport const CHART_AXIS_PROPS = {\n stroke: AXIS_STROKE,\n tick: AXIS_TICK_STYLE,\n tickLine: false,\n axisLine: false,\n} as const;\n\n/**\n * Spreadable defaults for `<CartesianGrid>` — horizontal dashed lines only.\n */\nexport const CHART_GRID_PROPS = {\n stroke: GRID_STROKE,\n strokeDasharray: \"3 3\",\n vertical: false,\n} as const;\n","/**\n * Shared x-axis tick helpers used by both `BarChart` and `LineChart`. Pulled into one module so\n * the truncation thresholds and the truncation algorithm itself stay in one place — otherwise\n * each variant evolves its own slightly-different heuristic and the charts read inconsistently\n * side-by-side.\n *\n * Bar uses `defaultBarTickFormatter` (label per category, truncated when dense).\n * Line uses `defaultLineChartTickFormatter` (label only at evenly-distributed indices).\n * Both share the `maxTickCharsByCategoryCount` ladder and the `truncateLabel` ellipsis logic.\n */\n\n/**\n * Max characters per x-axis tick label, keyed by category count. The thresholds approximate the\n * available pixel slot per tick on a typical chat-card-width chart (~700px plot area) at the\n * default 12px tick font size. Sparse charts get no truncation; dense charts get aggressive\n * trimming so labels stop overlapping.\n *\n * Consumers can override the entire formatting via `xAxisTickFormatter` on either chart.\n */\nexport function maxTickCharsByCategoryCount(n: number): number {\n if (n <= 5) return 24; // effectively no truncation\n if (n <= 8) return 14;\n if (n <= 12) return 10;\n if (n <= 16) return 7;\n return 5;\n}\n\n/**\n * Truncates one label per the per-count cap. Trailing whitespace before the ellipsis is trimmed\n * so \"Human Resources\" with cap=7 becomes \"Human…\" not \"Human …\" (reads cleaner).\n */\nexport function truncateLabel(value: unknown, maxChars: number): string {\n const s = String(value ?? \"\");\n if (s.length <= maxChars) return s;\n return s.slice(0, Math.max(1, maxChars - 1)).trimEnd() + \"…\";\n}\n\n/**\n * Compact number format for y-axis ticks — `15000` → `15K`, `1500000` → `1.5M`. Keeps long\n * numeric tick labels inside the fixed `YAxis` width slot (~40px) so they stop clipping to\n * their trailing digits (\"15000\" rendering as \"0000\"). One shared instance so every chart\n * abbreviates identically. The tooltip still shows the full unformatted value on hover.\n *\n * Assumes axis values are integer-magnitude (≥ 1) — the use cases today are headcounts and\n * currency amounts. `maximumFractionDigits: 1` means sub-1 values round coarsely (`0.123` → `0.1`,\n * `0.005` → `0`), so this default is unsuitable for charts plotting rates / proportions in (0, 1).\n * Such a chart needs a dedicated formatter (a y-axis formatter prop is a planned follow-up).\n */\nconst compactNumberFormat = new Intl.NumberFormat(\"en-US\", { notation: \"compact\", maximumFractionDigits: 1 });\n\n/**\n * Default `tickFormatter` for numeric y-axes on `BarChart` / `LineChart`. Abbreviates large\n * magnitudes (thousands → `K`, millions → `M`) so labels fit the axis gutter. Non-numeric or\n * non-finite values pass through as their string form unchanged.\n */\nexport function compactNumberTickFormatter(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n const n = typeof value === \"number\" ? value : Number(value);\n if (!Number.isFinite(n)) return String(value);\n return compactNumberFormat.format(n);\n}\n\n/**\n * Returns the set of data-point indices whose label should be visible. First and last always\n * included; the remaining (target - 2) are evenly distributed across the interior. Avoids the\n * \"cluster in the middle\" failure mode of recharts' built-in `preserveStartEnd`.\n *\n * Example for N=12, target=5: visible indices are {0, 3, 5, 8, 11} — 5 evenly-spaced labels.\n * Used by `LineChart` to thin x-axis labels at high data-point counts while keeping every data\n * point drawn.\n */\nexport function evenlyDistributedVisibleIndices(n: number, target: number): Set<number> {\n if (n <= target) {\n return new Set(Array.from({ length: n }, (_, i) => i));\n }\n const set = new Set<number>();\n const step = (n - 1) / (target - 1);\n for (let i = 0; i < target; i++) {\n set.add(Math.round(i * step));\n }\n return set;\n}\n\n/**\n * Per-category truncating formatter used as `BarChart`'s default `tickFormatter`. Every category\n * gets a label (no info loss from auto-skipping) but long labels get truncated by the\n * `maxTickCharsByCategoryCount` ladder so dense charts don't overlap.\n */\nexport function defaultBarTickFormatter(categoryCount: number): (value: unknown) => string {\n const max = maxTickCharsByCategoryCount(categoryCount);\n return (value) => truncateLabel(value, max);\n}\n\n/**\n * Per-index truncating formatter used as `LineChart`'s default `tickFormatter`. Returns the\n * (truncated) label only for indices in `visibleIndices`; the rest return `\"\"` so recharts\n * renders no text there. The data point itself still draws.\n *\n * Truncation is keyed by the *visible* tick count, not the total data-point count: LINE thins\n * its labels via `visibleIndices` (typically 5-7 visible ticks even at N=100+ data points), so\n * each rendered label has plenty of pixel room. Using `categoryCount` here would cap labels\n * like \"Dec 2022\" to 5 characters on a 50-month chart and clip them to \"Dec…\" even though only\n * ~5 ticks actually render. `BarChart` keeps using `categoryCount` because every category gets\n * a tick there — density really is data-point count.\n */\nexport function defaultLineChartTickFormatter(\n categoryCount: number,\n visibleIndices: Set<number>\n): (value: unknown, index: number) => string {\n const max = maxTickCharsByCategoryCount(visibleIndices.size || categoryCount);\n return (value, index) => {\n if (!visibleIndices.has(index)) return \"\";\n return truncateLabel(value, max);\n };\n}\n","/**\n * Returns a shallow copy of `rows` with the `numericKeys` columns coerced to `number`.\n * Cells that can't be parsed become `NaN`; `null` / `undefined` cells pass through untouched;\n * columns NOT in `numericKeys` pass through unchanged.\n *\n * Recharts needs `number` on `dataKey` resolution for `<Line>` / `<Bar>` / `<Pie>` — already-\n * numeric data is a no-op. The function exists for the CSV-derived case where values arrive\n * as strings. `NaN` propagates to recharts as a missing data point (zero-height bar, gap in\n * line, zero-area slice).\n */\nexport function coerceNumericColumns(\n rows: ReadonlyArray<Record<string, unknown>>,\n numericKeys: ReadonlyArray<string>\n): Array<Record<string, unknown>> {\n return rows.map((row) => {\n const out: Record<string, unknown> = { ...row };\n for (const k of numericKeys) {\n const v = out[k];\n if (v == null) continue;\n const n = Number(v);\n out[k] = Number.isFinite(n) ? n : NaN;\n }\n return out;\n });\n}\n","import { type ReactNode, useMemo } from \"react\";\nimport {\n CartesianGrid,\n LabelList,\n Legend,\n Line,\n LineChart as RechartsLineChart,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\n\nimport { ChartContainer } from \"../chart-container\";\nimport { ChartLegendContent } from \"../chart-legend-content\";\nimport { ChartTooltipContent } from \"../chart-tooltip-content\";\nimport { CHART_PALETTE, colorForSeriesIndex } from \"../chart-palette\";\nimport {\n CHART_AXIS_PROPS,\n CHART_GRID_PROPS,\n CHART_MARGIN,\n CHART_VALUE_LABEL_STYLE,\n LINE_ACTIVE_DOT_STROKE,\n} from \"../chart-styles\";\nimport {\n compactNumberTickFormatter,\n defaultLineChartTickFormatter,\n evenlyDistributedVisibleIndices,\n} from \"../chart-tick-utils\";\nimport { coerceNumericColumns } from \"../coerce-numeric\";\nimport type { ChartSeries } from \"../types\";\n\nexport interface LineChartProps {\n /** Rows to plot. Each row should carry the `xKey` column and one column per `series[].key`. */\n data: ReadonlyArray<Record<string, unknown>>;\n /** Data column for the categorical/temporal x-axis. */\n xKey: string;\n /** One descriptor per line series. */\n series: ChartSeries[];\n /** Render monotone-curve lines instead of straight segments. **Default true** — smooth\n * curves look cleaner for typical chat / dashboard usage. Pass `false` for true linear\n * interpolation (e.g. step-like data where the literal value at each point matters). */\n smooth?: boolean;\n /** Show data-point dots. **Default true** — dots anchor each bin of the line so the viewer\n * can read individual values at a glance. Pass `false` for a pure trend line (dense data sets\n * where dots would crowd, or styling preference for unembellished strokes). */\n showDots?: boolean;\n /** Line stroke width in px. Default 2. */\n strokeWidth?: number;\n /** Container height. Default 320. */\n height?: number | string;\n /** Container width. Default `\"100%\"`. */\n width?: number | string;\n /** Optional className on the outer container. */\n className?: string;\n /** Override the default palette. Colors are assigned by series index. */\n palette?: readonly string[];\n /** Show the tooltip on hover. Default true. */\n showTooltip?: boolean;\n /**\n * Show the legend at the top. **Default behavior**: auto-hidden for single-series charts\n * (the legend would just label the one and only color, which is noise). Pass `true` to force\n * the legend even with one series; pass `false` to suppress for multi-series.\n */\n showLegend?: boolean;\n /** Show horizontal dashed grid lines. Default true. */\n showGrid?: boolean;\n /** Show the x-axis. Default true. */\n showXAxis?: boolean;\n /** Show the y-axis. Default true. */\n showYAxis?: boolean;\n /**\n * Show numeric value labels next to each data point. **Default off** — for line charts with\n * many data points (12+ months × N series) labels overlap quickly. Set `true` for single-series\n * charts with sparse data (e.g. ≤8 points) where the labels stay readable.\n */\n showValueLabels?: boolean;\n /**\n * Recharts XAxis tick `interval`. **Default**: `0` (every tick rendered) — clay's tick\n * formatter blanks out non-key labels so the visible labels stay evenly distributed.\n * Override to a fixed number to force \"every Nth label\", or to a recharts string preset\n * like `\"preserveStartEnd\"` to let recharts pick.\n */\n xAxisInterval?: number | \"preserveStart\" | \"preserveEnd\" | \"preserveStartEnd\";\n /**\n * Rotate x-axis tick labels by this many degrees. Negative values tilt up-and-right (e.g.\n * `-30`). Default `0`. When non-zero, the chart auto-bumps its bottom margin.\n */\n xAxisAngle?: number;\n /**\n * Custom formatter for x-axis tick labels. **Default**: clay shows only ~5 evenly-distributed\n * labels (first + last + ~3 middle), and auto-truncates each shown label so dense datasets\n * stay readable. Pass an explicit formatter to override the per-label rendering — to also\n * change which labels are visible, pass `xAxisInterval` and a formatter that returns the\n * value for every index.\n *\n * The tooltip continues to show the full unformatted value on hover regardless.\n */\n xAxisTickFormatter?: (value: unknown) => string;\n}\n\n/**\n * Target visible x-axis label count for line charts. Recharts' built-in `preserveStartEnd`\n * picks labels by collision detection, which produces uneven clusters when label widths vary.\n * Picking a fixed target and distributing evenly gives a cleaner result and the same value at\n * any chart width (the chart still shows every data point as a dot — only labels thin out).\n */\nconst TARGET_VISIBLE_LABELS = 5;\n\n/**\n * Pre-composed line chart. Single-call usage for the common case; for custom recharts trees\n * compose `<ChartContainer>` + recharts primitives directly.\n *\n * ```tsx\n * <LineChart\n * data={[{ month: \"Jan\", value: 120 }, { month: \"Feb\", value: 132 }]}\n * xKey=\"month\"\n * series={[{ key: \"value\", label: \"Headcount\" }]}\n * smooth\n * />\n * ```\n *\n * **Smart defaults**: legend auto-hides for single-series; value labels default off (turn on\n * for sparse single-series charts); x-axis shows every tick by default.\n */\nexport function LineChart({\n data,\n xKey,\n series,\n smooth = true,\n showDots = true,\n strokeWidth = 2,\n height = 320,\n width = \"100%\",\n className,\n palette = CHART_PALETTE,\n showTooltip = true,\n showLegend,\n showGrid = true,\n showXAxis = true,\n showYAxis = true,\n showValueLabels = false,\n xAxisInterval = 0,\n xAxisAngle = 0,\n xAxisTickFormatter,\n}: LineChartProps): ReactNode {\n const seriesKeys = useMemo(() => series.map((s) => s.key), [series]);\n // Memoised so non-artifact consumers passing inline `data` arrays don't re-allocate the\n // coerced copy on every parent render.\n const coercedData = useMemo(\n () => coerceNumericColumns(data as ReadonlyArray<Record<string, unknown>>, seriesKeys),\n [data, seriesKeys]\n );\n const lineType = smooth ? \"monotone\" : \"linear\";\n\n const resolvedShowLegend = showLegend ?? series.length > 1;\n // Default: only ~5 evenly distributed labels are visible (first + last + middle), each\n // truncated to fit. Consumer can override with `xAxisTickFormatter` (their formatter is\n // applied to every label without thinning). See `defaultLineChartTickFormatter`.\n const resolvedTickFormatter = useMemo(() => {\n if (xAxisTickFormatter) return xAxisTickFormatter;\n const visible = evenlyDistributedVisibleIndices(coercedData.length, TARGET_VISIBLE_LABELS);\n return defaultLineChartTickFormatter(coercedData.length, visible);\n }, [xAxisTickFormatter, coercedData.length]);\n const angledLabelPad = xAxisAngle === 0 ? 0 : Math.min(Math.abs(xAxisAngle) * 0.7, 40);\n // Extra right margin so the rightmost x-axis tick label has room to render its right half\n // without getting clipped at the chart edge. Recharts centres tick labels under their tick;\n // without padding, ~half of the last label spills past the plot area.\n const chartMargin = { ...CHART_MARGIN, right: CHART_MARGIN.right + 16, bottom: CHART_MARGIN.bottom + angledLabelPad };\n\n return (\n <ChartContainer height={height} width={width} className={className}>\n <RechartsLineChart data={coercedData} margin={chartMargin}>\n {showGrid ? <CartesianGrid {...CHART_GRID_PROPS} /> : null}\n {showXAxis ? (\n <XAxis\n dataKey={xKey}\n {...CHART_AXIS_PROPS}\n interval={xAxisInterval}\n angle={xAxisAngle}\n textAnchor={xAxisAngle !== 0 ? \"end\" : \"middle\"}\n tickMargin={xAxisAngle === 0 ? 8 : 12}\n height={xAxisAngle !== 0 ? 60 : undefined}\n tickFormatter={resolvedTickFormatter}\n />\n ) : null}\n {showYAxis ? <YAxis {...CHART_AXIS_PROPS} width={40} tickFormatter={compactNumberTickFormatter} /> : null}\n {showTooltip ? <Tooltip content={<ChartTooltipContent />} /> : null}\n {resolvedShowLegend ? (\n <Legend\n verticalAlign=\"top\"\n align=\"center\"\n // Pin the absolutely-positioned wrapper flush to the chart's top edge — see `BarChart`\n // for the rationale.\n wrapperStyle={{ top: 0 }}\n // Preserve declaration order; disable recharts 3.x's `'value'` alphabetical sort.\n // See `BarChart` for the rationale.\n itemSorter={null}\n content={<ChartLegendContent iconType=\"line\" />}\n />\n ) : null}\n {series.map((s, i) => {\n const color = colorForSeriesIndex(i, palette);\n return (\n <Line\n key={s.key}\n type={lineType}\n dataKey={s.key}\n name={s.label}\n stroke={color}\n strokeWidth={strokeWidth}\n // Filled dot matching the line color — recharts default is hollow (white fill +\n // colored stroke), which reads as \"annotation\" rather than \"data point\".\n dot={showDots ? { r: 3, fill: color, stroke: color, strokeWidth: 0 } : false}\n activeDot={{ r: 5, fill: color, stroke: LINE_ACTIVE_DOT_STROKE, strokeWidth: 2 }}\n >\n {showValueLabels ? <LabelList dataKey={s.key} position=\"top\" style={CHART_VALUE_LABEL_STYLE} /> : null}\n </Line>\n );\n })}\n </RechartsLineChart>\n </ChartContainer>\n );\n}\n","import { type ReactNode, useMemo } from \"react\";\nimport { Cell, Legend, Pie, PieChart as RechartsPieChart, Tooltip } from \"recharts\";\n\nimport { ChartContainer } from \"../chart-container\";\nimport { ChartLegendContent } from \"../chart-legend-content\";\nimport { ChartTooltipContent } from \"../chart-tooltip-content\";\nimport { CHART_PALETTE, DEFAULT_OTHERS_CATEGORY_LABELS } from \"../chart-palette\";\nimport { CHART_VALUE_LABEL_STYLE, PIE_CHART_MARGIN } from \"../chart-styles\";\nimport { coerceNumericColumns } from \"../coerce-numeric\";\nimport { buildPieSlices } from \"./utils\";\n\n/**\n * Recharts injects geometric position props onto label render functions. Typed locally because\n * recharts' `PieLabelProps` is overly tagged-generic.\n */\ninterface PieLabelRenderProps {\n /** Computed x coordinate for the label (outside the slice). */\n x?: number;\n /** Computed y coordinate for the label. */\n y?: number;\n /** \"start\" / \"middle\" / \"end\" / \"inherit\" — pre-computed for legibility outside the slice. */\n textAnchor?: \"start\" | \"middle\" | \"end\" | \"inherit\";\n /** The slice's numeric value (the value of `valueKey` on the row). */\n value?: unknown;\n}\n\nexport interface PieChartProps {\n /** Rows to plot. Each row maps to one slice. */\n data: ReadonlyArray<Record<string, unknown>>;\n /** Data column used as the slice label / legend entry. */\n categoryKey: string;\n /** Data column used as the slice numeric value. */\n valueKey: string;\n /** Container height. Default 320. */\n height?: number | string;\n /** Container width. Default `\"100%\"`. */\n width?: number | string;\n /** Optional className on the outer container. */\n className?: string;\n /** Override the default palette. Default `CHART_PALETTE` — the shared blue + indigo graduated\n * palette every chart variant uses. Override per-instance for brand-specific colours. */\n palette?: readonly string[];\n /** Show value labels next to each slice. Default true. */\n showLabels?: boolean;\n /** Show the tooltip on hover. Default true. */\n showTooltip?: boolean;\n /** Show the legend (category names). Default true. Position controlled by `legendPosition`. */\n showLegend?: boolean;\n /** Inner radius — `0` (default) for a pie; `>0` (e.g. `\"40%\"`) for a donut. */\n innerRadius?: number | string;\n /** Outer radius. Default `\"68%\"` — leaves room for outside value labels. */\n outerRadius?: number | string;\n /**\n * Category labels treated as the \"Others\" bucket (case-insensitive match). Matching slices are\n * pinned to the end of the sweep regardless of value and rendered in neutral grey\n * (`OTHERS_SLICE_COLOR`).\n *\n * **Default**: `DEFAULT_OTHERS_CATEGORY_LABELS` (English \"Others\" / \"Other\"). Pass a localized\n * list in non-English UIs — e.g. `[\"אחרים\"]` for Hebrew or `[\"Otros\", \"Otro\"]` for Spanish.\n * Pass `[]` to disable Others detection entirely (every slice colored from the palette).\n */\n othersCategoryLabels?: readonly string[];\n}\n\n/**\n * Pre-composed pie chart. One slice per row, colored by row index from the palette. Outside\n * value labels (no connector line); legend at the top. Set `innerRadius` to make a donut.\n *\n * **Sweep**: starts at 12 o'clock and proceeds clockwise (`startAngle={90}` / `endAngle={-270}`).\n * Recharts' default starts at 3 o'clock counter-clockwise, which feels arbitrary for a\n * data-first composition.\n *\n * **\"Others\" bucket**: explicit \"Others\" / \"Other\" categories (case-insensitive) *and*\n * missing-value categories (`null` / `\"\"` / `\"(none)\"` / …) are summed into a single neutral-grey\n * slice pinned to the end of the sweep, so they read as \"unattributed leftover\" rather than peer\n * categories. A `\"(none)\"` row therefore collapses *into* \"Other\" instead of standing alone.\n * Named slices retain their incoming order and palette colors. See `buildPieSlices`.\n *\n * ```tsx\n * <PieChart\n * data={[\n * { department: \"Engineering\", headcount: 42 },\n * { department: \"Sales\", headcount: 18 },\n * { department: \"Others\", headcount: 5 },\n * ]}\n * categoryKey=\"department\"\n * valueKey=\"headcount\"\n * />\n *\n * // Donut variant\n * <PieChart data={...} categoryKey=\"...\" valueKey=\"...\" innerRadius=\"40%\" />\n * ```\n */\nexport function PieChart({\n data,\n categoryKey,\n valueKey,\n height = 320,\n width = \"100%\",\n className,\n palette = CHART_PALETTE,\n showLabels = true,\n showTooltip = true,\n showLegend = true,\n innerRadius = 0,\n outerRadius = \"68%\",\n othersCategoryLabels = DEFAULT_OTHERS_CATEGORY_LABELS,\n}: PieChartProps): ReactNode {\n // Memoised so non-artifact consumers passing inline `data` arrays don't re-allocate the\n // coerced + bucketed copy on every parent render. Coerce the `valueKey` column to numeric\n // (CSV-derived rows arrive as strings), then partition into named slices + one merged grey\n // \"Others\" slice (explicit \"Others\"/\"Other\" and missing-value rows collapse together). See\n // `buildPieSlices`.\n const { orderedData, sliceColors } = useMemo(() => {\n const coerced = coerceNumericColumns(data as ReadonlyArray<Record<string, unknown>>, [valueKey]);\n return buildPieSlices(coerced, categoryKey, valueKey, othersCategoryLabels, palette);\n }, [data, valueKey, categoryKey, othersCategoryLabels, palette]);\n\n return (\n <ChartContainer height={height} width={width} className={className}>\n <RechartsPieChart margin={PIE_CHART_MARGIN}>\n {showTooltip ? <Tooltip content={<ChartTooltipContent />} /> : null}\n {showLegend ? (\n <Legend\n verticalAlign=\"top\"\n align=\"center\"\n // Pin the absolutely-positioned wrapper flush to the chart's top edge — see `BarChart`\n // for the rationale.\n wrapperStyle={{ top: 0 }}\n // Preserve slice order; disable recharts 3.x's `'value'` alphabetical sort. Critical\n // for pie because the Others bucket is intentionally pinned to the end of the sweep\n // — sorting alphabetically would break that contract.\n itemSorter={null}\n content={<ChartLegendContent iconType=\"square\" />}\n />\n ) : null}\n <Pie\n data={orderedData}\n dataKey={valueKey}\n nameKey={categoryKey}\n cx=\"50%\"\n cy=\"52%\"\n // Start at 12 o'clock and sweep clockwise. Recharts' default (`0` / `360`) starts at\n // 3 o'clock counter-clockwise. The +90 / -270 pair preserves the full 360° arc length.\n startAngle={90}\n endAngle={-270}\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n label={\n showLabels\n ? (entry: PieLabelRenderProps) => {\n const v = entry.value;\n if (v === undefined || v === null) return null;\n // Render the label as a `<text>` so we can pin its `fill` to the shared\n // `CHART_VALUE_LABEL_STYLE` instead of letting recharts auto-color it to\n // the slice's fill (which on light-blue slices becomes near-invisible).\n // Recharts passes the computed `x`/`y`/`textAnchor` so positioning is\n // unchanged.\n return (\n <text\n x={entry.x}\n y={entry.y}\n fill={CHART_VALUE_LABEL_STYLE.fill}\n fontSize={CHART_VALUE_LABEL_STYLE.fontSize}\n fontWeight={CHART_VALUE_LABEL_STYLE.fontWeight}\n textAnchor={entry.textAnchor}\n dominantBaseline=\"central\"\n >\n {String(v)}\n </text>\n );\n }\n : false\n }\n // No connector line — outside labels sit clean next to their slice. The thin\n // brown line between slice and label adds visual noise without information gain.\n labelLine={false}\n // No stroke between slices — gradient palette + adjacent contiguous segments read\n // as one continuous wheel rather than discrete cards with cream gaps between them.\n stroke=\"none\"\n strokeWidth={0}\n >\n {orderedData.map((_row, i) => (\n <Cell key={i} fill={sliceColors[i]} />\n ))}\n </Pie>\n </RechartsPieChart>\n </ChartContainer>\n );\n}\n","import {\n OTHERS_SLICE_COLOR,\n colorForSeriesIndex,\n isNoneCategory,\n isOthersCategory,\n} from \"../chart-palette\";\n\n/**\n * Result of partitioning pie rows into palette-colored named slices plus one merged grey\n * \"Others\" slice.\n */\nexport interface PieSlices {\n /** Rows in render order — named slices first, the merged Others slice (if any) last. */\n orderedData: Record<string, unknown>[];\n /** Per-slice fill color, index-aligned to `orderedData`. */\n sliceColors: string[];\n}\n\n/**\n * Display label for the merged Others slice. Prefers an explicit \"Others\"/\"Other\" row's own\n * label (keeps a localized bucket name as the agent wrote it); falls back to the first configured\n * others label, capitalized, when only missing-value rows were folded in.\n *\n * @param leftoverRows - Rows being merged into the Others bucket.\n * @param categoryKey - Column holding each row's category label.\n * @param othersCategoryLabels - Configured \"Others\" match labels.\n * @returns The label to render on the merged slice.\n */\nfunction mergedOthersLabel(\n leftoverRows: ReadonlyArray<Record<string, unknown>>,\n categoryKey: string,\n othersCategoryLabels: readonly string[]\n): string {\n const explicit = leftoverRows.find((row) => isOthersCategory(row[categoryKey], othersCategoryLabels));\n if (explicit) return String(explicit[categoryKey]);\n const fallback = othersCategoryLabels[0] ?? \"Other\";\n return fallback.charAt(0).toUpperCase() + fallback.slice(1);\n}\n\n/**\n * Partitions pie rows into named slices and a single merged \"Others\" slice.\n *\n * - **Named slices** keep their incoming order and are colored by their *named-slice index* (not\n * their position in the output), so adding/removing a leftover row never shifts a named\n * category's color.\n * - **Leftover rows** — explicit \"Others\"/\"Other\" categories *and* missing-value categories\n * (`null` / `\"\"` / `\"(none)\"` / …) — are summed into one grey slice pinned to the end of the\n * sweep. This collapses `\"(none)\"` *into* \"Other\" rather than rendering it as a peer grey slice.\n * - Bucketing is gated on `othersCategoryLabels` being non-empty; pass `[]` to render every row as\n * a palette-colored peer (no Others/none folding).\n *\n * @param data - Rows with the value column already coerced to numeric.\n * @param categoryKey - Column holding each slice's category label.\n * @param valueKey - Column holding each slice's numeric value.\n * @param othersCategoryLabels - \"Others\" match labels; `[]` disables bucketing.\n * @param palette - Ordered colors assigned to named slices by index.\n * @returns Render-ordered rows and their index-aligned fill colors.\n */\nexport function buildPieSlices(\n data: ReadonlyArray<Record<string, unknown>>,\n categoryKey: string,\n valueKey: string,\n othersCategoryLabels: readonly string[],\n palette: readonly string[]\n): PieSlices {\n const namedRows: Record<string, unknown>[] = [];\n const namedColors: string[] = [];\n const leftoverRows: Record<string, unknown>[] = [];\n\n for (const row of data) {\n const isLeftover =\n othersCategoryLabels.length > 0 &&\n (isNoneCategory(row[categoryKey]) || isOthersCategory(row[categoryKey], othersCategoryLabels));\n if (isLeftover) {\n leftoverRows.push(row);\n } else {\n namedRows.push(row);\n namedColors.push(colorForSeriesIndex(namedRows.length - 1, palette));\n }\n }\n\n if (leftoverRows.length === 0) {\n return { orderedData: namedRows, sliceColors: namedColors };\n }\n\n const total = leftoverRows.reduce((sum, row) => sum + (Number(row[valueKey]) || 0), 0);\n const mergedRow: Record<string, unknown> = {\n [categoryKey]: mergedOthersLabel(leftoverRows, categoryKey, othersCategoryLabels),\n [valueKey]: total,\n };\n\n return {\n orderedData: [...namedRows, mergedRow],\n sliceColors: [...namedColors, OTHERS_SLICE_COLOR],\n };\n}\n"],"mappings":"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","names":["import_recharts","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","RechartsBarChart","import_react","import_recharts","import_jsx_runtime","RechartsLineChart","import_react","import_recharts","import_jsx_runtime","RechartsPieChart"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/chart/index.ts","../src/components/chart/bar-chart/bar-chart.tsx","../src/components/chart/chart-container.tsx","../src/lib/utils.ts","../src/components/chart/chart-legend-content.tsx","../src/components/chart/chart-tooltip-content.tsx","../src/tokens/colors.ts","../src/components/chart/chart-palette.ts","../src/components/chart/chart-styles.ts","../src/components/chart/chart-tick-utils.ts","../src/components/chart/coerce-numeric.ts","../src/components/chart/line-chart/line-chart.tsx","../src/components/chart/pie-chart/pie-chart.tsx","../src/components/chart/pie-chart/utils.ts"],"sourcesContent":["/**\n * Public surface for `@shapesos/clay/chart`.\n *\n * Two layers:\n *\n * 1. **High-level components** — single-call convenience renderers with sensible defaults.\n * Use these for ~90% of cases:\n *\n * ```tsx\n * import { BarChart, LineChart, PieChart } from \"@shapesos/clay/chart\";\n *\n * <BarChart data={rows} xKey=\"month\" series={[...]} stacked />\n * <LineChart data={rows} xKey=\"month\" series={[...]} smooth />\n * <PieChart data={rows} categoryKey=\"dept\" valueKey=\"count\" />\n * ```\n *\n * 2. **Composable primitives** — for custom recharts trees (mixed-type charts, radar, scatter,\n * or anything the high-level components don't cover):\n *\n * ```tsx\n * import { ChartContainer, ChartTooltipContent, ChartLegendContent,\n * CHART_AXIS_PROPS, CHART_GRID_PROPS, CHART_PALETTE } from \"@shapesos/clay/chart\";\n * import { LineChart, Line, XAxis, YAxis, Tooltip, Legend, CartesianGrid } from \"recharts\";\n *\n * <ChartContainer height={320}>\n * <LineChart data={data}>\n * <CartesianGrid {...CHART_GRID_PROPS} />\n * <XAxis dataKey=\"month\" {...CHART_AXIS_PROPS} />\n * <YAxis {...CHART_AXIS_PROPS} />\n * <Tooltip content={<ChartTooltipContent />} />\n * <Legend content={<ChartLegendContent iconType=\"line\" />} />\n * <Line dataKey=\"value\" stroke={CHART_PALETTE[0]} />\n * </LineChart>\n * </ChartContainer>\n * ```\n *\n * **Required CSS** — consumers must import the compiled Tailwind bundle:\n *\n * import \"@shapesos/clay/blocks/styles.css\";\n *\n * (The stylesheet name is `blocks/styles.css` for historical reasons — it's the single bundle\n * that compiles all clay-side Tailwind output, including the chart components.)\n */\n\n// ── high-level components ─────────────────────────────────────────────────────────────────\nexport { BarChart } from \"./bar-chart/bar-chart\";\nexport type { BarChartProps } from \"./bar-chart/bar-chart\";\n\nexport { LineChart } from \"./line-chart/line-chart\";\nexport type { LineChartProps } from \"./line-chart/line-chart\";\n\nexport { PieChart } from \"./pie-chart/pie-chart\";\nexport type { PieChartProps } from \"./pie-chart/pie-chart\";\n\n// ── composable primitives ─────────────────────────────────────────────────────────────────\nexport { ChartContainer } from \"./chart-container\";\nexport type { ChartContainerProps } from \"./chart-container\";\n\nexport { ChartTooltipContent } from \"./chart-tooltip-content\";\nexport type { ChartTooltipContentProps } from \"./chart-tooltip-content\";\n\nexport { ChartLegendContent } from \"./chart-legend-content\";\nexport type { ChartLegendContentProps } from \"./chart-legend-content\";\n\n// ── shared types ──────────────────────────────────────────────────────────────────────────\nexport type { ChartSeries, ChartVariant } from \"./types\";\n\n// ── styling presets (spreadable into recharts primitives) ────────────────────────────────\n//\n// Only the two preset bundles are public — they're the documented composable surface for\n// custom chart trees. The raw color/margin constants behind them (`AXIS_STROKE`, `GRID_STROKE`,\n// `CHART_MARGIN`, etc.) stay internal to `chart-styles.ts`; promote them if a third-party\n// consumer ever needs a single constant without the preset bundle.\nexport { CHART_AXIS_PROPS, CHART_GRID_PROPS } from \"./chart-styles\";\n\n// ── palette + helpers ─────────────────────────────────────────────────────────────────────\n// CHART_PALETTE — shared blue + indigo graduated palette, default for every chart variant\n// (BarChart, LineChart, PieChart). One palette keeps adjacent charts on a dashboard reading\n// as a unified design system rather than three independently-themed components.\nexport { CHART_PALETTE, colorForSeriesIndex } from \"./chart-palette\";\nexport { coerceNumericColumns } from \"./coerce-numeric\";\n","import { type ReactNode, useMemo } from \"react\";\nimport { Bar, BarChart as RechartsBarChart, CartesianGrid, Legend, Tooltip, XAxis, YAxis } from \"recharts\";\n\nimport { ChartContainer } from \"../chart-container\";\nimport { ChartLegendContent } from \"../chart-legend-content\";\nimport { ChartTooltipContent } from \"../chart-tooltip-content\";\nimport { CHART_PALETTE, colorForSeriesIndex } from \"../chart-palette\";\nimport {\n BAR_TOOLTIP_CURSOR_FILL,\n CHART_AXIS_PROPS,\n CHART_GRID_PROPS,\n CHART_MARGIN,\n} from \"../chart-styles\";\nimport { compactNumberTickFormatter, defaultBarTickFormatter } from \"../chart-tick-utils\";\nimport { coerceNumericColumns } from \"../coerce-numeric\";\nimport type { ChartSeries } from \"../types\";\n\nexport interface BarChartProps {\n /** Rows to plot. Each row should carry the `xKey` column and one column per `series[].key`. */\n data: ReadonlyArray<Record<string, unknown>>;\n /** CSV/data column to use for the categorical x-axis (e.g. `\"month\"`, `\"quarter\"`). */\n xKey: string;\n /** One descriptor per bar series. Length 1 = single-series chart; 2+ = grouped or stacked. */\n series: ChartSeries[];\n /**\n * When true, all series stack on one stack-id (vertical sum). When false (default), bars\n * group side-by-side per x-tick.\n */\n stacked?: boolean;\n /** Container height. Number = px, string = any CSS length. Default 320. */\n height?: number | string;\n /** Container width. Default `\"100%\"`. */\n width?: number | string;\n /** Optional className on the outer container. */\n className?: string;\n /** Override the default palette (`CHART_PALETTE`). Colors are assigned by series index. */\n palette?: readonly string[];\n /** Show the tooltip on hover. Default true. */\n showTooltip?: boolean;\n /**\n * Show the legend at the top. **Default behavior**: auto-hidden for single-series charts\n * (the legend would just label the one and only color, which is noise). Pass `true` to force\n * the legend even with one series; pass `false` to suppress for multi-series.\n */\n showLegend?: boolean;\n /** Show horizontal dashed grid lines. Default true. */\n showGrid?: boolean;\n /** Show the x-axis. Default true. */\n showXAxis?: boolean;\n /** Show the y-axis. Default true. */\n showYAxis?: boolean;\n /**\n * Recharts XAxis tick `interval`. Default `0` — every category gets a label (no info loss\n * from auto-skipping). Use `\"preserveStartEnd\"` to let recharts drop colliding labels but\n * keep the first and last. For long category names, prefer `xAxisAngle` to rotate the labels\n * rather than dropping them.\n */\n xAxisInterval?: number | \"preserveStart\" | \"preserveEnd\" | \"preserveStartEnd\";\n /**\n * Rotate x-axis tick labels by this many degrees. **Default**: auto — `0` (horizontal) for\n * ≤7 categories; `-30` for 8+ categories so longer labels fit diagonally without overlapping\n * their neighbours. Pass `0` explicitly to force horizontal labels even at high counts; pass\n * any other number to set a custom angle.\n *\n * When the resolved angle is non-zero the chart auto-bumps its bottom margin and right-\n * anchors the labels so they don't run off the axis. The container `height` budget should\n * accommodate the angled labels (~40-60px more).\n */\n xAxisAngle?: number;\n /**\n * Custom formatter for x-axis tick labels. **Default**: clay auto-truncates labels based on\n * the number of categories so no labels overlap (see `getDefaultTickFormatter`). Pass an\n * explicit formatter to override — e.g. for word-boundary truncation, locale-aware\n * abbreviations, or to opt out of truncation entirely with `(v) => String(v)`.\n *\n * The tooltip continues to show the full unformatted value on hover regardless.\n */\n xAxisTickFormatter?: (value: unknown) => string;\n}\n\n/**\n * Pre-composed bar chart. Single-call usage for the common case; for custom recharts trees\n * compose `<ChartContainer>` + recharts primitives directly.\n *\n * ```tsx\n * <BarChart\n * data={[{ month: \"Jan\", us: 120, uk: 60 }, { month: \"Feb\", us: 132, uk: 64 }]}\n * xKey=\"month\"\n * series={[\n * { key: \"us\", label: \"US\" },\n * { key: \"uk\", label: \"UK\" },\n * ]}\n * stacked\n * />\n * ```\n *\n * **Smart defaults**: legend auto-hides for single-series charts; all x-axis ticks are shown\n * by default (no recharts auto-skip). Override any of these via the named props.\n *\n * Numeric coercion: `data` rows may carry string values for the series columns (e.g. when\n * derived from CSV) — recharts needs numbers, so we coerce in-place. Already-numeric data\n * passes through unchanged.\n */\nexport function BarChart({\n data,\n xKey,\n series,\n stacked = false,\n height = 320,\n width = \"100%\",\n className,\n palette = CHART_PALETTE,\n showTooltip = true,\n showLegend,\n showGrid = true,\n showXAxis = true,\n showYAxis = true,\n xAxisInterval = 0,\n xAxisAngle,\n xAxisTickFormatter,\n}: BarChartProps): ReactNode {\n const seriesKeys = useMemo(() => series.map((s) => s.key), [series]);\n // Memoised so non-artifact consumers passing inline `data` arrays don't re-allocate the\n // coerced copy on every parent render. For the artifact path `data` is already stable from\n // `useRowsArtifactData`, so this is a no-op there.\n const coercedData = useMemo(\n () => coerceNumericColumns(data as ReadonlyArray<Record<string, unknown>>, seriesKeys),\n [data, seriesKeys]\n );\n\n // Smart defaults — see prop JSDoc for rationale.\n const resolvedShowLegend = showLegend ?? series.length > 1;\n // Auto-angle for dense bar charts: at 8+ categories the horizontal slot per label is too\n // narrow for full-text labels to fit. Rotating to -30° lets labels extend diagonally below\n // the axis without overlapping their neighbours. Consumer can override with `xAxisAngle={0}`.\n const resolvedAngle = xAxisAngle ?? (coercedData.length >= 8 ? -30 : 0);\n // Auto-truncating tick formatter — keeps every bar labeled while preventing overlap. The\n // tooltip shows the full unformatted value on hover, so no information is lost. Consumer\n // can opt out with `(v) => String(v)`.\n const resolvedTickFormatter = useMemo(\n () => xAxisTickFormatter ?? defaultBarTickFormatter(coercedData.length),\n [xAxisTickFormatter, coercedData.length]\n );\n\n // Angled labels need extra bottom margin so they don't clip the chart. ~0.7px per degree\n // covers up to -45° comfortably; we cap to avoid runaway when callers pass aggressive angles.\n const angledLabelPad = resolvedAngle === 0 ? 0 : Math.min(Math.abs(resolvedAngle) * 0.7, 40);\n const chartMargin = { ...CHART_MARGIN, bottom: CHART_MARGIN.bottom + angledLabelPad };\n\n return (\n <ChartContainer height={height} width={width} className={className}>\n <RechartsBarChart data={coercedData} margin={chartMargin} barCategoryGap=\"22%\">\n {showGrid ? <CartesianGrid {...CHART_GRID_PROPS} /> : null}\n {showXAxis ? (\n <XAxis\n dataKey={xKey}\n {...CHART_AXIS_PROPS}\n interval={xAxisInterval}\n angle={resolvedAngle}\n // Right-anchor angled labels so the end of each label aligns with its tick, rather\n // than the centre running off the axis. Middle-anchor for horizontal labels.\n textAnchor={resolvedAngle !== 0 ? \"end\" : \"middle\"}\n tickMargin={resolvedAngle === 0 ? 8 : 12}\n height={resolvedAngle !== 0 ? 60 : undefined}\n tickFormatter={resolvedTickFormatter}\n />\n ) : null}\n {showYAxis ? <YAxis {...CHART_AXIS_PROPS} width={40} tickFormatter={compactNumberTickFormatter} /> : null}\n {showTooltip ? <Tooltip cursor={{ fill: BAR_TOOLTIP_CURSOR_FILL }} content={<ChartTooltipContent />} /> : null}\n {resolvedShowLegend ? (\n <Legend\n verticalAlign=\"top\"\n align=\"center\"\n // Pin the absolutely-positioned wrapper flush to the chart's top edge. Recharts'\n // default `top` for a top-aligned legend leaves a gap above the swatches; we'd\n // rather let `CHART_MARGIN.top` control the breathing room below the legend.\n wrapperStyle={{ top: 0 }}\n // Recharts 3.x defaults `itemSorter` to `'value'`, which alphabetically sorts legend\n // entries by label. The tooltip, the stack, and our chart's series colours all follow\n // declaration order — sorting the legend silently breaks correspondence (an \"Others\"\n // series declared last ends up mid-legend alphabetically). `null` disables the sort.\n itemSorter={null}\n content={<ChartLegendContent iconType=\"square\" />}\n />\n ) : null}\n {series.map((s, i) => (\n <Bar\n key={s.key}\n dataKey={s.key}\n name={s.label}\n fill={colorForSeriesIndex(i, palette)}\n stackId={stacked ? \"default\" : s.key}\n radius={barRadius(stacked, i, series.length)}\n />\n ))}\n </RechartsBarChart>\n </ChartContainer>\n );\n}\n\n/**\n * Per-corner border radius for a bar at position `seriesIndex` in `seriesCount` total series.\n *\n * - **Grouped (non-stacked)** — every series rounded at the top (`[6, 6, 0, 0]`). Bottom sits\n * on the X-axis, so flat bottom looks correct.\n * - **Stacked** — only the top-most segment gets `[6, 6, 0, 0]`; bottom + middle segments are\n * squared so the rect joins look seamless. Bottom segment is flat too because the chart's\n * X-axis is its base.\n */\nfunction barRadius(stacked: boolean, seriesIndex: number, seriesCount: number): [number, number, number, number] {\n if (!stacked) return [6, 6, 0, 0];\n const isTopSegment = seriesIndex === seriesCount - 1;\n return isTopSegment ? [6, 6, 0, 0] : [0, 0, 0, 0];\n}\n","import { type CSSProperties, type ReactElement, type ReactNode } from \"react\";\nimport { ResponsiveContainer } from \"recharts\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface ChartContainerProps {\n /** A single recharts chart element — `<LineChart>`, `<BarChart>`, `<PieChart>`, etc. */\n children: ReactElement;\n /**\n * Container height. Recharts' `ResponsiveContainer` measures its parent, so we need a\n * concrete value here (not \"auto\"). Accepts a number (px) or any CSS length string.\n * Defaults to `320` — a sensible mid-density chart height.\n */\n height?: number | string;\n /**\n * Container width. Defaults to `\"100%\"` so the chart flexes to its parent. Pass a fixed\n * number when embedding in a layout that doesn't have a definite width (e.g. an auto-sized\n * flex column).\n */\n width?: number | string;\n /** Optional className spread on the outer wrapper. */\n className?: string;\n /** Optional inline style merged into the outer wrapper. `width`/`height` here take precedence. */\n style?: CSSProperties;\n}\n\n/**\n * The composable foundation for every clay chart. Wraps recharts' `ResponsiveContainer` in a\n * sized `<div>` so the chart has a definite parent box to measure against — without this, charts\n * silently collapse to 0×0 inside flex containers (see the `flex-basis` gotcha documented in\n * the chart-artifact orchestrator).\n *\n * Use directly when composing a chart from recharts primitives:\n *\n * ```tsx\n * <ChartContainer height={320}>\n * <LineChart data={data} margin={{ top: 8, right: 16, left: 0, bottom: 4 }}>\n * <CartesianGrid {...CHART_GRID_PROPS} />\n * <XAxis dataKey=\"month\" {...CHART_AXIS_PROPS} />\n * <YAxis {...CHART_AXIS_PROPS} />\n * <Tooltip content={<ChartTooltipContent />} />\n * <Legend content={<ChartLegendContent />} />\n * <Line dataKey=\"value\" stroke={CHART_PALETTE[0]} />\n * </LineChart>\n * </ChartContainer>\n * ```\n *\n * For common shapes, prefer the pre-composed `<BarChart>` / `<LineChart>` / `<PieChart>` —\n * they call `ChartContainer` under the hood with sensible defaults.\n */\nexport function ChartContainer({\n children,\n height = 320,\n width = \"100%\",\n className,\n style,\n}: ChartContainerProps): ReactNode {\n return (\n <div className={cn(\"text-xs text-foreground\", className)} style={{ width, height, ...style }}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n {children}\n </ResponsiveContainer>\n </div>\n );\n}\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Combines class names using clsx and tailwind-merge — the standard shadcn/ui helper.\n * Tailwind classes that conflict (e.g. `p-2 p-4`) get merged so the last one wins.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { type ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Single entry in recharts' legend payload — one per series. Typed locally because recharts'\n * `LegendProps['payload']` is overly tagged-generic.\n */\ninterface LegendPayloadEntry {\n value?: string | number;\n color?: string;\n dataKey?: string | number;\n type?: string;\n}\n\n/**\n * Recharts injects `payload` at runtime when this component is used as the `content` slot on\n * `<Legend>`. Consumer-facing props (`className`, `iconType`) survive the cloneElement merge.\n */\nexport interface ChartLegendContentProps {\n /** Set by recharts at runtime — one entry per series. */\n payload?: LegendPayloadEntry[];\n /** Optional className merged onto the legend list. */\n className?: string;\n /** Visual indicator next to each label. `square` for bars/pies; `line` for line/area. Default `square`. */\n iconType?: \"square\" | \"line\";\n}\n\n/**\n * The default legend body for clay charts. Drop into any recharts `<Legend>`:\n *\n * ```tsx\n * <Legend content={<ChartLegendContent iconType=\"square\" />} />\n * <Legend content={<ChartLegendContent iconType=\"line\" />} />\n * ```\n *\n * Recharts also accepts `verticalAlign` / `align` on `<Legend>` itself for positioning —\n * `<ChartLegendContent>` is just the body. Style stays consistent regardless of position.\n */\nexport function ChartLegendContent({ payload, className, iconType = \"square\" }: ChartLegendContentProps): ReactNode {\n if (!payload || payload.length === 0) return null;\n\n return (\n <ul\n // No padding on this `<ul>`. Recharts wraps it in a `.recharts-legend-wrapper` div that's\n // positioned `absolute` with an inline `top` — padding here doesn't shift the wrapper's\n // anchor point, it only inflates the wrapper's height. The \"gap above the legend\" must be\n // controlled by the wrapper's inline `top`, set via each chart's `<Legend wrapperStyle>`.\n className={cn(\"flex flex-wrap items-center justify-center gap-x-4 gap-y-2 text-xs text-brown-80\", className)}\n >\n {payload.map((entry: LegendPayloadEntry, i: number) => {\n const swatchColor = typeof entry.color === \"string\" ? entry.color : \"transparent\";\n const label = entry.value !== undefined ? String(entry.value) : \"\";\n return (\n <li key={`${label}-${i}`} className=\"flex items-center gap-1.5\">\n {iconType === \"square\" ? (\n <span className=\"inline-block h-2.5 w-2.5 shrink-0 rounded-sm\" style={{ background: swatchColor }} />\n ) : (\n <span className=\"inline-block h-[3px] w-4 shrink-0 rounded-full\" style={{ background: swatchColor }} />\n )}\n <span>{label}</span>\n </li>\n );\n })}\n </ul>\n );\n}\n","import { type ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/**\n * Single entry in recharts' tooltip payload — one per series at the hovered x-tick.\n * Typed locally because recharts' `TooltipProps['payload']` is overly tagged-generic for this use.\n */\ninterface TooltipPayloadEntry {\n name?: string | number;\n value?: number | string;\n color?: string;\n dataKey?: string | number;\n}\n\n/**\n * Recharts injects `active`, `payload`, and `label` at runtime when this component is used as\n * the `content` slot on `<Tooltip>`. Consumer-facing props (`className`, `showLabel`,\n * `formatValue`) survive the cloneElement merge.\n */\nexport interface ChartTooltipContentProps {\n /** Set by recharts at runtime — true when the tooltip is hovered open. */\n active?: boolean;\n /** Set by recharts at runtime — one entry per series. */\n payload?: TooltipPayloadEntry[];\n /** Set by recharts at runtime — the x-tick label for the hovered column. */\n label?: string | number;\n /** Optional className merged onto the tooltip card. */\n className?: string;\n /** When false, the row label (typically the x-tick value) is hidden. Default true. */\n showLabel?: boolean;\n /** Override the formatter used on each entry's value. Defaults to `String(value)`. */\n formatValue?: (value: number | string | undefined, name: string | undefined) => string;\n}\n\n/**\n * The default tooltip card for clay charts. Drop into any recharts `<Tooltip>`:\n *\n * ```tsx\n * <Tooltip content={<ChartTooltipContent />} />\n * <Tooltip content={<ChartTooltipContent formatValue={(v) => `$${v}`} />} />\n * ```\n *\n * Renders a soft brown card with one row per series, swatch left, name center, value right.\n * Returns `null` when recharts says the tooltip is inactive — recharts mounts the content\n * component unconditionally and toggles it via the `active` prop.\n */\nexport function ChartTooltipContent({\n active,\n payload,\n label,\n className,\n showLabel = true,\n formatValue,\n}: ChartTooltipContentProps): ReactNode {\n if (!active || !payload || payload.length === 0) return null;\n\n return (\n <div\n className={cn(\n \"rounded-lg border border-brown-40 bg-brown-10 px-3 py-2 text-xs shadow-sm\",\n \"min-w-32 text-foreground\",\n className\n )}\n >\n {showLabel && label !== undefined && label !== null ? (\n <div className=\"mb-1.5 font-medium text-brown-90\">{String(label)}</div>\n ) : null}\n <ul className=\"space-y-1\">\n {payload.map((entry: TooltipPayloadEntry, i: number) => {\n const name = entry.name !== undefined ? String(entry.name) : \"\";\n const rawValue = entry.value;\n const display = formatValue ? formatValue(rawValue, name) : rawValue === undefined ? \"\" : String(rawValue);\n const swatch = typeof entry.color === \"string\" ? entry.color : \"transparent\";\n return (\n <li key={`${name}-${i}`} className=\"flex items-center gap-2\">\n <span className=\"inline-block h-2.5 w-2.5 shrink-0 rounded-sm\" style={{ background: swatch }} />\n <span className=\"text-brown-70\">{name}</span>\n <span className=\"ml-auto font-semibold tabular-nums text-brown-90\">{display}</span>\n </li>\n );\n })}\n </ul>\n </div>\n );\n}\n","export const colors = {\n // White\n white: \"#FFFFFF\",\n \"white-alpha-85\": \"rgba(255, 255, 255, 0.85)\",\n \"white-alpha-40\": \"rgba(255, 255, 255, 0.40)\",\n\n // Brown\n \"brown-10\": \"#FAF9F8\",\n \"brown-20\": \"#F5F3F0\",\n \"brown-30\": \"#EEEBE5\",\n \"brown-40\": \"#E6E2DA\",\n \"brown-50\": \"#CFCBC4\",\n \"brown-60\": \"#A19E99\",\n \"brown-70\": \"#73716D\",\n \"brown-80\": \"#5C5A57\",\n \"brown-90\": \"#2E2D2C\",\n \"brown-100\": \"#171716\",\n \"brown-alpha-12\": \"rgba(23, 23, 22, 0.12)\",\n \"brown-alpha-20\": \"rgba(23, 23, 22, 0.20)\",\n \"brown-alpha-55\": \"rgba(23, 23, 22, 0.55)\",\n \"brown-alpha-70\": \"rgba(23, 23, 22, 0.70)\",\n \"brown-alpha-80\": \"rgba(23, 23, 22, 0.80)\",\n \"brown-alpha-90\": \"rgba(23, 23, 22, 0.90)\",\n\n // Fuchsia\n \"fuchsia-50\": \"#FAF5FF\",\n \"fuchsia-300\": \"#F0ABFC\",\n \"fuchsia-500\": \"#D946EF\",\n \"fuchsia-600\": \"#C026D3\",\n \"fuchsia-800\": \"#86198F\",\n\n // Pink\n \"pink-50\": \"#FDF2F8\",\n \"pink-400\": \"#F472B6\",\n \"pink-600\": \"#DB2777\",\n \"pink-800\": \"#9D174D\",\n\n // Violet\n \"violet-50\": \"#F5F3FF\",\n \"violet-400\": \"#A78BFA\",\n \"violet-600\": \"#7C3AED\",\n \"violet-800\": \"#5B21B6\",\n\n // Indigo\n \"indigo-50\": \"#EEF2FF\",\n \"indigo-400\": \"#818CF8\",\n \"indigo-500\": \"#6366F1\",\n \"indigo-600\": \"#4F46E5\",\n \"indigo-800\": \"#3730A3\",\n\n // Cyan\n \"cyan-50\": \"#E7FEFF\",\n \"cyan-300\": \"#67E8F9\",\n \"cyan-600\": \"#0891B2\",\n \"cyan-900\": \"#164E63\",\n\n // Teal\n \"teal-50\": \"#EBFDF9\",\n \"teal-300\": \"#5EEAD4\",\n \"teal-600\": \"#0D9488\",\n\n // Rose\n \"rose-400\": \"#FB7185\",\n\n // Purple\n \"purple-400\": \"#C084FC\",\n\n // Blue\n \"blue-50\": \"#EFF6FF\",\n \"blue-100\": \"#DBEAFE\",\n \"blue-300\": \"#93C5FD\",\n \"blue-400\": \"#60A5FA\",\n \"blue-600\": \"#2563EB\",\n \"blue-800\": \"#1E40AF\",\n\n // Sky\n \"sky-300\": \"#7DD3FC\",\n\n // Green\n \"green-50\": \"#ECF9F0\",\n \"green-100\": \"#D4F1D9\",\n \"green-400\": \"#3DC269\",\n \"green-700\": \"#277C43\",\n \"green-800\": \"#1C5930\",\n\n // Orange\n \"orange-50\": \"#FFF7ED\",\n \"orange-100\": \"#FFEDD5\",\n \"orange-200\": \"#FED7AA\",\n \"orange-500\": \"#F97316\",\n \"orange-600\": \"#EA580C\",\n\n // Red\n \"red-50\": \"#FEF2F2\",\n \"red-100\": \"#FEE2E2\",\n \"red-200\": \"#FECACA\",\n \"red-400\": \"#F7776C\",\n \"red-500\": \"#EF4444\",\n \"red-600\": \"#DC2626\",\n\n // Deck\n \"deck-canvas\": \"#faf8f5\",\n} as const;\n\nexport type ColorToken = keyof typeof colors;\n","import { colors } from \"@/tokens\";\n\n/**\n * Single ordered color palette shared by every chart variant (`BarChart`, `LineChart`,\n * `PieChart`). A graduated walk down the blue family (`blue-600` → `blue-400` → `blue-300` →\n * `blue-100`), pivot into the indigo family (`indigo-400` → `indigo-500` → `indigo-600` →\n * `indigo-800`), and close on the deepest blue (`blue-800`).\n *\n * Design intent: every chart in the product sits in the same cool blue / indigo family so\n * adjacent charts on a dashboard read as a unified system rather than a kaleidoscope. The\n * deliberately narrow hue range (blue + indigo only — no warm accents) is the point: it\n * forecloses on rainbow-coded multi-series charts where the visual noise outweighs the\n * series-distinction it tries to provide.\n *\n * **Same palette for pie too**: pie slices read as parts of a whole, but they also share a\n * dashboard with bar/line charts — keeping one palette across every variant means a single\n * chat surface containing all three variants looks like one design system, not three.\n *\n * Nine entries — the v1 series cap. The palette cycles modulo its length for series counts\n * past nine via `colorForSeriesIndex`.\n */\nexport const CHART_PALETTE = [\n colors[\"blue-600\"], // #2563EB — primary\n colors[\"blue-400\"], // #60A5FA — mid\n colors[\"blue-300\"], // #93C5FD — light\n colors[\"blue-100\"], // #DBEAFE — very light\n colors[\"indigo-400\"], // #818CF8\n colors[\"indigo-500\"], // #6366F1\n colors[\"indigo-600\"], // #4F46E5\n colors[\"indigo-800\"], // #3730A3\n colors[\"blue-800\"], // #1E40AF — deepest\n] as const;\n\n/**\n * Slice color reserved for the \"Others\" bucket in pie charts. Neutral warm grey so it reads as\n * \"leftover / unattributed\" rather than a peer category. Pinning to a constant (rather than the\n * tail of `CHART_PALETTE`) means an Others slice always renders identically regardless of how\n * many named categories the data carries before it.\n */\nexport const OTHERS_SLICE_COLOR = colors[\"brown-60\"];\n\n/**\n * English fallback labels treated as the \"Others\" bucket — case-insensitive match.\n *\n * Consumers should pass their own localized list to `<PieChart>` via the `othersCategoryLabels`\n * prop (or via the artifact's `labels.othersCategoryLabels`) — in non-English UIs the agent\n * writes a translated bucket name (e.g. \"אחרים\", \"Otros\", \"Anderen\") and the consumer's i18n\n * layer is the only place that knows which strings to map to grey/last.\n */\nexport const DEFAULT_OTHERS_CATEGORY_LABELS: readonly string[] = [\"others\", \"other\"];\n\n/**\n * Category values that read as \"missing\" rather than a real category — `null`, `undefined`,\n * empty string, and the common placeholder strings a data source emits for an absent value\n * (e.g. a null employee gender surfacing as the literal `\"(none)\"`). Matched case-insensitively\n * after trimming. Folded into the grey \"Others\" bucket by `<PieChart>` so a missing-value slice\n * reads as \"unattributed leftover\" instead of a peer category in the palette.\n */\n// Deliberately excludes bare \"na\" — it collides with real category abbreviations like \"NA\"\n// (North America / Namibia). \"n/a\" (with the slash) is unambiguous and kept.\nconst NONE_CATEGORY_VALUES: readonly string[] = [\"\", \"(none)\", \"none\", \"null\", \"undefined\", \"n/a\", \"-\"];\n\n/**\n * True when `value` represents a missing/empty category (see `NONE_CATEGORY_VALUES`). `null` and\n * `undefined` always count; non-empty real category names never do.\n */\nexport function isNoneCategory(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n return NONE_CATEGORY_VALUES.includes(String(value).trim().toLowerCase());\n}\n\n/**\n * True when `value` matches one of `labels` (case-insensitive, trims whitespace). `labels` is\n * required — consumers pass either `DEFAULT_OTHERS_CATEGORY_LABELS` (English fallback) or their\n * own translated list. Pass an empty array to disable Others detection entirely.\n */\nexport function isOthersCategory(value: unknown, labels: readonly string[]): boolean {\n if (value === null || value === undefined) return false;\n if (labels.length === 0) return false;\n const normalized = String(value).trim().toLowerCase();\n for (const label of labels) {\n if (normalized === label.toLowerCase()) return true;\n }\n return false;\n}\n\n/**\n * Resolves the color for a series at `index`. Cycles deterministically past the palette length\n * so configurations with more series than colors still render rather than throwing. Pass an\n * alternate `palette` (e.g. a brand-specific override) to use something other than the default\n * `CHART_PALETTE`.\n */\nexport function colorForSeriesIndex(index: number, palette: readonly string[] = CHART_PALETTE): string {\n return palette[index % palette.length] ?? CHART_PALETTE[0];\n}\n","import { colors } from \"@/tokens\";\n\n/**\n * Shared visual constants for every chart variant. Two flavours of export:\n *\n * 1. Raw constants (`GRID_STROKE`, `AXIS_STROKE`, …) — for one-off uses or custom recharts trees.\n * 2. Preset prop bundles (`CHART_AXIS_PROPS`, `CHART_GRID_PROPS`) — spreadable into recharts\n * primitives so consumers can build composable charts without restating defaults:\n *\n * ```tsx\n * <CartesianGrid {...CHART_GRID_PROPS} />\n * <XAxis dataKey=\"x\" {...CHART_AXIS_PROPS} tickMargin={8} />\n * ```\n *\n * Recharts primitives must be inlined inside the chart tree — recharts identifies its slot\n * children by component reference (`child.type === XAxis`), so wrapping them in a custom React\n * component breaks dispatch. Constants and preset props are the right shape to share.\n */\n\n// ── raw color constants ──────────────────────────────────────────────────────────────────────\n\n/** Horizontal grid line color — kept soft so the data dominates the visual hierarchy. */\nexport const GRID_STROKE = colors[\"brown-40\"];\n\n/** Axis-line + axis-tick color. Lighter than the tick text so the axis frames rather than competes. */\nexport const AXIS_STROKE = colors[\"brown-50\"];\n\n/** Axis tick label text style. */\nexport const AXIS_TICK_STYLE = {\n fill: colors[\"brown-70\"],\n fontSize: 12,\n fontWeight: 500,\n} as const;\n\n/**\n * Text style for data-point value labels — bars (`<LabelList position=\"top\">`), line\n * data-point labels, and pie slice value labels all use this so labels read as one visual\n * family regardless of chart variant. Matches `AXIS_TICK_STYLE` for color/weight/size so\n * every secondary text element in a chart sits at the same hierarchy level.\n */\nexport const CHART_VALUE_LABEL_STYLE = {\n fill: colors[\"brown-70\"],\n fontSize: 12,\n fontWeight: 500,\n} as const;\n\n/** Cursor (hover guide) fill for bar tooltips. */\nexport const BAR_TOOLTIP_CURSOR_FILL = colors[\"brown-alpha-12\"];\n\n/** Active-dot ring fill on hovered line points — matches the chart background so the dot reads raised. */\nexport const LINE_ACTIVE_DOT_STROKE = colors[\"brown-10\"];\n\n/** Default recharts margin — leaves room for axis ticks/labels and the bottom legend. */\nexport const CHART_MARGIN = { top: 8, right: 16, left: 0, bottom: 4 } as const;\n\n/** Pie-specific margin — extra horizontal room to absorb outside slice labels. */\nexport const PIE_CHART_MARGIN = { top: 0, right: 24, left: 24, bottom: 4 } as const;\n\n// ── preset prop bundles ──────────────────────────────────────────────────────────────────────\n\n/**\n * Spreadable defaults for `<XAxis>` and `<YAxis>` — no axis line, no tick line, soft brown ticks.\n * Pass `dataKey` explicitly on `<XAxis>`; leave it off `<YAxis>`. Override anything per-instance.\n */\nexport const CHART_AXIS_PROPS = {\n stroke: AXIS_STROKE,\n tick: AXIS_TICK_STYLE,\n tickLine: false,\n axisLine: false,\n} as const;\n\n/**\n * Spreadable defaults for `<CartesianGrid>` — horizontal dashed lines only.\n */\nexport const CHART_GRID_PROPS = {\n stroke: GRID_STROKE,\n strokeDasharray: \"3 3\",\n vertical: false,\n} as const;\n","/**\n * Shared x-axis tick helpers used by both `BarChart` and `LineChart`. Pulled into one module so\n * the truncation thresholds and the truncation algorithm itself stay in one place — otherwise\n * each variant evolves its own slightly-different heuristic and the charts read inconsistently\n * side-by-side.\n *\n * Bar uses `defaultBarTickFormatter` (label per category, truncated when dense).\n * Line uses `defaultLineChartTickFormatter` (label only at evenly-distributed indices).\n * Both share the `maxTickCharsByCategoryCount` ladder and the `truncateLabel` ellipsis logic.\n */\n\n/**\n * Max characters per x-axis tick label, keyed by category count. The thresholds approximate the\n * available pixel slot per tick on a typical chat-card-width chart (~700px plot area) at the\n * default 12px tick font size. Sparse charts get no truncation; dense charts get aggressive\n * trimming so labels stop overlapping.\n *\n * Consumers can override the entire formatting via `xAxisTickFormatter` on either chart.\n */\nexport function maxTickCharsByCategoryCount(n: number): number {\n if (n <= 5) return 24; // effectively no truncation\n if (n <= 8) return 14;\n if (n <= 12) return 10;\n if (n <= 16) return 7;\n return 5;\n}\n\n/**\n * Truncates one label per the per-count cap. Trailing whitespace before the ellipsis is trimmed\n * so \"Human Resources\" with cap=7 becomes \"Human…\" not \"Human …\" (reads cleaner).\n */\nexport function truncateLabel(value: unknown, maxChars: number): string {\n const s = String(value ?? \"\");\n if (s.length <= maxChars) return s;\n return s.slice(0, Math.max(1, maxChars - 1)).trimEnd() + \"…\";\n}\n\n/**\n * Compact number format for y-axis ticks — `15000` → `15K`, `1500000` → `1.5M`. Keeps long\n * numeric tick labels inside the fixed `YAxis` width slot (~40px) so they stop clipping to\n * their trailing digits (\"15000\" rendering as \"0000\"). One shared instance so every chart\n * abbreviates identically. The tooltip still shows the full unformatted value on hover.\n *\n * Assumes axis values are integer-magnitude (≥ 1) — the use cases today are headcounts and\n * currency amounts. `maximumFractionDigits: 1` means sub-1 values round coarsely (`0.123` → `0.1`,\n * `0.005` → `0`), so this default is unsuitable for charts plotting rates / proportions in (0, 1).\n * Such a chart needs a dedicated formatter (a y-axis formatter prop is a planned follow-up).\n */\nconst compactNumberFormat = new Intl.NumberFormat(\"en-US\", { notation: \"compact\", maximumFractionDigits: 1 });\n\n/**\n * Default `tickFormatter` for numeric y-axes on `BarChart` / `LineChart`. Abbreviates large\n * magnitudes (thousands → `K`, millions → `M`) so labels fit the axis gutter. Non-numeric or\n * non-finite values pass through as their string form unchanged.\n */\nexport function compactNumberTickFormatter(value: unknown): string {\n if (value === null || value === undefined) return \"\";\n const n = typeof value === \"number\" ? value : Number(value);\n if (!Number.isFinite(n)) return String(value);\n return compactNumberFormat.format(n);\n}\n\n/**\n * Returns the set of data-point indices whose label should be visible. First and last always\n * included; the remaining (target - 2) are evenly distributed across the interior. Avoids the\n * \"cluster in the middle\" failure mode of recharts' built-in `preserveStartEnd`.\n *\n * Example for N=12, target=5: visible indices are {0, 3, 5, 8, 11} — 5 evenly-spaced labels.\n * Used by `LineChart` to thin x-axis labels at high data-point counts while keeping every data\n * point drawn.\n */\nexport function evenlyDistributedVisibleIndices(n: number, target: number): Set<number> {\n if (n <= target) {\n return new Set(Array.from({ length: n }, (_, i) => i));\n }\n const set = new Set<number>();\n const step = (n - 1) / (target - 1);\n for (let i = 0; i < target; i++) {\n set.add(Math.round(i * step));\n }\n return set;\n}\n\n/**\n * Per-category truncating formatter used as `BarChart`'s default `tickFormatter`. Every category\n * gets a label (no info loss from auto-skipping) but long labels get truncated by the\n * `maxTickCharsByCategoryCount` ladder so dense charts don't overlap.\n */\nexport function defaultBarTickFormatter(categoryCount: number): (value: unknown) => string {\n const max = maxTickCharsByCategoryCount(categoryCount);\n return (value) => truncateLabel(value, max);\n}\n\n/**\n * Per-index truncating formatter used as `LineChart`'s default `tickFormatter`. Returns the\n * (truncated) label only for indices in `visibleIndices`; the rest return `\"\"` so recharts\n * renders no text there. The data point itself still draws.\n *\n * Truncation is keyed by the *visible* tick count, not the total data-point count: LINE thins\n * its labels via `visibleIndices` (typically 5-7 visible ticks even at N=100+ data points), so\n * each rendered label has plenty of pixel room. Using `categoryCount` here would cap labels\n * like \"Dec 2022\" to 5 characters on a 50-month chart and clip them to \"Dec…\" even though only\n * ~5 ticks actually render. `BarChart` keeps using `categoryCount` because every category gets\n * a tick there — density really is data-point count.\n */\nexport function defaultLineChartTickFormatter(\n categoryCount: number,\n visibleIndices: Set<number>\n): (value: unknown, index: number) => string {\n const max = maxTickCharsByCategoryCount(visibleIndices.size || categoryCount);\n return (value, index) => {\n if (!visibleIndices.has(index)) return \"\";\n return truncateLabel(value, max);\n };\n}\n","/**\n * Returns a shallow copy of `rows` with the `numericKeys` columns coerced to `number`.\n * Cells that can't be parsed become `NaN`; `null` / `undefined` cells pass through untouched;\n * columns NOT in `numericKeys` pass through unchanged.\n *\n * Recharts needs `number` on `dataKey` resolution for `<Line>` / `<Bar>` / `<Pie>` — already-\n * numeric data is a no-op. The function exists for the CSV-derived case where values arrive\n * as strings. `NaN` propagates to recharts as a missing data point (zero-height bar, gap in\n * line, zero-area slice).\n */\nexport function coerceNumericColumns(\n rows: ReadonlyArray<Record<string, unknown>>,\n numericKeys: ReadonlyArray<string>\n): Array<Record<string, unknown>> {\n return rows.map((row) => {\n const out: Record<string, unknown> = { ...row };\n for (const k of numericKeys) {\n const v = out[k];\n if (v == null) continue;\n const n = Number(v);\n out[k] = Number.isFinite(n) ? n : NaN;\n }\n return out;\n });\n}\n","import { type ReactNode, useMemo } from \"react\";\nimport {\n CartesianGrid,\n LabelList,\n Legend,\n Line,\n LineChart as RechartsLineChart,\n Tooltip,\n XAxis,\n YAxis,\n} from \"recharts\";\n\nimport { ChartContainer } from \"../chart-container\";\nimport { ChartLegendContent } from \"../chart-legend-content\";\nimport { ChartTooltipContent } from \"../chart-tooltip-content\";\nimport { CHART_PALETTE, colorForSeriesIndex } from \"../chart-palette\";\nimport {\n CHART_AXIS_PROPS,\n CHART_GRID_PROPS,\n CHART_MARGIN,\n CHART_VALUE_LABEL_STYLE,\n LINE_ACTIVE_DOT_STROKE,\n} from \"../chart-styles\";\nimport {\n compactNumberTickFormatter,\n defaultLineChartTickFormatter,\n evenlyDistributedVisibleIndices,\n} from \"../chart-tick-utils\";\nimport { coerceNumericColumns } from \"../coerce-numeric\";\nimport type { ChartSeries } from \"../types\";\n\nexport interface LineChartProps {\n /** Rows to plot. Each row should carry the `xKey` column and one column per `series[].key`. */\n data: ReadonlyArray<Record<string, unknown>>;\n /** Data column for the categorical/temporal x-axis. */\n xKey: string;\n /** One descriptor per line series. */\n series: ChartSeries[];\n /** Render monotone-curve lines instead of straight segments. **Default true** — smooth\n * curves look cleaner for typical chat / dashboard usage. Pass `false` for true linear\n * interpolation (e.g. step-like data where the literal value at each point matters). */\n smooth?: boolean;\n /** Show data-point dots. **Default true** — dots anchor each bin of the line so the viewer\n * can read individual values at a glance. Pass `false` for a pure trend line (dense data sets\n * where dots would crowd, or styling preference for unembellished strokes). */\n showDots?: boolean;\n /** Line stroke width in px. Default 2. */\n strokeWidth?: number;\n /** Container height. Default 320. */\n height?: number | string;\n /** Container width. Default `\"100%\"`. */\n width?: number | string;\n /** Optional className on the outer container. */\n className?: string;\n /** Override the default palette. Colors are assigned by series index. */\n palette?: readonly string[];\n /** Show the tooltip on hover. Default true. */\n showTooltip?: boolean;\n /**\n * Show the legend at the top. **Default behavior**: auto-hidden for single-series charts\n * (the legend would just label the one and only color, which is noise). Pass `true` to force\n * the legend even with one series; pass `false` to suppress for multi-series.\n */\n showLegend?: boolean;\n /** Show horizontal dashed grid lines. Default true. */\n showGrid?: boolean;\n /** Show the x-axis. Default true. */\n showXAxis?: boolean;\n /** Show the y-axis. Default true. */\n showYAxis?: boolean;\n /**\n * Show numeric value labels next to each data point. **Default off** — for line charts with\n * many data points (12+ months × N series) labels overlap quickly. Set `true` for single-series\n * charts with sparse data (e.g. ≤8 points) where the labels stay readable.\n */\n showValueLabels?: boolean;\n /**\n * Recharts XAxis tick `interval`. **Default**: `0` (every tick rendered) — clay's tick\n * formatter blanks out non-key labels so the visible labels stay evenly distributed.\n * Override to a fixed number to force \"every Nth label\", or to a recharts string preset\n * like `\"preserveStartEnd\"` to let recharts pick.\n */\n xAxisInterval?: number | \"preserveStart\" | \"preserveEnd\" | \"preserveStartEnd\";\n /**\n * Rotate x-axis tick labels by this many degrees. Negative values tilt up-and-right (e.g.\n * `-30`). Default `0`. When non-zero, the chart auto-bumps its bottom margin.\n */\n xAxisAngle?: number;\n /**\n * Custom formatter for x-axis tick labels. **Default**: clay shows only ~5 evenly-distributed\n * labels (first + last + ~3 middle), and auto-truncates each shown label so dense datasets\n * stay readable. Pass an explicit formatter to override the per-label rendering — to also\n * change which labels are visible, pass `xAxisInterval` and a formatter that returns the\n * value for every index.\n *\n * The tooltip continues to show the full unformatted value on hover regardless.\n */\n xAxisTickFormatter?: (value: unknown) => string;\n}\n\n/**\n * Target visible x-axis label count for line charts. Recharts' built-in `preserveStartEnd`\n * picks labels by collision detection, which produces uneven clusters when label widths vary.\n * Picking a fixed target and distributing evenly gives a cleaner result and the same value at\n * any chart width (the chart still shows every data point as a dot — only labels thin out).\n */\nconst TARGET_VISIBLE_LABELS = 5;\n\n/**\n * Pre-composed line chart. Single-call usage for the common case; for custom recharts trees\n * compose `<ChartContainer>` + recharts primitives directly.\n *\n * ```tsx\n * <LineChart\n * data={[{ month: \"Jan\", value: 120 }, { month: \"Feb\", value: 132 }]}\n * xKey=\"month\"\n * series={[{ key: \"value\", label: \"Headcount\" }]}\n * smooth\n * />\n * ```\n *\n * **Smart defaults**: legend auto-hides for single-series; value labels default off (turn on\n * for sparse single-series charts); x-axis shows every tick by default.\n */\nexport function LineChart({\n data,\n xKey,\n series,\n smooth = true,\n showDots = true,\n strokeWidth = 2,\n height = 320,\n width = \"100%\",\n className,\n palette = CHART_PALETTE,\n showTooltip = true,\n showLegend,\n showGrid = true,\n showXAxis = true,\n showYAxis = true,\n showValueLabels = false,\n xAxisInterval = 0,\n xAxisAngle = 0,\n xAxisTickFormatter,\n}: LineChartProps): ReactNode {\n const seriesKeys = useMemo(() => series.map((s) => s.key), [series]);\n // Memoised so non-artifact consumers passing inline `data` arrays don't re-allocate the\n // coerced copy on every parent render.\n const coercedData = useMemo(\n () => coerceNumericColumns(data as ReadonlyArray<Record<string, unknown>>, seriesKeys),\n [data, seriesKeys]\n );\n const lineType = smooth ? \"monotone\" : \"linear\";\n\n const resolvedShowLegend = showLegend ?? series.length > 1;\n // Default: only ~5 evenly distributed labels are visible (first + last + middle), each\n // truncated to fit. Consumer can override with `xAxisTickFormatter` (their formatter is\n // applied to every label without thinning). See `defaultLineChartTickFormatter`.\n const resolvedTickFormatter = useMemo(() => {\n if (xAxisTickFormatter) return xAxisTickFormatter;\n const visible = evenlyDistributedVisibleIndices(coercedData.length, TARGET_VISIBLE_LABELS);\n return defaultLineChartTickFormatter(coercedData.length, visible);\n }, [xAxisTickFormatter, coercedData.length]);\n const angledLabelPad = xAxisAngle === 0 ? 0 : Math.min(Math.abs(xAxisAngle) * 0.7, 40);\n // Extra right margin so the rightmost x-axis tick label has room to render its right half\n // without getting clipped at the chart edge. Recharts centres tick labels under their tick;\n // without padding, ~half of the last label spills past the plot area.\n const chartMargin = { ...CHART_MARGIN, right: CHART_MARGIN.right + 16, bottom: CHART_MARGIN.bottom + angledLabelPad };\n\n return (\n <ChartContainer height={height} width={width} className={className}>\n <RechartsLineChart data={coercedData} margin={chartMargin}>\n {showGrid ? <CartesianGrid {...CHART_GRID_PROPS} /> : null}\n {showXAxis ? (\n <XAxis\n dataKey={xKey}\n {...CHART_AXIS_PROPS}\n interval={xAxisInterval}\n angle={xAxisAngle}\n textAnchor={xAxisAngle !== 0 ? \"end\" : \"middle\"}\n tickMargin={xAxisAngle === 0 ? 8 : 12}\n height={xAxisAngle !== 0 ? 60 : undefined}\n tickFormatter={resolvedTickFormatter}\n />\n ) : null}\n {showYAxis ? <YAxis {...CHART_AXIS_PROPS} width={40} tickFormatter={compactNumberTickFormatter} /> : null}\n {showTooltip ? <Tooltip content={<ChartTooltipContent />} /> : null}\n {resolvedShowLegend ? (\n <Legend\n verticalAlign=\"top\"\n align=\"center\"\n // Pin the absolutely-positioned wrapper flush to the chart's top edge — see `BarChart`\n // for the rationale.\n wrapperStyle={{ top: 0 }}\n // Preserve declaration order; disable recharts 3.x's `'value'` alphabetical sort.\n // See `BarChart` for the rationale.\n itemSorter={null}\n content={<ChartLegendContent iconType=\"line\" />}\n />\n ) : null}\n {series.map((s, i) => {\n const color = colorForSeriesIndex(i, palette);\n return (\n <Line\n key={s.key}\n type={lineType}\n dataKey={s.key}\n name={s.label}\n stroke={color}\n strokeWidth={strokeWidth}\n // Filled dot matching the line color — recharts default is hollow (white fill +\n // colored stroke), which reads as \"annotation\" rather than \"data point\".\n dot={showDots ? { r: 3, fill: color, stroke: color, strokeWidth: 0 } : false}\n activeDot={{ r: 5, fill: color, stroke: LINE_ACTIVE_DOT_STROKE, strokeWidth: 2 }}\n >\n {showValueLabels ? <LabelList dataKey={s.key} position=\"top\" style={CHART_VALUE_LABEL_STYLE} /> : null}\n </Line>\n );\n })}\n </RechartsLineChart>\n </ChartContainer>\n );\n}\n","import { type ReactNode, useMemo } from \"react\";\nimport { Cell, Legend, Pie, PieChart as RechartsPieChart, Tooltip } from \"recharts\";\n\nimport { ChartContainer } from \"../chart-container\";\nimport { ChartLegendContent } from \"../chart-legend-content\";\nimport { ChartTooltipContent } from \"../chart-tooltip-content\";\nimport { CHART_PALETTE, DEFAULT_OTHERS_CATEGORY_LABELS } from \"../chart-palette\";\nimport { CHART_VALUE_LABEL_STYLE, PIE_CHART_MARGIN } from \"../chart-styles\";\nimport { coerceNumericColumns } from \"../coerce-numeric\";\nimport { buildPieSlices } from \"./utils\";\n\n/**\n * Recharts injects geometric position props onto label render functions. Typed locally because\n * recharts' `PieLabelProps` is overly tagged-generic.\n */\ninterface PieLabelRenderProps {\n /** Computed x coordinate for the label (outside the slice). */\n x?: number;\n /** Computed y coordinate for the label. */\n y?: number;\n /** \"start\" / \"middle\" / \"end\" / \"inherit\" — pre-computed for legibility outside the slice. */\n textAnchor?: \"start\" | \"middle\" | \"end\" | \"inherit\";\n /** The slice's numeric value (the value of `valueKey` on the row). */\n value?: unknown;\n}\n\nexport interface PieChartProps {\n /** Rows to plot. Each row maps to one slice. */\n data: ReadonlyArray<Record<string, unknown>>;\n /** Data column used as the slice label / legend entry. */\n categoryKey: string;\n /** Data column used as the slice numeric value. */\n valueKey: string;\n /** Container height. Default 320. */\n height?: number | string;\n /** Container width. Default `\"100%\"`. */\n width?: number | string;\n /** Optional className on the outer container. */\n className?: string;\n /** Override the default palette. Default `CHART_PALETTE` — the shared blue + indigo graduated\n * palette every chart variant uses. Override per-instance for brand-specific colours. */\n palette?: readonly string[];\n /** Show value labels next to each slice. Default true. */\n showLabels?: boolean;\n /** Show the tooltip on hover. Default true. */\n showTooltip?: boolean;\n /** Show the legend (category names). Default true. Position controlled by `legendPosition`. */\n showLegend?: boolean;\n /** Inner radius — `0` (default) for a pie; `>0` (e.g. `\"40%\"`) for a donut. */\n innerRadius?: number | string;\n /** Outer radius. Default `\"68%\"` — leaves room for outside value labels. */\n outerRadius?: number | string;\n /**\n * Category labels treated as the \"Others\" bucket (case-insensitive match). Matching slices are\n * pinned to the end of the sweep regardless of value and rendered in neutral grey\n * (`OTHERS_SLICE_COLOR`).\n *\n * **Default**: `DEFAULT_OTHERS_CATEGORY_LABELS` (English \"Others\" / \"Other\"). Pass a localized\n * list in non-English UIs — e.g. `[\"אחרים\"]` for Hebrew or `[\"Otros\", \"Otro\"]` for Spanish.\n * Pass `[]` to disable Others detection entirely (every slice colored from the palette).\n */\n othersCategoryLabels?: readonly string[];\n}\n\n/**\n * Pre-composed pie chart. One slice per row, colored by row index from the palette. Outside\n * value labels (no connector line); legend at the top. Set `innerRadius` to make a donut.\n *\n * **Sweep**: starts at 12 o'clock and proceeds clockwise (`startAngle={90}` / `endAngle={-270}`).\n * Recharts' default starts at 3 o'clock counter-clockwise, which feels arbitrary for a\n * data-first composition.\n *\n * **\"Others\" bucket**: explicit \"Others\" / \"Other\" categories (case-insensitive) *and*\n * missing-value categories (`null` / `\"\"` / `\"(none)\"` / …) are summed into a single neutral-grey\n * slice pinned to the end of the sweep, so they read as \"unattributed leftover\" rather than peer\n * categories. A `\"(none)\"` row therefore collapses *into* \"Other\" instead of standing alone.\n * Named slices retain their incoming order and palette colors. See `buildPieSlices`.\n *\n * ```tsx\n * <PieChart\n * data={[\n * { department: \"Engineering\", headcount: 42 },\n * { department: \"Sales\", headcount: 18 },\n * { department: \"Others\", headcount: 5 },\n * ]}\n * categoryKey=\"department\"\n * valueKey=\"headcount\"\n * />\n *\n * // Donut variant\n * <PieChart data={...} categoryKey=\"...\" valueKey=\"...\" innerRadius=\"40%\" />\n * ```\n */\nexport function PieChart({\n data,\n categoryKey,\n valueKey,\n height = 320,\n width = \"100%\",\n className,\n palette = CHART_PALETTE,\n showLabels = true,\n showTooltip = true,\n showLegend = true,\n innerRadius = 0,\n outerRadius = \"68%\",\n othersCategoryLabels = DEFAULT_OTHERS_CATEGORY_LABELS,\n}: PieChartProps): ReactNode {\n // Memoised so non-artifact consumers passing inline `data` arrays don't re-allocate the\n // coerced + bucketed copy on every parent render. Coerce the `valueKey` column to numeric\n // (CSV-derived rows arrive as strings), then partition into named slices + one merged grey\n // \"Others\" slice (explicit \"Others\"/\"Other\" and missing-value rows collapse together). See\n // `buildPieSlices`.\n const { orderedData, sliceColors } = useMemo(() => {\n const coerced = coerceNumericColumns(data as ReadonlyArray<Record<string, unknown>>, [valueKey]);\n return buildPieSlices(coerced, categoryKey, valueKey, othersCategoryLabels, palette);\n }, [data, valueKey, categoryKey, othersCategoryLabels, palette]);\n\n return (\n <ChartContainer height={height} width={width} className={className}>\n <RechartsPieChart margin={PIE_CHART_MARGIN}>\n {showTooltip ? <Tooltip content={<ChartTooltipContent />} /> : null}\n {showLegend ? (\n <Legend\n verticalAlign=\"top\"\n align=\"center\"\n // Pin the absolutely-positioned wrapper flush to the chart's top edge — see `BarChart`\n // for the rationale.\n wrapperStyle={{ top: 0 }}\n // Preserve slice order; disable recharts 3.x's `'value'` alphabetical sort. Critical\n // for pie because the Others bucket is intentionally pinned to the end of the sweep\n // — sorting alphabetically would break that contract.\n itemSorter={null}\n content={<ChartLegendContent iconType=\"square\" />}\n />\n ) : null}\n <Pie\n data={orderedData}\n dataKey={valueKey}\n nameKey={categoryKey}\n cx=\"50%\"\n cy=\"52%\"\n // Start at 12 o'clock and sweep clockwise. Recharts' default (`0` / `360`) starts at\n // 3 o'clock counter-clockwise. The +90 / -270 pair preserves the full 360° arc length.\n startAngle={90}\n endAngle={-270}\n innerRadius={innerRadius}\n outerRadius={outerRadius}\n label={\n showLabels\n ? (entry: PieLabelRenderProps) => {\n const v = entry.value;\n if (v === undefined || v === null) return null;\n // Render the label as a `<text>` so we can pin its `fill` to the shared\n // `CHART_VALUE_LABEL_STYLE` instead of letting recharts auto-color it to\n // the slice's fill (which on light-blue slices becomes near-invisible).\n // Recharts passes the computed `x`/`y`/`textAnchor` so positioning is\n // unchanged.\n return (\n <text\n x={entry.x}\n y={entry.y}\n fill={CHART_VALUE_LABEL_STYLE.fill}\n fontSize={CHART_VALUE_LABEL_STYLE.fontSize}\n fontWeight={CHART_VALUE_LABEL_STYLE.fontWeight}\n textAnchor={entry.textAnchor}\n dominantBaseline=\"central\"\n >\n {String(v)}\n </text>\n );\n }\n : false\n }\n // No connector line — outside labels sit clean next to their slice. The thin\n // brown line between slice and label adds visual noise without information gain.\n labelLine={false}\n // No stroke between slices — gradient palette + adjacent contiguous segments read\n // as one continuous wheel rather than discrete cards with cream gaps between them.\n stroke=\"none\"\n strokeWidth={0}\n >\n {orderedData.map((_row, i) => (\n <Cell key={i} fill={sliceColors[i]} />\n ))}\n </Pie>\n </RechartsPieChart>\n </ChartContainer>\n );\n}\n","import {\n OTHERS_SLICE_COLOR,\n colorForSeriesIndex,\n isNoneCategory,\n isOthersCategory,\n} from \"../chart-palette\";\n\n/**\n * Result of partitioning pie rows into palette-colored named slices plus one merged grey\n * \"Others\" slice.\n */\nexport interface PieSlices {\n /** Rows in render order — named slices first, the merged Others slice (if any) last. */\n orderedData: Record<string, unknown>[];\n /** Per-slice fill color, index-aligned to `orderedData`. */\n sliceColors: string[];\n}\n\n/**\n * Display label for the merged Others slice. Prefers an explicit \"Others\"/\"Other\" row's own\n * label (keeps a localized bucket name as the agent wrote it); falls back to the first configured\n * others label, capitalized, when only missing-value rows were folded in.\n *\n * @param leftoverRows - Rows being merged into the Others bucket.\n * @param categoryKey - Column holding each row's category label.\n * @param othersCategoryLabels - Configured \"Others\" match labels.\n * @returns The label to render on the merged slice.\n */\nfunction mergedOthersLabel(\n leftoverRows: ReadonlyArray<Record<string, unknown>>,\n categoryKey: string,\n othersCategoryLabels: readonly string[]\n): string {\n const explicit = leftoverRows.find((row) => isOthersCategory(row[categoryKey], othersCategoryLabels));\n if (explicit) return String(explicit[categoryKey]);\n const fallback = othersCategoryLabels[0] ?? \"Other\";\n return fallback.charAt(0).toUpperCase() + fallback.slice(1);\n}\n\n/**\n * Partitions pie rows into named slices and a single merged \"Others\" slice.\n *\n * - **Named slices** keep their incoming order and are colored by their *named-slice index* (not\n * their position in the output), so adding/removing a leftover row never shifts a named\n * category's color.\n * - **Leftover rows** — explicit \"Others\"/\"Other\" categories *and* missing-value categories\n * (`null` / `\"\"` / `\"(none)\"` / …) — are summed into one grey slice pinned to the end of the\n * sweep. This collapses `\"(none)\"` *into* \"Other\" rather than rendering it as a peer grey slice.\n * - Bucketing is gated on `othersCategoryLabels` being non-empty; pass `[]` to render every row as\n * a palette-colored peer (no Others/none folding).\n *\n * @param data - Rows with the value column already coerced to numeric.\n * @param categoryKey - Column holding each slice's category label.\n * @param valueKey - Column holding each slice's numeric value.\n * @param othersCategoryLabels - \"Others\" match labels; `[]` disables bucketing.\n * @param palette - Ordered colors assigned to named slices by index.\n * @returns Render-ordered rows and their index-aligned fill colors.\n */\nexport function buildPieSlices(\n data: ReadonlyArray<Record<string, unknown>>,\n categoryKey: string,\n valueKey: string,\n othersCategoryLabels: readonly string[],\n palette: readonly string[]\n): PieSlices {\n const namedRows: Record<string, unknown>[] = [];\n const namedColors: string[] = [];\n const leftoverRows: Record<string, unknown>[] = [];\n\n for (const row of data) {\n const isLeftover =\n othersCategoryLabels.length > 0 &&\n (isNoneCategory(row[categoryKey]) || isOthersCategory(row[categoryKey], othersCategoryLabels));\n if (isLeftover) {\n leftoverRows.push(row);\n } else {\n namedRows.push(row);\n namedColors.push(colorForSeriesIndex(namedRows.length - 1, palette));\n }\n }\n\n if (leftoverRows.length === 0) {\n return { orderedData: namedRows, sliceColors: namedColors };\n }\n\n const total = leftoverRows.reduce((sum, row) => sum + (Number(row[valueKey]) || 0), 0);\n const mergedRow: Record<string, unknown> = {\n [categoryKey]: mergedOthersLabel(leftoverRows, categoryKey, othersCategoryLabels),\n [valueKey]: total,\n };\n\n return {\n orderedData: [...namedRows, mergedRow],\n sliceColors: [...namedColors, OTHERS_SLICE_COLOR],\n };\n}\n"],"mappings":"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","names":["import_recharts","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","RechartsBarChart","import_react","import_recharts","import_jsx_runtime","RechartsLineChart","import_react","import_recharts","import_jsx_runtime","RechartsPieChart"]}
|
package/dist/chart.js
CHANGED
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
PieChart,
|
|
11
11
|
coerceNumericColumns,
|
|
12
12
|
colorForSeriesIndex
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-G4NXVFXU.js";
|
|
14
14
|
import "./chunk-C77QMQNT.js";
|
|
15
15
|
import "./chunk-UXT2H3FM.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-SN3ORQSJ.js";
|
|
17
17
|
import "./chunk-P6GUNIAE.js";
|
|
18
18
|
import "./chunk-5WRI5ZAA.js";
|
|
19
19
|
export {
|