@qumra/fanar 0.0.13 → 0.0.15

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.
@@ -0,0 +1,392 @@
1
+ import * as react from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ /** Series color, drawn from Qumra's semantic tokens — never a literal. */
5
+ type ChartTone = 'brand' | 'amber' | 'violet' | 'green' | 'red' | 'mint' | 'muted';
6
+ /**
7
+ * The default series order.
8
+ *
9
+ * Six tones, then it cycles. Adjacent entries are far apart in hue so a
10
+ * reader never has to check the legend to tell two neighbouring series
11
+ * apart.
12
+ */
13
+ declare const SERIES_ORDER: readonly ChartTone[];
14
+ /** Resolves a tone to the CSS custom property that carries it. */
15
+ declare function toneColor(tone: ChartTone): string;
16
+ /** The tone at a given series index, cycling through {@link SERIES_ORDER}. */
17
+ declare function toneAt(index: number): ChartTone;
18
+ /**
19
+ * `true` when the page reads right-to-left.
20
+ *
21
+ * Read from `<html dir>` in the browser, and derived from the display
22
+ * locale on the server so the first paint matches the hydrated one.
23
+ */
24
+ declare function useRtl(): boolean;
25
+
26
+ /** One row of chart data — the x key plus a numeric field per series. */
27
+ type ChartRow = Record<string, string | number | null | undefined>;
28
+ /** A single plotted series: which field to read, what to call it, what colour. */
29
+ interface ChartSeries {
30
+ /** Field name in each row. */
31
+ key: string;
32
+ /** Shown in the legend and the tooltip. Falls back to `key`. */
33
+ label?: string;
34
+ /** Token-backed colour. Defaults to the series order. */
35
+ tone?: ChartTone;
36
+ /**
37
+ * Series sharing a `stackId` are stacked on top of each other.
38
+ *
39
+ * Stack only parts of one whole — revenue split by channel, not two
40
+ * independent totals. Stacking hides that one part fell while another
41
+ * rose, so the reader sees a flat total and no cause.
42
+ */
43
+ stackId?: string;
44
+ }
45
+ /**
46
+ * How the horizontal axis is read.
47
+ *
48
+ * `category` flips with page direction — a category is text and follows
49
+ * the page. `time` never flips: start is left and end is right in every
50
+ * language, the same axis `TrendChart`, `Scrubber` and the media players
51
+ * already draw.
52
+ */
53
+ type ChartAxis = 'category' | 'time';
54
+ /** Props every cartesian chart in this entry point accepts. */
55
+ interface BaseChartProps {
56
+ /** The rows to plot. An empty array renders the empty state. */
57
+ data: ChartRow[];
58
+ /** Field holding the axis label of each row. */
59
+ x: string;
60
+ /** What to plot. One entry per line, area or bar group. */
61
+ series: ChartSeries[];
62
+ /** Plot height in pixels. Width always fills the parent. */
63
+ height?: number;
64
+ /**
65
+ * Accessible name — **required**.
66
+ *
67
+ * The chart is announced as one image, so this sentence is everything a
68
+ * screen reader gets: say the measure and the span ("Revenue, Jan to
69
+ * Dec"), not the shape ("bar chart").
70
+ */
71
+ label: string;
72
+ /** Formats values in the tooltip. Defaults to the page locale. */
73
+ formatValue?: (value: number) => string;
74
+ /** Formats the axis ticks. Defaults to a compact locale number. */
75
+ formatAxis?: (value: number) => string;
76
+ /** Formats the x tick label. */
77
+ formatX?: (value: string | number) => string;
78
+ /** Horizontal axis semantics. See {@link ChartAxis}. */
79
+ axis?: ChartAxis;
80
+ /** Horizontal rules behind the plot. On by default. */
81
+ grid?: boolean;
82
+ /** Series key below the plot. On when there is more than one series. */
83
+ legend?: boolean;
84
+ /** Shown instead of the plot when `data` is empty. */
85
+ empty?: ReactNode;
86
+ className?: string;
87
+ }
88
+ declare function ChartEmpty({ height, children }: {
89
+ height: number;
90
+ children?: ReactNode;
91
+ }): react.JSX.Element;
92
+ declare function ChartFrame({ label, height, empty, isEmpty, className, children, }: {
93
+ label: string;
94
+ height: number;
95
+ empty?: ReactNode;
96
+ isEmpty: boolean;
97
+ className?: string;
98
+ children: ReactNode;
99
+ }): react.JSX.Element;
100
+
101
+ interface BarChartProps extends BaseChartProps {
102
+ /**
103
+ * `columns` stands the bars up (the default), `rows` lays them down.
104
+ *
105
+ * Use `rows` when the category labels are words — a name reads on one
106
+ * line beside its bar instead of being tilted under it.
107
+ */
108
+ bars?: 'columns' | 'rows';
109
+ }
110
+ /**
111
+ * Bars — for comparing a handful of periods or categories.
112
+ *
113
+ * Series sit side by side unless they share a `stackId`.
114
+ */
115
+ declare function BarChart({ data, x, series, bars, height, label, formatValue, formatAxis, formatX, axis, grid, legend, empty, className, }: BarChartProps): react.JSX.Element;
116
+ interface LineChartProps extends BaseChartProps {
117
+ /** Draws a dot at every data point. Off by default — noise past ~30 points. */
118
+ dots?: boolean;
119
+ /** Straight segments instead of a smoothed curve. */
120
+ straight?: boolean;
121
+ }
122
+ /**
123
+ * A line — for a measure moving through time.
124
+ *
125
+ * The horizontal axis defaults to `time`, so it does **not** flip in
126
+ * Arabic: earlier is always to the left.
127
+ */
128
+ declare function LineChart({ data, x, series, height, label, formatValue, formatAxis, formatX, axis, grid, legend, dots, straight, empty, className, }: LineChartProps): react.JSX.Element;
129
+ /**
130
+ * An area — a line whose fill carries the size of the total.
131
+ *
132
+ * Reach for it when the reader should feel volume, not only direction.
133
+ * With more than two series stack them: overlapping translucent fills
134
+ * turn into a colour nobody can trace back to a series.
135
+ */
136
+ declare function AreaChart({ data, x, series, height, label, formatValue, formatAxis, formatX, axis, grid, legend, empty, className, }: BaseChartProps): react.JSX.Element;
137
+ /** A series in a {@link ComposedChart}, with the shape it is drawn as. */
138
+ interface ComposedSeries extends ChartSeries {
139
+ /** How this series is drawn. Defaults to `bar`. */
140
+ as?: 'bar' | 'line' | 'area';
141
+ /**
142
+ * Which vertical scale this series is measured on.
143
+ *
144
+ * `secondary` puts it on its own axis at the opposite edge — the point
145
+ * of a composed chart. 412 orders and 88,000 pounds on one scale flatten
146
+ * the bars into a line along zero: both series are drawn, and only one
147
+ * can be read.
148
+ */
149
+ scale?: 'primary' | 'secondary';
150
+ }
151
+ interface ComposedChartProps extends Omit<BaseChartProps, 'series'> {
152
+ series: ComposedSeries[];
153
+ }
154
+ /**
155
+ * Bars and lines on one pair of axes.
156
+ *
157
+ * The pairing carries a meaning the shapes alone do not: bars are the
158
+ * counted thing (orders, units) and the line is the rate read against
159
+ * them (conversion, average value). Two bar series would say the same as
160
+ * a grouped `BarChart`, so reach for that instead.
161
+ */
162
+ declare function ComposedChart({ data, x, series, height, label, formatValue, formatAxis, formatX, axis, grid, legend, empty, className, }: ComposedChartProps): react.JSX.Element;
163
+ /** One point in a {@link ScatterChart}. `z` sizes the dot when present. */
164
+ interface ScatterPoint {
165
+ x: number;
166
+ y: number;
167
+ z?: number;
168
+ [key: string]: string | number | undefined;
169
+ }
170
+ /** A named, coloured group of scatter points. */
171
+ interface ScatterGroup {
172
+ key: string;
173
+ label?: string;
174
+ tone?: ChartTone;
175
+ points: ScatterPoint[];
176
+ }
177
+ interface ScatterChartProps {
178
+ groups: ScatterGroup[];
179
+ height?: number;
180
+ label: string;
181
+ /** Axis names, shown on the axes and in the tooltip. */
182
+ xLabel?: string;
183
+ yLabel?: string;
184
+ formatValue?: (value: number) => string;
185
+ formatAxis?: (value: number) => string;
186
+ grid?: boolean;
187
+ legend?: boolean;
188
+ empty?: React.ReactNode;
189
+ className?: string;
190
+ }
191
+ /**
192
+ * Scattered points — for the relation between two measures.
193
+ *
194
+ * It answers a different question from every other chart here: not "how
195
+ * did this move" but "do these two move together" — price against units
196
+ * sold, discount against return rate.
197
+ */
198
+ declare function ScatterChart({ groups, height, label, xLabel, yLabel, formatValue, formatAxis, grid, legend, empty, className, }: ScatterChartProps): react.JSX.Element;
199
+ interface SparklineProps {
200
+ /** The values, oldest first. */
201
+ values: number[];
202
+ /** Accessible name — the sparkline carries no axis to read instead. */
203
+ label: string;
204
+ /**
205
+ * A name per point — a date, an hour.
206
+ *
207
+ * Passing them turns on the tooltip, and that is the only thing that
208
+ * does. Without them a tooltip would read "95" with nothing to say
209
+ * ninety-five *of when* — which is the half the plot already draws.
210
+ */
211
+ labels?: string[];
212
+ /** Formats the value in the tooltip. Defaults to the page locale. */
213
+ formatValue?: (value: number) => string;
214
+ tone?: ChartTone;
215
+ height?: number;
216
+ /** Fills under the line. */
217
+ filled?: boolean;
218
+ className?: string;
219
+ }
220
+ /**
221
+ * A bare line — shape, with no axes and no legend.
222
+ *
223
+ * It belongs beside a number that already carries the value: the figure
224
+ * says how much, the sparkline says which way. Alone it says neither, so
225
+ * it is never the whole of a card.
226
+ */
227
+ declare function Sparkline({ values, label, labels, formatValue, tone, height, filled, className, }: SparklineProps): react.JSX.Element | null;
228
+
229
+ /** One slice: a name, a number, and optionally a token colour. */
230
+ interface SliceItem {
231
+ key: string;
232
+ label?: string;
233
+ value: number;
234
+ tone?: ChartTone;
235
+ }
236
+ interface PieChartProps {
237
+ items: SliceItem[];
238
+ height?: number;
239
+ /** Accessible name — required, the slices carry no axis to read instead. */
240
+ label: string;
241
+ formatValue?: (value: number) => string;
242
+ legend?: boolean;
243
+ empty?: React.ReactNode;
244
+ className?: string;
245
+ }
246
+ interface DonutChartProps extends PieChartProps {
247
+ /** Big number in the hole. Defaults to the sum of the slices. */
248
+ centerValue?: React.ReactNode;
249
+ /** Caption under the centre number. */
250
+ centerLabel?: React.ReactNode;
251
+ }
252
+ /**
253
+ * A pie — for a part of one whole, with few slices.
254
+ *
255
+ * Prefer `ShareList` when the categories are ranked or numerous: order is
256
+ * itself information, and a list keeps it.
257
+ */
258
+ declare function PieChart({ items, height, label, formatValue, legend, empty, className, }: PieChartProps): react.JSX.Element;
259
+ /**
260
+ * A donut — a pie whose hole carries the total.
261
+ *
262
+ * The default centre is the sum of the slices, which is the number the
263
+ * parts add up to; pass `centerValue` when the whole is something else
264
+ * (a target, a previous period).
265
+ */
266
+ declare function DonutChart({ items, height, label, formatValue, legend, centerValue, centerLabel, empty, className, }: DonutChartProps): react.JSX.Element;
267
+ interface RadarChartProps {
268
+ /** One row per axis — the axis name plus a value per series. */
269
+ data: Record<string, string | number>[];
270
+ /** Field holding each row's axis name. */
271
+ x: string;
272
+ series: ChartSeries[];
273
+ height?: number;
274
+ label: string;
275
+ formatValue?: (value: number) => string;
276
+ legend?: boolean;
277
+ empty?: React.ReactNode;
278
+ className?: string;
279
+ }
280
+ /**
281
+ * A radar — one subject measured on several axes at once.
282
+ *
283
+ * It compares **profiles**, not amounts: two overlaid shapes show where a
284
+ * branch is strong and where it is thin. The axes must share a scale, or
285
+ * the shape means nothing.
286
+ */
287
+ declare function RadarChart({ data, x, series, height, label, formatValue, legend, empty, className, }: RadarChartProps): react.JSX.Element;
288
+ interface RadialChartProps {
289
+ items: SliceItem[];
290
+ /**
291
+ * The value a full ring stands for.
292
+ *
293
+ * Without it the largest item fills the ring, and every reading becomes
294
+ * relative to whichever item happens to lead — so a bad month looks the
295
+ * same as a good one.
296
+ */
297
+ max?: number;
298
+ height?: number;
299
+ label: string;
300
+ formatValue?: (value: number) => string;
301
+ legend?: boolean;
302
+ empty?: React.ReactNode;
303
+ className?: string;
304
+ }
305
+ /**
306
+ * Radial bars — progress towards a target, one ring per item.
307
+ *
308
+ * Read it as a set of gauges, not as a comparison: arc length grows with
309
+ * radius, so the outer ring looks larger at equal value. Keep it to a few
310
+ * items with a shared `max`.
311
+ */
312
+ declare function RadialChart({ items, max, height, label, formatValue, legend, empty, className, }: RadialChartProps): react.JSX.Element;
313
+
314
+ /** One funnel stage, in order. */
315
+ interface FunnelStep {
316
+ key: string;
317
+ label?: string;
318
+ value: number;
319
+ tone?: ChartTone;
320
+ }
321
+ interface FunnelChartProps {
322
+ steps: FunnelStep[];
323
+ height?: number;
324
+ label: string;
325
+ formatValue?: (value: number) => string;
326
+ /** Shows each stage's share of the first one on its band. */
327
+ showRate?: boolean;
328
+ empty?: React.ReactNode;
329
+ className?: string;
330
+ }
331
+ /**
332
+ * A funnel — how many survive each step of a journey.
333
+ *
334
+ * The bands flip with page direction: the steps are named in words, and
335
+ * words follow the page.
336
+ */
337
+ declare function FunnelChart({ steps, height, label, formatValue, showRate, empty, className, }: FunnelChartProps): react.JSX.Element;
338
+ /** One rectangle. Nest with `children` for a two-level map. */
339
+ interface TreemapNode {
340
+ name: string;
341
+ value?: number;
342
+ tone?: ChartTone;
343
+ children?: TreemapNode[];
344
+ [key: string]: unknown;
345
+ }
346
+ interface TreemapChartProps {
347
+ nodes: TreemapNode[];
348
+ height?: number;
349
+ label: string;
350
+ formatValue?: (value: number) => string;
351
+ empty?: React.ReactNode;
352
+ className?: string;
353
+ }
354
+ /**
355
+ * A treemap — area stands for share, inside a fixed box.
356
+ *
357
+ * It holds far more categories than a pie without turning into slivers,
358
+ * which is what makes it right for a long tail: a hundred products where
359
+ * five matter. Exact comparison is not its job — reading two rectangles
360
+ * of similar area is guesswork, so pair it with a number.
361
+ */
362
+ declare function TreemapChart({ nodes, height, label, formatValue, empty, className, }: TreemapChartProps): react.JSX.Element;
363
+ interface SankeyNode {
364
+ name: string;
365
+ }
366
+ interface SankeyLink {
367
+ /** Index into `nodes`. */
368
+ source: number;
369
+ /** Index into `nodes`. */
370
+ target: number;
371
+ value: number;
372
+ }
373
+ interface SankeyChartProps {
374
+ nodes: SankeyNode[];
375
+ links: SankeyLink[];
376
+ height?: number;
377
+ label: string;
378
+ formatValue?: (value: number) => string;
379
+ empty?: React.ReactNode;
380
+ className?: string;
381
+ }
382
+ /**
383
+ * A flow diagram — where a quantity splits and where it ends up.
384
+ *
385
+ * Use it when the same total travels through stages and the reader needs
386
+ * the branches: visits arriving by source, then landing on a page, then
387
+ * ordering or leaving. For a single path with no branching a funnel says
388
+ * the same thing in less space.
389
+ */
390
+ declare function SankeyChart({ nodes, links, height, label, formatValue, empty, className, }: SankeyChartProps): react.JSX.Element;
391
+
392
+ export { AreaChart, BarChart, type BarChartProps, type BaseChartProps, type ChartAxis, ChartEmpty, ChartFrame, type ChartRow, type ChartSeries, type ChartTone, ComposedChart, type ComposedChartProps, type ComposedSeries, DonutChart, type DonutChartProps, FunnelChart, type FunnelChartProps, type FunnelStep, LineChart, type LineChartProps, PieChart, type PieChartProps, RadarChart, type RadarChartProps, RadialChart, type RadialChartProps, SERIES_ORDER, SankeyChart, type SankeyChartProps, type SankeyLink, type SankeyNode, ScatterChart, type ScatterChartProps, type ScatterGroup, type ScatterPoint, type SliceItem, Sparkline, type SparklineProps, TreemapChart, type TreemapChartProps, type TreemapNode, toneAt, toneColor, useRtl };
package/dist/charts.js ADDED
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ import{TOKENS,cn,useMoneyLocale,useUIText}from"./chunk-N7CZXHOG.js";import"react";import{CartesianGrid,Legend,ResponsiveContainer,Tooltip,XAxis,YAxis}from"recharts";import{useCallback,useSyncExternalStore}from"react";var VAR={brand:"var(--color-brand)",amber:"var(--color-amber)",violet:"var(--color-violet)",green:"var(--color-green)",red:"var(--color-red)",mint:"var(--color-mint)",muted:"var(--color-brand-100)"};var SERIES_ORDER=["brand","amber","violet","green","red","mint"];function toneColor(tone){return VAR[tone]}function toneAt(index){return SERIES_ORDER[index%SERIES_ORDER.length]}var AXIS_COLOR="var(--color-muted)";var GRID_COLOR="var(--color-line)";var SURFACE_COLOR="var(--color-surface)";var dirStore={subscribe(cb){if(typeof MutationObserver==="undefined")return()=>{};const o=new MutationObserver(cb);o.observe(document.documentElement,{attributes:true,attributeFilter:["dir"]});return()=>o.disconnect()},get:()=>typeof document==="undefined"?"rtl":document.documentElement.dir||"rtl"};function useRtl(){const locale=useMoneyLocale();const serverSnapshot=useCallback(()=>locale.startsWith("en")?"ltr":"rtl",[locale]);return useSyncExternalStore(dirStore.subscribe,dirStore.get,serverSnapshot)!=="ltr"}var BAR_RADIUS=Number.parseFloat(TOKENS["--radius-mark"]);import{jsx,jsxs}from"react/jsx-runtime";function useFormatters(formatValue,formatAxis){const locale=useMoneyLocale();return{value:formatValue??(v=>new Intl.NumberFormat(locale).format(v)),axis:formatAxis??(v=>new Intl.NumberFormat(locale,{notation:"compact",maximumFractionDigits:1}).format(v))}}function ChartEmpty({height,children}){const ui=useUIText();return jsx("div",{className:"text-caption text-muted2 flex items-center justify-center",style:{height},role:"status",children:children??ui.noData})}function ChartTooltipContent({active,payload,label,format,formatX}){if(!active||!payload?.length)return null;return jsxs("div",{className:"bg-surface border-line rounded-card shadow-tip min-w-32 border p-2.5 whitespace-nowrap",children:[label!==void 0&&label!==""&&jsx("p",{className:"text-caption text-muted mb-1.5",children:formatX?formatX(label):String(label)}),jsx("ul",{className:"space-y-1",children:payload.map((entry,i)=>jsxs("li",{className:"flex items-center gap-2",children:[jsx("span",{className:"rounded-mark size-2 shrink-0",style:{backgroundColor:entry.color},"aria-hidden":"true"}),jsx("span",{className:"text-caption text-muted grow",children:entry.name}),jsx("span",{className:"text-ui text-ink font-bold","data-num":true,children:typeof entry.value==="number"?format(entry.value):String(entry.value??"")})]},`${entry.dataKey??"k"}-${i}`))})]})}function ChartTooltipLine({active,payload,label,format}){const point=payload?.[0];if(!active||!point)return null;const named=label!==void 0&&label!=="";return jsxs("div",{className:"bg-surface border-line rounded-sm shadow-tip flex items-center gap-1.5 border px-2 py-1 whitespace-nowrap",children:[named&&jsx("span",{className:"text-micro text-muted",children:label}),named&&jsx("span",{className:"text-micro text-muted2","aria-hidden":"true",children:"\xB7"}),jsx("span",{className:"text-caption text-ink font-bold","data-num":true,children:typeof point.value==="number"?format(point.value):String(point.value??"")})]})}function ChartLegendContent({payload}){if(!payload?.length)return null;return jsx("ul",{className:"text-caption text-muted flex flex-wrap items-center justify-center gap-x-4 gap-y-1 pt-2",children:payload.map((entry,i)=>jsxs("li",{className:"flex items-center gap-1.5",children:[jsx("span",{className:"rounded-mark size-2 shrink-0",style:{backgroundColor:entry.color},"aria-hidden":"true"}),entry.value]},`${entry.dataKey??"k"}-${i}`))})}function chartGrid(){return jsx(CartesianGrid,{stroke:GRID_COLOR,strokeDasharray:"3 3",vertical:false})}function chartXAxis({dataKey,rtl,axis,formatX}){return jsx(XAxis,{dataKey,reversed:rtl&&axis==="category",tickFormatter:formatX,tick:{fill:AXIS_COLOR,className:"text-caption"},tickLine:false,axisLine:{stroke:GRID_COLOR},tickMargin:8,minTickGap:4})}function chartYAxis({rtl,format,id,side="primary"}){const onRight=side==="primary"?rtl:!rtl;return jsx(YAxis,{yAxisId:id,orientation:onRight?"right":"left",tickFormatter:format,tick:{fill:AXIS_COLOR,className:"text-caption",textAnchor:onRight===rtl?"end":"start"},tickLine:false,axisLine:false,width:"auto"})}var TOOLTIP_WRAPPER={zIndex:50};function chartTooltip({format,formatX}){return jsx(Tooltip,{cursor:{fill:GRID_COLOR,fillOpacity:.6},wrapperStyle:TOOLTIP_WRAPPER,content:jsx(ChartTooltipContent,{format,formatX})})}function chartLegend(){return jsx(Legend,{content:jsx(ChartLegendContent,{}),verticalAlign:"bottom"})}function ChartFrame({label,height,empty,isEmpty,className,children}){return jsx("div",{className:cn("w-full",className),role:"img","aria-label":label,children:isEmpty?jsx(ChartEmpty,{height,children:empty}):jsx(ResponsiveContainer,{width:"100%",height,children})})}function resolveSeries(series){return series.map((s,i)=>({...s,name:s.label??s.key,color:toneColor(s.tone??toneAt(i))}))}function chartMargin(rtl){return{top:8,bottom:0,left:rtl?4:0,right:rtl?0:4}}import{useId}from"react";import{Area,AreaChart as RAreaChart,Bar,BarChart as RBarChart,ComposedChart as RComposedChart,Line,LineChart as RLineChart,ResponsiveContainer as ResponsiveContainer2,Scatter,Tooltip as Tooltip2,ScatterChart as RScatterChart,XAxis as XAxis2,YAxis as YAxis2,ZAxis}from"recharts";import{Fragment,jsx as jsx2,jsxs as jsxs2}from"react/jsx-runtime";var DEFAULT_HEIGHT=220;function BarChart({data,x,series,bars="columns",height=DEFAULT_HEIGHT,label,formatValue,formatAxis,formatX,axis="category",grid=true,legend,empty,className}){const rtl=useRtl();const fmt=useFormatters(formatValue,formatAxis);const items=resolveSeries(series);const showLegend=legend??items.length>1;const rows=bars==="rows";return jsx2(ChartFrame,{label,height,isEmpty:data.length===0,empty,className,children:jsxs2(RBarChart,{data,layout:rows?"vertical":"horizontal",margin:chartMargin(rtl),accessibilityLayer:true,children:[grid&&chartGrid(),rows?jsxs2(Fragment,{children:[jsx2(XAxis2,{type:"number",tickFormatter:fmt.axis,tick:{fill:AXIS_COLOR,className:"text-caption"},tickLine:false,axisLine:{stroke:GRID_COLOR},reversed:rtl}),jsx2(YAxis2,{type:"category",dataKey:x,tickFormatter:formatX,tick:{fill:AXIS_COLOR,className:"text-caption",textAnchor:"end"},tickLine:false,axisLine:false,orientation:rtl?"right":"left",width:"auto"})]}):jsxs2(Fragment,{children:[chartXAxis({dataKey:x,rtl,axis,formatX}),chartYAxis({rtl,format:fmt.axis})]}),chartTooltip({format:fmt.value,formatX}),showLegend&&chartLegend(),items.map(s=>jsx2(Bar,{dataKey:s.key,name:s.name,fill:s.color,stackId:s.stackId,radius:rows?[0,BAR_RADIUS,BAR_RADIUS,0]:[BAR_RADIUS,BAR_RADIUS,0,0],maxBarSize:rows?24:48,isAnimationActive:false},s.key))]})})}function LineChart({data,x,series,height=DEFAULT_HEIGHT,label,formatValue,formatAxis,formatX,axis="time",grid=true,legend,dots=false,straight=false,empty,className}){const rtl=useRtl();const fmt=useFormatters(formatValue,formatAxis);const items=resolveSeries(series);const showLegend=legend??items.length>1;return jsx2(ChartFrame,{label,height,isEmpty:data.length===0,empty,className,children:jsxs2(RLineChart,{data,margin:chartMargin(rtl),accessibilityLayer:true,children:[grid&&chartGrid(),chartXAxis({dataKey:x,rtl,axis,formatX}),chartYAxis({rtl,format:fmt.axis}),chartTooltip({format:fmt.value,formatX}),showLegend&&chartLegend(),items.map(s=>jsx2(Line,{type:straight?"linear":"monotone",dataKey:s.key,name:s.name,stroke:s.color,strokeWidth:2,dot:dots?{r:3,fill:SURFACE_COLOR,strokeWidth:2}:false,activeDot:{r:4,fill:SURFACE_COLOR,strokeWidth:2},connectNulls:false,isAnimationActive:false},s.key))]})})}function AreaChart({data,x,series,height=DEFAULT_HEIGHT,label,formatValue,formatAxis,formatX,axis="time",grid=true,legend,empty,className}){const rtl=useRtl();const fmt=useFormatters(formatValue,formatAxis);const items=resolveSeries(series);const showLegend=legend??items.length>1;const gid=useId().replace(/:/g,"");return jsx2(ChartFrame,{label,height,isEmpty:data.length===0,empty,className,children:jsxs2(RAreaChart,{data,margin:chartMargin(rtl),accessibilityLayer:true,children:[jsx2("defs",{children:items.map(s=>jsxs2("linearGradient",{id:`${gid}-${s.key}`,x1:"0",y1:"0",x2:"0",y2:"1",children:[jsx2("stop",{offset:"0%",stopColor:s.color,stopOpacity:.28}),jsx2("stop",{offset:"100%",stopColor:s.color,stopOpacity:.02})]},s.key))}),grid&&chartGrid(),chartXAxis({dataKey:x,rtl,axis,formatX}),chartYAxis({rtl,format:fmt.axis}),chartTooltip({format:fmt.value,formatX}),showLegend&&chartLegend(),items.map(s=>jsx2(Area,{type:"monotone",dataKey:s.key,name:s.name,stackId:s.stackId,stroke:s.color,strokeWidth:2,fill:`url(#${gid}-${s.key})`,activeDot:{r:4,fill:SURFACE_COLOR,strokeWidth:2},connectNulls:false,isAnimationActive:false},s.key))]})})}function ComposedChart({data,x,series,height=DEFAULT_HEIGHT,label,formatValue,formatAxis,formatX,axis="category",grid=true,legend,empty,className}){const rtl=useRtl();const fmt=useFormatters(formatValue,formatAxis);const items=resolveSeries(series);const showLegend=legend??items.length>1;const gid=useId().replace(/:/g,"");const split=items.some(s=>s.scale==="secondary");const axisOf=s=>split?s.scale==="secondary"?"r":"l":void 0;return jsx2(ChartFrame,{label,height,isEmpty:data.length===0,empty,className,children:jsxs2(RComposedChart,{data,margin:chartMargin(rtl),accessibilityLayer:true,children:[jsx2("defs",{children:items.filter(s=>s.as==="area").map(s=>jsxs2("linearGradient",{id:`${gid}-${s.key}`,x1:"0",y1:"0",x2:"0",y2:"1",children:[jsx2("stop",{offset:"0%",stopColor:s.color,stopOpacity:.28}),jsx2("stop",{offset:"100%",stopColor:s.color,stopOpacity:.02})]},s.key))}),grid&&chartGrid(),chartXAxis({dataKey:x,rtl,axis,formatX}),chartYAxis({rtl,format:fmt.axis,id:split?"l":void 0}),split&&chartYAxis({rtl,format:fmt.axis,id:"r",side:"secondary"}),chartTooltip({format:fmt.value,formatX}),showLegend&&chartLegend(),items.map(s=>s.as==="line"?jsx2(Line,{type:"monotone",dataKey:s.key,name:s.name,yAxisId:axisOf(s),stroke:s.color,strokeWidth:2,dot:false,activeDot:{r:4,fill:SURFACE_COLOR,strokeWidth:2},isAnimationActive:false},s.key):s.as==="area"?jsx2(Area,{type:"monotone",dataKey:s.key,name:s.name,yAxisId:axisOf(s),stackId:s.stackId,stroke:s.color,strokeWidth:2,fill:`url(#${gid}-${s.key})`,isAnimationActive:false},s.key):jsx2(Bar,{dataKey:s.key,name:s.name,yAxisId:axisOf(s),fill:s.color,stackId:s.stackId,radius:[BAR_RADIUS,BAR_RADIUS,0,0],maxBarSize:48,isAnimationActive:false},s.key))]})})}function ScatterChart({groups,height=DEFAULT_HEIGHT,label,xLabel,yLabel,formatValue,formatAxis,grid=true,legend,empty,className}){const rtl=useRtl();const fmt=useFormatters(formatValue,formatAxis);const showLegend=legend??groups.length>1;const isEmpty=groups.every(g=>g.points.length===0);return jsx2(ChartFrame,{label,height,isEmpty,empty,className,children:jsxs2(RScatterChart,{margin:chartMargin(rtl),accessibilityLayer:true,children:[grid&&chartGrid(),jsx2(XAxis2,{type:"number",dataKey:"x",name:xLabel,tickFormatter:fmt.axis,tick:{fill:AXIS_COLOR,className:"text-caption"},tickLine:false,axisLine:{stroke:GRID_COLOR}}),jsx2(YAxis2,{type:"number",dataKey:"y",name:yLabel,tickFormatter:fmt.axis,tick:{fill:AXIS_COLOR,className:"text-caption",textAnchor:"end"},tickLine:false,axisLine:false,orientation:rtl?"right":"left",width:"auto"}),jsx2(ZAxis,{type:"number",dataKey:"z",range:[36,300]}),chartTooltip({format:fmt.value}),showLegend&&chartLegend(),groups.map((g,i)=>jsx2(Scatter,{name:g.label??g.key,data:g.points,fill:toneColor(g.tone??toneAt(i)),fillOpacity:.75,isAnimationActive:false},g.key))]})})}function Sparkline({values,label,labels,formatValue,tone="brand",height=36,filled,className}){const gid=useId().replace(/:/g,"");const fmt=useFormatters(formatValue);const color=toneColor(tone);const named=labels!==void 0&&labels.length>0;const data=values.map((v,i)=>({i,v,at:labels?.[i]??""}));if(values.length===0)return null;return jsx2("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx2(ResponsiveContainer2,{width:"100%",height,children:jsxs2(RAreaChart,{data,margin:{top:2,bottom:2,left:0,right:0},accessibilityLayer:true,children:[jsx2("defs",{children:jsxs2("linearGradient",{id:`${gid}-spark`,x1:"0",y1:"0",x2:"0",y2:"1",children:[jsx2("stop",{offset:"0%",stopColor:color,stopOpacity:.3}),jsx2("stop",{offset:"100%",stopColor:color,stopOpacity:0})]})}),named&&jsx2(XAxis2,{dataKey:"at",hide:true}),named&&jsx2(Tooltip2,{cursor:{stroke:color,strokeWidth:1},wrapperStyle:TOOLTIP_WRAPPER,content:jsx2(ChartTooltipLine,{format:fmt.value})}),jsx2(Area,{type:"monotone",dataKey:"v",name:label,stroke:color,strokeWidth:1.5,fill:filled?`url(#${gid}-spark)`:"none",dot:false,isAnimationActive:false})]})})})}import{Cell,Legend as Legend2,Pie,PieChart as RPieChart,PolarAngleAxis,PolarGrid,PolarRadiusAxis,Radar,RadarChart as RRadarChart,RadialBar,RadialBarChart as RRadialBarChart,ResponsiveContainer as ResponsiveContainer3,Tooltip as Tooltip3}from"recharts";import{jsx as jsx3,jsxs as jsxs3}from"react/jsx-runtime";var DEFAULT_HEIGHT2=220;function slices(items){return items.map((s,i)=>({name:s.label??s.key,value:s.value,color:toneColor(s.tone??toneAt(i)),key:s.key}))}function PieChart({items,height=DEFAULT_HEIGHT2,label,formatValue,legend=true,empty,className}){return jsx3(Ring,{items,height,label,formatValue,legend,empty,className,inner:0})}function DonutChart({items,height=DEFAULT_HEIGHT2,label,formatValue,legend=true,centerValue,centerLabel,empty,className}){return jsx3(Ring,{items,height,label,formatValue,legend,empty,className,inner:62,centerValue,centerLabel})}function Ring({items,height,label,formatValue,legend,empty,className,inner,centerValue,centerLabel}){const locale=useMoneyLocale();const fmt=useFormatters(formatValue);const data=slices(items);const isEmpty=data.length===0||data.every(d=>!d.value);const total=data.reduce((sum,d)=>sum+(d.value||0),0);if(isEmpty){return jsx3("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx3(ChartEmpty,{height:height??DEFAULT_HEIGHT2,children:empty})})}return jsxs3("div",{className:cn("relative w-full",className),role:"img","aria-label":label,children:[jsx3(ResponsiveContainer3,{width:"100%",height:height??DEFAULT_HEIGHT2,children:jsxs3(RPieChart,{children:[jsx3(Tooltip3,{wrapperStyle:TOOLTIP_WRAPPER,content:jsx3(ChartTooltipContent,{format:fmt.value})}),legend&&jsx3(Legend2,{content:jsx3(ChartLegendContent,{}),verticalAlign:"bottom"}),jsx3(Pie,{data,dataKey:"value",nameKey:"name",innerRadius:inner?`${inner}%`:0,outerRadius:"88%",stroke:SURFACE_COLOR,strokeWidth:2,isAnimationActive:false,startAngle:90,endAngle:-270,children:data.map(d=>jsx3(Cell,{fill:d.color},d.key))})]})}),inner>0&&jsxs3("div",{className:"pointer-events-none absolute inset-0 flex flex-col items-center justify-center",children:[jsx3("span",{className:"text-h3 text-ink font-extrabold","data-num":true,children:centerValue??new Intl.NumberFormat(locale).format(total)}),centerLabel&&jsx3("span",{className:"text-caption text-muted",children:centerLabel})]})]})}function RadarChart({data,x,series,height=DEFAULT_HEIGHT2,label,formatValue,legend,empty,className}){const fmt=useFormatters(formatValue);const items=resolveSeries(series);const showLegend=legend??items.length>1;if(data.length===0){return jsx3("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx3(ChartEmpty,{height,children:empty})})}return jsx3("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx3(ResponsiveContainer3,{width:"100%",height,children:jsxs3(RRadarChart,{data,outerRadius:"72%",children:[jsx3(PolarGrid,{stroke:GRID_COLOR}),jsx3(PolarAngleAxis,{dataKey:x,tick:{fill:AXIS_COLOR,className:"text-caption"}}),jsx3(PolarRadiusAxis,{tick:false,axisLine:false}),jsx3(Tooltip3,{wrapperStyle:TOOLTIP_WRAPPER,content:jsx3(ChartTooltipContent,{format:fmt.value})}),showLegend&&jsx3(Legend2,{content:jsx3(ChartLegendContent,{}),verticalAlign:"bottom"}),items.map(s=>jsx3(Radar,{dataKey:s.key,name:s.name,stroke:s.color,strokeWidth:2,fill:s.color,fillOpacity:.18,isAnimationActive:false},s.key))]})})})}function RadialChart({items,max,height=DEFAULT_HEIGHT2,label,formatValue,legend=true,empty,className}){const fmt=useFormatters(formatValue);const data=slices(items);const isEmpty=data.length===0;if(isEmpty){return jsx3("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx3(ChartEmpty,{height,children:empty})})}const ceiling=max??Math.max(...data.map(d=>d.value||0));return jsx3("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx3(ResponsiveContainer3,{width:"100%",height,children:jsxs3(RRadialBarChart,{data,innerRadius:"30%",outerRadius:"95%",startAngle:90,endAngle:-270,barSize:12,children:[jsx3(PolarAngleAxis,{type:"number",domain:[0,ceiling],tick:false}),jsx3(Tooltip3,{wrapperStyle:TOOLTIP_WRAPPER,content:jsx3(ChartTooltipContent,{format:fmt.value})}),legend&&jsx3(Legend2,{content:jsx3(ChartLegendContent,{}),verticalAlign:"bottom"}),jsx3(RadialBar,{dataKey:"value",background:{fill:GRID_COLOR},cornerRadius:"50%",isAnimationActive:false,children:data.map(d=>jsx3(Cell,{fill:d.color},d.key))})]})})})}import{useMemo}from"react";import{Funnel,FunnelChart as RFunnelChart,LabelList,useChartWidth,useMargin,ResponsiveContainer as ResponsiveContainer4,Sankey,Tooltip as Tooltip4,Treemap}from"recharts";import{jsx as jsx4,jsxs as jsxs4}from"react/jsx-runtime";var DEFAULT_HEIGHT3=240;function FunnelChart({steps,height=DEFAULT_HEIGHT3,label,formatValue,showRate=true,empty,className}){const rtl=useRtl();const locale=useMoneyLocale();const fmt=useFormatters(formatValue);const isEmpty=steps.length===0||steps.every(s=>!s.value);if(isEmpty){return jsx4("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx4(ChartEmpty,{height,children:empty})})}const first=steps[0]?.value||0;const data=steps.map(s=>({name:s.label??s.key,value:s.value,fill:toneColor(s.tone??"brand"),rate:first?s.value/first:0}));return jsx4("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx4(ResponsiveContainer4,{width:"100%",height,children:jsxs4(RFunnelChart,{margin:rtl?{left:56,right:104}:{left:104,right:56},children:[jsx4(Tooltip4,{wrapperStyle:TOOLTIP_WRAPPER,content:jsx4(ChartTooltipContent,{format:fmt.value})}),jsx4(Funnel,{dataKey:"value",data,stroke:SURFACE_COLOR,strokeWidth:2,isAnimationActive:false,children:jsx4(LabelList,{dataKey:"name",content:jsx4(FunnelBandLabel,{rtl,rows:data,showRate,formatRate:v=>new Intl.NumberFormat(locale,{style:"percent",maximumFractionDigits:1}).format(v)})})})]})})})}function TreemapChart({nodes,height=DEFAULT_HEIGHT3,label,formatValue,empty,className}){const fmt=useFormatters(formatValue);const isEmpty=nodes.length===0;if(isEmpty){return jsx4("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx4(ChartEmpty,{height,children:empty})})}const data=nodes.map((n,i)=>({...n,fill:toneColor(n.tone??toneAt(i))}));return jsx4("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx4(ResponsiveContainer4,{width:"100%",height,children:jsx4(Treemap,{data,dataKey:"value",stroke:SURFACE_COLOR,isAnimationActive:false,content:jsx4(TreemapCell,{}),children:jsx4(Tooltip4,{wrapperStyle:TOOLTIP_WRAPPER,content:jsx4(ChartTooltipContent,{format:fmt.value})})})})})}function TreemapCell(props){const{x=0,y=0,width=0,height=0,name,fill}=props;const roomy=width>64&&height>24;return jsxs4("g",{children:[jsx4("rect",{x,y,width,height,fill,stroke:SURFACE_COLOR,strokeWidth:2}),roomy&&name&&jsx4("text",{x:x+width/2,y:y+height/2,textAnchor:"middle",dominantBaseline:"middle",fill:SURFACE_COLOR,className:"text-caption",children:name})]})}function SankeyChart({nodes,links,height=DEFAULT_HEIGHT3,label,formatValue,empty,className}){const rtl=useRtl();const fmt=useFormatters(formatValue);const isEmpty=nodes.length===0||links.length===0;const ends=useMemo(()=>{const withIncoming=new Set(links.map(l=>l.target));const withOutgoing=new Set(links.map(l=>l.source));return{first:new Set(nodes.map((_,i)=>i).filter(i=>!withIncoming.has(i))),last:new Set(nodes.map((_,i)=>i).filter(i=>!withOutgoing.has(i)))}},[nodes,links]);if(isEmpty){return jsx4("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx4(ChartEmpty,{height,children:empty})})}return jsx4("div",{className:cn("w-full",className),role:"img","aria-label":label,children:jsx4(ResponsiveContainer4,{width:"100%",height,children:jsx4(Sankey,{data:{nodes,links},nodePadding:24,node:jsx4(SankeyNodeShape,{rtl,ends}),link:{stroke:toneColor("brand"),strokeOpacity:.16},margin:{top:24,bottom:8,left:72,right:72},children:jsx4(Tooltip4,{wrapperStyle:TOOLTIP_WRAPPER,content:jsx4(ChartTooltipContent,{format:fmt.value})})})})})}function SankeyNodeShape(props){const{x=0,y=0,width=0,height=0,index=0,rtl=false,ends,payload}=props;const isFirst=ends?.first.has(index)??false;const isLast=ends?.last.has(index)??false;const at=isFirst&&!isLast?{x:x-8,y:y+height/2,anchor:rtl?"start":"end"}:isLast?{x:x+width+8,y:y+height/2,anchor:rtl?"end":"start"}:{x:x+width/2,y:y-8,anchor:"middle"};return jsxs4("g",{children:[jsx4("rect",{x,y,width,height,fill:toneColor("brand"),rx:BAR_RADIUS}),jsx4("text",{x:at.x,y:at.y,textAnchor:at.anchor,dominantBaseline:at.anchor==="middle"?"auto":"middle",fill:AXIS_COLOR,className:"text-caption",children:payload?.name})]})}function FunnelBandLabel(props){const{y=0,height=0,index=0,rtl=false,showRate,rows,formatRate,value}=props;const chartWidth=useChartWidth()??0;const margin=useMargin()??{left:0,right:0};const left=margin.left??0;const right=margin.right??0;const rate=rows?.[index]?.rate;const mid=y+height/2;const pad=8;const nameX=rtl?chartWidth-right+pad:left-pad;const rateX=rtl?left-pad:chartWidth-right+pad;return jsxs4("g",{children:[jsx4("text",{x:nameX,y:mid,textAnchor:"end",dominantBaseline:"middle",fill:AXIS_COLOR,className:"text-caption",children:value}),showRate&&rate!==void 0&&jsx4("text",{x:rateX,y:mid,textAnchor:"start",dominantBaseline:"middle",fill:AXIS_COLOR,className:"text-caption",children:formatRate?.(rate)})]})}export{AreaChart,BarChart,ChartEmpty,ChartFrame,ComposedChart,DonutChart,FunnelChart,LineChart,PieChart,RadarChart,RadialChart,SERIES_ORDER,SankeyChart,ScatterChart,Sparkline,TreemapChart,toneAt,toneColor,useRtl};