neba 1.3.0 → 1.5.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.
Files changed (135) hide show
  1. package/README.md +7 -7
  2. package/dist/components/alert/Alert.d.ts +9 -1
  3. package/dist/components/alert/Alert.js +1 -1
  4. package/dist/components/area-chart/AreaChart.d.ts +54 -0
  5. package/dist/components/area-chart/AreaChart.js +1 -0
  6. package/dist/components/area-chart/index.d.ts +2 -0
  7. package/dist/components/area-chart/index.js +1 -0
  8. package/dist/components/bar-chart/BarChart.d.ts +63 -0
  9. package/dist/components/bar-chart/BarChart.js +1 -0
  10. package/dist/components/bar-chart/index.d.ts +2 -0
  11. package/dist/components/bar-chart/index.js +1 -0
  12. package/dist/components/bottom-navigation/BottomNavigation.d.ts +111 -0
  13. package/dist/components/bottom-navigation/BottomNavigation.js +1 -0
  14. package/dist/components/bottom-navigation/index.d.ts +1 -0
  15. package/dist/components/bottom-navigation/index.js +1 -0
  16. package/dist/components/breadcrumb/Breadcrumb.d.ts +35 -2
  17. package/dist/components/breadcrumb/Breadcrumb.js +1 -1
  18. package/dist/components/button/Button.d.ts +16 -0
  19. package/dist/components/button/Button.js +1 -1
  20. package/dist/components/carousel/Carousel.d.ts +10 -4
  21. package/dist/components/carousel/Carousel.js +1 -1
  22. package/dist/components/chip/Chip.d.ts +9 -1
  23. package/dist/components/chip/Chip.js +1 -1
  24. package/dist/components/collapsible/Collapsible.d.ts +88 -0
  25. package/dist/components/collapsible/Collapsible.js +1 -0
  26. package/dist/components/collapsible/index.d.ts +1 -0
  27. package/dist/components/collapsible/index.js +1 -0
  28. package/dist/components/combobox/Combobox.d.ts +19 -7
  29. package/dist/components/combobox/Combobox.js +1 -1
  30. package/dist/components/data-table/DataTable.d.ts +323 -0
  31. package/dist/components/data-table/DataTable.js +1 -0
  32. package/dist/components/data-table/index.d.ts +2 -0
  33. package/dist/components/data-table/index.js +1 -0
  34. package/dist/components/dialog/Dialog.d.ts +11 -5
  35. package/dist/components/dialog/Dialog.js +1 -1
  36. package/dist/components/drawer/Drawer.d.ts +11 -5
  37. package/dist/components/drawer/Drawer.js +1 -1
  38. package/dist/components/empty/Empty.d.ts +69 -0
  39. package/dist/components/empty/Empty.js +1 -0
  40. package/dist/components/empty/index.d.ts +2 -0
  41. package/dist/components/empty/index.js +1 -0
  42. package/dist/components/file-picker/FilePicker.d.ts +1 -3
  43. package/dist/components/file-picker/FilePicker.js +1 -1
  44. package/dist/components/floating-action-button/FloatingActionButton.d.ts +146 -0
  45. package/dist/components/floating-action-button/FloatingActionButton.js +1 -0
  46. package/dist/components/floating-action-button/index.d.ts +1 -0
  47. package/dist/components/floating-action-button/index.js +1 -0
  48. package/dist/components/heatmap-chart/HeatmapChart.d.ts +69 -0
  49. package/dist/components/heatmap-chart/HeatmapChart.js +1 -0
  50. package/dist/components/heatmap-chart/index.d.ts +2 -0
  51. package/dist/components/heatmap-chart/index.js +1 -0
  52. package/dist/components/highlight/Highlight.js +1 -1
  53. package/dist/components/line-chart/LineChart.d.ts +74 -0
  54. package/dist/components/line-chart/LineChart.js +1 -0
  55. package/dist/components/line-chart/index.d.ts +2 -0
  56. package/dist/components/line-chart/index.js +1 -0
  57. package/dist/components/mockup/Mockup.d.ts +151 -0
  58. package/dist/components/mockup/Mockup.js +1 -0
  59. package/dist/components/mockup/index.d.ts +2 -0
  60. package/dist/components/mockup/index.js +1 -0
  61. package/dist/components/number-field/NumberField.d.ts +10 -6
  62. package/dist/components/number-field/NumberField.js +1 -1
  63. package/dist/components/overlay/Overlay.d.ts +11 -6
  64. package/dist/components/overlay/Overlay.js +1 -1
  65. package/dist/components/pagination/Pagination.d.ts +28 -6
  66. package/dist/components/pagination/Pagination.js +1 -1
  67. package/dist/components/panes/Panes.js +1 -1
  68. package/dist/components/pie-chart/PieChart.d.ts +58 -0
  69. package/dist/components/pie-chart/PieChart.js +1 -0
  70. package/dist/components/pie-chart/index.d.ts +2 -0
  71. package/dist/components/pie-chart/index.js +1 -0
  72. package/dist/components/popover/Popover.d.ts +11 -5
  73. package/dist/components/popover/Popover.js +1 -1
  74. package/dist/components/progress-box/ProgressBox.js +1 -1
  75. package/dist/components/progress-circular/ProgressCircular.js +1 -1
  76. package/dist/components/progress-linear/ProgressLinear.js +1 -1
  77. package/dist/components/rating/Rating.d.ts +100 -0
  78. package/dist/components/rating/Rating.js +1 -0
  79. package/dist/components/rating/index.d.ts +1 -0
  80. package/dist/components/rating/index.js +1 -0
  81. package/dist/components/scatter-chart/ScatterChart.d.ts +45 -0
  82. package/dist/components/scatter-chart/ScatterChart.js +1 -0
  83. package/dist/components/scatter-chart/index.d.ts +2 -0
  84. package/dist/components/scatter-chart/index.js +1 -0
  85. package/dist/components/select/Select.d.ts +1 -3
  86. package/dist/components/select/Select.js +1 -1
  87. package/dist/components/sparkline/Sparkline.d.ts +67 -0
  88. package/dist/components/sparkline/Sparkline.js +1 -0
  89. package/dist/components/sparkline/index.d.ts +2 -0
  90. package/dist/components/sparkline/index.js +1 -0
  91. package/dist/components/statistic/Statistic.d.ts +7 -0
  92. package/dist/components/statistic/Statistic.js +1 -1
  93. package/dist/components/table/Table.d.ts +13 -2
  94. package/dist/components/table/Table.js +1 -1
  95. package/dist/components/text-link/TextLink.js +1 -1
  96. package/dist/components/time-picker/TimePicker.js +1 -1
  97. package/dist/components/timeline-chart/TimelineChart.d.ts +44 -0
  98. package/dist/components/timeline-chart/TimelineChart.js +1 -0
  99. package/dist/components/timeline-chart/index.d.ts +2 -0
  100. package/dist/components/timeline-chart/index.js +1 -0
  101. package/dist/components/toast/Toast.d.ts +10 -2
  102. package/dist/components/toast/Toast.js +1 -1
  103. package/dist/components/tooltip/Tooltip.d.ts +2 -4
  104. package/dist/components/tooltip/Tooltip.js +1 -1
  105. package/dist/components/tree-view/TreeView.js +1 -1
  106. package/dist/index.d.ts +15 -0
  107. package/dist/index.js +1 -1
  108. package/dist/internal/animate.d.ts +0 -9
  109. package/dist/internal/animate.js +1 -1
  110. package/dist/internal/calendar.js +1 -1
  111. package/dist/internal/chart-frame.d.ts +409 -0
  112. package/dist/internal/chart-frame.js +1 -0
  113. package/dist/internal/chart-line.d.ts +44 -0
  114. package/dist/internal/chart-line.js +1 -0
  115. package/dist/internal/chart.d.ts +456 -0
  116. package/dist/internal/chart.js +1 -0
  117. package/dist/internal/data-table.d.ts +170 -0
  118. package/dist/internal/data-table.js +1 -0
  119. package/dist/internal/date.d.ts +0 -2
  120. package/dist/internal/date.js +1 -1
  121. package/dist/internal/format.d.ts +29 -0
  122. package/dist/internal/format.js +1 -0
  123. package/dist/internal/i18n.d.ts +166 -0
  124. package/dist/internal/i18n.js +1 -1
  125. package/dist/internal/icons.d.ts +2 -0
  126. package/dist/internal/icons.js +1 -1
  127. package/dist/internal/mockup.d.ts +193 -0
  128. package/dist/internal/mockup.js +1 -0
  129. package/dist/internal/picker.d.ts +2 -4
  130. package/dist/internal/picker.js +1 -1
  131. package/dist/internal/progress.d.ts +1 -3
  132. package/dist/styles.css +1 -1
  133. package/dist/tailwind.css +231 -11
  134. package/dist/types.d.ts +214 -0
  135. package/package.json +19 -15
@@ -0,0 +1,409 @@
1
+ /**
2
+ * Everything a chart draws that is not its marks.
3
+ *
4
+ * The split this file makes is the one the whole `internal/` folder is about:
5
+ * a LineChart, an AreaChart and a BarChart differ in about forty lines each —
6
+ * a path, a band, a rounded end — and agree on everything else. The axes, the
7
+ * grid, the legend, the crosshair, the tooltip, the empty state, the hidden
8
+ * table a screen reader reads instead of the picture, and the measurement that
9
+ * turns a percentage width into the pixels an SVG needs are all the same
10
+ * problem five times over.
11
+ *
12
+ * So `CartesianChart` is the chart, and a component hands it a function that
13
+ * draws the marks. What is left in `LineChart.tsx` is the line.
14
+ *
15
+ * `chart.ts` is the arithmetic under this; nothing in there knows what an
16
+ * element is, and nothing in here does arithmetic that is not layout.
17
+ */
18
+ import * as React from 'react';
19
+ import { type BoxProps } from '../components/box/Box';
20
+ import { type BandScale, type ChartValue, type PlotBox, type ValueScale } from './chart';
21
+ import type { NebaChartAxis, NebaChartCategory, NebaChartLegend, NebaChartSeries, NebaChartTooltip, NebaSize } from '../types';
22
+ /**
23
+ * How wide the chart actually is, in pixels.
24
+ *
25
+ * An SVG cannot lay a chart out from a percentage: every tick position, every
26
+ * bar width and the decision about how many category labels fit are arithmetic
27
+ * on a number, and `100%` is not one. So the host element is measured and the
28
+ * drawing waits for the answer.
29
+ *
30
+ * The wait is one frame and not one paint — `useLayoutEffect` runs before the
31
+ * browser draws, so the empty state never reaches the screen. What does reach
32
+ * it on a server-rendered page is a box of the right height with nothing in it,
33
+ * which is why the height is a prop and not something measured too: a reserve
34
+ * that is dropped when the content arrives is the same jump twice.
35
+ */
36
+ declare function useMeasuredWidth(ref: React.RefObject<HTMLElement | null>): number;
37
+ /**
38
+ * What every chart takes, and the reason it is one interface: a dashboard is
39
+ * built by copying a tile and changing the component in it, and that only works
40
+ * if `height`, `legend`, `tooltip` and `format` mean the same thing on all of
41
+ * them.
42
+ *
43
+ * `variant` defaults to `text` and `padded` to `false`, which is the one place
44
+ * a chart deviates from Box. A chart is a *drawing*, not a sheet — it goes on a
45
+ * Card, next to the number it explains, and a sheet of its own inside that Card
46
+ * would be two edges where the design language wants one. `variant="outline"`
47
+ * is there for the chart that stands on the page by itself.
48
+ */
49
+ export interface ChartBaseProps extends Omit<BoxProps, 'children' | 'title'> {
50
+ /**
51
+ * How tall the drawing is. A number is pixels; a string is any CSS length.
52
+ * Defaults to the `size` ladder.
53
+ *
54
+ * The axis labels are drawn *inside* this, not under it, so a card sized to
55
+ * the chart is a card the chart fits in.
56
+ */
57
+ height?: number | string;
58
+ /**
59
+ * How the numbers are written, everywhere they appear — the axis, the
60
+ * tooltip, the labels on the marks. `Intl.NumberFormat` options, the same
61
+ * prop Statistic and the progress indicators take.
62
+ *
63
+ * Without it an axis tick is compacted past ten thousand (`12.4K`), because
64
+ * four labels of seven digits is a chart with a column of numbers beside it.
65
+ */
66
+ format?: Intl.NumberFormatOptions;
67
+ /** Which language the chart's own words and dates are in. @default the reader's */
68
+ locale?: string;
69
+ /**
70
+ * The chart's accessible name — what it is a chart *of*. Read out in place of
71
+ * the drawing, and used as the caption of the table underneath it.
72
+ */
73
+ label?: string;
74
+ /**
75
+ * The legend. Shown automatically from two series up and left off below that,
76
+ * because a legend with one swatch in it restates the title.
77
+ *
78
+ * `false` turns it off; an object places it and says whether it does anything
79
+ * when clicked.
80
+ */
81
+ legend?: boolean | NebaChartLegend;
82
+ /**
83
+ * What the pointer uncovers. On by default — a chart drawn in a browser is
84
+ * interactive, and a reader who wants the number for March should not have to
85
+ * measure it against a gridline.
86
+ *
87
+ * It never carries a value that is not readable another way: the table under
88
+ * every chart has all of them.
89
+ */
90
+ tooltip?: boolean | NebaChartTooltip;
91
+ /** What to draw when there is nothing to draw. */
92
+ empty?: React.ReactNode;
93
+ }
94
+ /** The props a chart with two axes adds. */
95
+ export interface CartesianChartProps extends ChartBaseProps {
96
+ /** The series, in the order their colours are handed out. */
97
+ series: readonly NebaChartSeries[];
98
+ /** The category axis' labels. Points may carry their own `x` instead. */
99
+ categories?: readonly NebaChartCategory[];
100
+ /** The category axis. */
101
+ xAxis?: NebaChartAxis;
102
+ /** The value axis. */
103
+ yAxis?: NebaChartAxis;
104
+ }
105
+ interface Visibility {
106
+ visible: boolean[];
107
+ hovered: number | null;
108
+ toggle: (index: number) => void;
109
+ setHovered: (index: number | null) => void;
110
+ }
111
+ /**
112
+ * Which series are drawn, and which one the pointer is resting on in the legend.
113
+ *
114
+ * Keyed by index into the array as it was passed, which is what keeps a hidden
115
+ * series from renumbering the ones after it. The colours come off the same
116
+ * index, so hiding Europe leaves Asia exactly the colour it was.
117
+ */
118
+ declare function useVisibility(series: readonly NebaChartSeries[]): Visibility;
119
+ interface LegendProps {
120
+ series: readonly NebaChartSeries[];
121
+ colors: readonly string[];
122
+ options: NebaChartLegend;
123
+ visibility: Visibility;
124
+ size: NebaSize;
125
+ values?: readonly (string | undefined)[];
126
+ swatch?: (index: number, color: string) => React.ReactNode;
127
+ }
128
+ /**
129
+ * The dependable identity channel.
130
+ *
131
+ * A swatch and a word, and the swatch is the only thing on it wearing the
132
+ * series colour — the name is ink, at whatever the size ladder says, because a
133
+ * light hue is illegible as text and because colour is what the swatch beside
134
+ * it is for.
135
+ *
136
+ * A hidden series stays in the legend and goes grey rather than disappearing:
137
+ * a list that shortens when you click it is a list you cannot click twice.
138
+ *
139
+ * `swatch` is for the chart whose marks carry a second identity channel. A
140
+ * scatter past the third series tells its series apart by shape as well as by
141
+ * hue, and a legend that answered with eight identical squares would be back to
142
+ * colour alone — which is the thing the shapes were added to fix.
143
+ */
144
+ declare function ChartLegendBar({ series, colors, options, visibility, size, values, swatch }: LegendProps): React.JSX.Element;
145
+ interface ScaleLegendProps {
146
+ /** The steps, palest first, as the `var()`s that resolve them. */
147
+ steps: readonly string[];
148
+ /** What the two ends of the scale say. */
149
+ from: string;
150
+ to: string;
151
+ /** And the middle, on a diverging scale where the middle means something. */
152
+ middle?: string;
153
+ align: NonNullable<NebaChartLegend['align']>;
154
+ vertical: boolean;
155
+ size: NebaSize;
156
+ }
157
+ /**
158
+ * The legend a magnitude needs, which is a bar and not a list of swatches.
159
+ *
160
+ * `ChartLegendBar` answers "which one is Europe" — a set of names, in no order,
161
+ * each with a colour beside it. A sequential scale is the other question
162
+ * entirely: nothing here has a name, the order *is* the meaning, and what the
163
+ * reader needs is the two numbers at the ends. A key of five unnamed swatches
164
+ * would say neither.
165
+ *
166
+ * The steps are drawn as five joined blocks rather than as a CSS gradient,
167
+ * because five is what the cells are actually coloured with — a smooth bar
168
+ * would promise a continuum the chart cannot deliver, and a reader matching a
169
+ * cell against it would be guessing.
170
+ */
171
+ declare function ChartScaleLegend({ steps, from, to, middle, align, vertical, size }: ScaleLegendProps): React.JSX.Element;
172
+ /** One row of a tooltip: a series, and what it says at the active category. */
173
+ export interface ChartTooltipItem {
174
+ seriesIndex: number;
175
+ name?: string;
176
+ color: string;
177
+ value: number | null;
178
+ formatted: string;
179
+ label?: React.ReactNode;
180
+ }
181
+ interface TooltipProps {
182
+ heading: React.ReactNode;
183
+ items: readonly ChartTooltipItem[];
184
+ /** Where along the plot the anchor sits, in pixels from the chart's left. */
185
+ x: number;
186
+ /** And how far down. */
187
+ y: number;
188
+ /** Which half of the chart the anchor is in — the tooltip opens the other way. */
189
+ flip: boolean;
190
+ size: NebaSize;
191
+ }
192
+ /**
193
+ * The panel under the pointer.
194
+ *
195
+ * Anchored by its near edge rather than centred with a translate: the design
196
+ * language spends no `transform` on anything, and anchoring left-or-right by
197
+ * which half of the plot the pointer is in is also the only placement that
198
+ * cannot run off the side of a narrow card.
199
+ *
200
+ * It is `pointer-events-none` because it is a readout, not a surface — a panel
201
+ * that the pointer can enter is a panel that steals the hover that produced it
202
+ * and then flickers.
203
+ */
204
+ declare function ChartTooltipPanel({ heading, items, x, y, flip, size }: TooltipProps): React.JSX.Element;
205
+ interface DataTableProps {
206
+ id: string;
207
+ caption?: string;
208
+ corner?: React.ReactNode;
209
+ categories: readonly NebaChartCategory[];
210
+ series: readonly NebaChartSeries[];
211
+ values: readonly ChartValue[][];
212
+ format: (value: number) => string;
213
+ locale?: string;
214
+ }
215
+ /**
216
+ * The chart, as a table, for the readers a drawing does not reach.
217
+ *
218
+ * Not an option and not a toggle. A tooltip that is the only way to a number
219
+ * gates that number behind a pointer, and an SVG with an `aria-label` on it
220
+ * says "revenue by month" and then says nothing else at all. This is the same
221
+ * data in the one form every assistive technology already reads, so the picture
222
+ * is free to be a picture.
223
+ *
224
+ * It is clipped rather than `display: none`, for the reason `srOnlyClasses`
225
+ * gives: the second one takes it off the accessibility tree along with the
226
+ * screen, which would leave the chart exactly as mute as before.
227
+ */
228
+ declare function ChartDataTable({ id, caption, corner, categories, series, values, format, locale }: DataTableProps): React.JSX.Element;
229
+ interface SurfaceProps extends Omit<BoxProps, 'children'> {
230
+ legend: React.ReactNode;
231
+ legendSide: NonNullable<NebaChartLegend['side']>;
232
+ children: React.ReactNode;
233
+ table: React.ReactNode;
234
+ }
235
+ /** Box, with the legend on one of its four sides and the table underneath. */
236
+ declare function ChartSurface({ legend, legendSide, children, table, className, ...box }: SurfaceProps): React.JSX.Element;
237
+ /**
238
+ * One mark on a plot whose marks are not arranged in columns.
239
+ *
240
+ * A scatter has no shared categories, so there is no column for a pointer to
241
+ * be inside and nothing for a crosshair to be dropped through: the only
242
+ * question a reader can be asking is "which of these dots". A chart that says
243
+ * so hands the frame its marks and gets the nearest-mark search, the arrow
244
+ * keys and the tooltip anchoring for free.
245
+ */
246
+ export interface ChartMark {
247
+ /** Its series' place in the array as it was passed — where its colour is from. */
248
+ series: number;
249
+ /** Its own place within that series. */
250
+ index: number;
251
+ /** Its centre, in pixels from the chart's top-left. */
252
+ x: number;
253
+ y: number;
254
+ /** How big it is. Widens the hit target, so a bubble is easier to hit than a dot. */
255
+ r: number;
256
+ /**
257
+ * Its half-width and half-height, when the mark is a box rather than a disc.
258
+ *
259
+ * A span on a Gantt is two hundred pixels of bar whose centre a pointer may
260
+ * never go near, so measuring to the centre would hand the row's short bar a
261
+ * hover the reader is plainly not making. Given these, the pointer is tested
262
+ * against the *body*.
263
+ */
264
+ rx?: number;
265
+ ry?: number;
266
+ }
267
+ /**
268
+ * Where everything goes — the half of the context that is settled before the
269
+ * pointer is consulted.
270
+ *
271
+ * It is split out because the marks are built from it: a chart hands the frame
272
+ * a builder, the frame runs it on the layout, and only then is there a list for
273
+ * the pointer to be nearest to. A builder that could read what is active would
274
+ * be reading a value that does not exist yet.
275
+ */
276
+ export interface CartesianLayout {
277
+ plot: PlotBox;
278
+ /** Every series unpacked, in the order it was passed. */
279
+ values: readonly ChartValue[][];
280
+ /** Which of them are drawn. */
281
+ visible: readonly boolean[];
282
+ /** And what colour each one is, by its original index. */
283
+ colors: readonly string[];
284
+ scale: ValueScale;
285
+ band: BandScale;
286
+ /** Bars run along the category axis rather than across it. */
287
+ horizontal: boolean;
288
+ /** Where a value sits along the value axis, in pixels from the chart's edge. */
289
+ valuePx: (value: number) => number;
290
+ /** Where a category's centre sits along the category axis. */
291
+ categoryPx: (index: number) => number;
292
+ /** The two combined, whichever way round the chart runs. */
293
+ point: (index: number, value: number) => {
294
+ x: number;
295
+ y: number;
296
+ };
297
+ /**
298
+ * The scale the *category* axis runs on, when `xScale` made it a second value
299
+ * axis. `null` on every chart whose categories are columns.
300
+ */
301
+ categoryScale: ValueScale | null;
302
+ /**
303
+ * Where a value sits along the category axis, in pixels from the chart's
304
+ * edge — the same absolute reckoning `valuePx` uses, and deliberately not
305
+ * `categoryPx`'s offset-along-the-axis. Only meaningful with `xScale="value"`.
306
+ */
307
+ categoryValuePx: (value: number) => number;
308
+ /** Where the baseline is along the value axis. */
309
+ zeroPx: number;
310
+ categories: readonly NebaChartCategory[];
311
+ format: (value: number) => string;
312
+ size: NebaSize;
313
+ }
314
+ /** The layout, plus everything the pointer decides. */
315
+ export interface CartesianContext extends CartesianLayout {
316
+ /** The series the legend is being hovered over, if any. */
317
+ hovered: number | null;
318
+ /** The category under the pointer, if any. */
319
+ activeIndex: number | null;
320
+ /** Every mark, when the chart supplied a builder. Empty otherwise. */
321
+ marks: readonly ChartMark[];
322
+ /** The one the pointer is on, or the one the arrow keys walked to. */
323
+ activeMark: ChartMark | null;
324
+ }
325
+ interface CartesianProps extends CartesianChartProps {
326
+ /**
327
+ * Makes the category axis a second value axis instead of a row of columns.
328
+ * `value` is what a scatter needs and what nothing else does.
329
+ * @default 'band'
330
+ */
331
+ xScale?: 'band' | 'value';
332
+ /**
333
+ * Builds every mark on the plot, which swaps the frame's column hit-testing
334
+ * for a nearest-mark search and makes the arrow keys walk this list. The
335
+ * result comes back on the context, so the marks are laid out once and drawn
336
+ * from the same array they are hit-tested against.
337
+ */
338
+ marks?: (layout: CartesianLayout) => readonly ChartMark[];
339
+ /**
340
+ * How far off a mark the pointer still counts as on it, in pixels. Added to
341
+ * the mark's own radius — a 4px dot is not a hit target.
342
+ * @default 24
343
+ */
344
+ markRadius?: number;
345
+ /** The table under the chart, for a chart whose data is not a grid. */
346
+ table?: (id: string) => React.ReactNode;
347
+ /** The legend's swatch, for a chart whose marks are not all the same shape. */
348
+ swatch?: (index: number, color: string) => React.ReactNode;
349
+ /**
350
+ * The value axis' scale, already worked out.
351
+ *
352
+ * For the axis that is not a count. `valueScale` rounds to 1-2-5, which is
353
+ * the family a reader does arithmetic in and exactly the wrong one for an
354
+ * instant — sixty, twenty-four, seven, twelve. A chart whose axis has its own
355
+ * arithmetic builds the scale itself and hands it over.
356
+ */
357
+ scale?: ValueScale;
358
+ /**
359
+ * What the tooltip says about a mark.
360
+ *
361
+ * Without it a mark is read as "this series at this category", which is right
362
+ * for anything whose marks sit in a grid the frame already understands. A
363
+ * Gantt's rows are the frame's *categories* and its marks are spans within
364
+ * them, so there is no cell for the frame to look the answer up in.
365
+ */
366
+ markTooltip?: (mark: ChartMark) => {
367
+ heading: React.ReactNode;
368
+ items: readonly ChartTooltipItem[];
369
+ } | null;
370
+ /** Bars, and only bars, run the other way. */
371
+ horizontal?: boolean;
372
+ /** The value axis measures totals rather than parts. */
373
+ stacked?: boolean;
374
+ /** A line chart is free to leave zero out; a bar chart is not. */
375
+ includeZero?: boolean;
376
+ /** How much of a band the marks take — bars need room reserved, lines do not. */
377
+ bandRatio?: number;
378
+ /**
379
+ * Lines and areas sit *on* the category ticks; bars sit *between* them. The
380
+ * difference is one half-step, and getting it wrong is what makes a line
381
+ * chart's first point float a centimetre off the axis.
382
+ */
383
+ inset?: boolean;
384
+ /** Extra room at the top of the plot, for value labels that ride the marks. */
385
+ headroom?: number;
386
+ /**
387
+ * Room on **every** side of the plot, for marks drawn from their centre.
388
+ *
389
+ * `headroom` is not enough for those: a bubble at the largest x hangs over the
390
+ * right edge and one at the smallest hangs over the value axis' own labels.
391
+ * A line's marker gets away with it because a line is inset from both ends
392
+ * anyway; a scatter places a mark wherever the number says, including exactly
393
+ * on the corner.
394
+ */
395
+ markInset?: number;
396
+ /** Draws the marks. */
397
+ children: (context: CartesianContext) => React.ReactNode;
398
+ }
399
+ /**
400
+ * The frame: two axes, a grid, a crosshair, a legend, a tooltip and the table.
401
+ *
402
+ * Everything here is one of two things — a measurement, or a piece of chrome
403
+ * that is identical on a line chart and a bar chart. The marks are the `children`
404
+ * function's business, and they are handed pixels rather than values so a
405
+ * component never has to know which way round the axes are.
406
+ */
407
+ export declare function CartesianChart({ series, categories, xAxis, yAxis, horizontal, stacked, includeZero, bandRatio, inset, headroom, markInset, xScale, marks, markRadius, table, swatch, scale: givenScale, markTooltip, height, format, locale, label, legend, tooltip, empty, size, variant, padded, className, children, ...box }: CartesianProps): React.JSX.Element;
408
+ export { ChartDataTable, ChartLegendBar, ChartScaleLegend, ChartSurface, ChartTooltipPanel, useMeasuredWidth, useVisibility };
409
+ export type { Visibility };
@@ -0,0 +1 @@
1
+ import{jsx as e,Fragment as t,jsxs as n}from"react/jsx-runtime";import*as a from"react";import{Box as l}from"../components/box/Box";import{bandScale as i,categoryAt as r,categoryCount as s,categoryExtent as o,chartFontSizes as c,compactNumber as d,extentOf as u,fitsLast as h,formatCategory as m,markerRadii as f,plotHeights as x,seriesColor as p,showsTick as g,textWidth as b,tickStride as v,toValues as y,truncate as k,valueScale as w}from"./chart";import{numberFormatter as M}from"./format";import{useMessages as N}from"./i18n";import{cx as z,metaTextClasses as S,srOnlyClasses as C,transitionClasses as A}from"./styles";const P="undefined"==typeof document?a.useEffect:a.useLayoutEffect,W=[];function B(e){const[t,n]=a.useState(0);return P(()=>{const t=e.current;if(!t)return;const a=()=>n(t.clientWidth);if(a(),"undefined"==typeof ResizeObserver)return;const l=new ResizeObserver(a);return l.observe(t),()=>l.disconnect()},[e]),t}function R(e){const[t,n]=a.useState(()=>{const t=new Set;return e.forEach((e,n)=>{e.hidden&&t.add(n)}),t}),[l,i]=a.useState(null),r=a.useCallback(e=>{n(t=>{const n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]);return{visible:e.map((e,n)=>!t.has(n)),hovered:l,toggle:r,setHovered:i}}const j={top:"flex-col-reverse",bottom:"flex-col",left:"flex-row-reverse",right:"flex-row"},F={start:"justify-start",center:"justify-center",end:"justify-end"};function E({series:a,colors:l,options:i,visibility:r,size:s,values:o,swatch:c}){const d=!1!==i.interactive,u="left"===i.side||"right"===i.side;return e("ul",{className:z("flex list-none flex-wrap items-center gap-x-3 gap-y-1 p-0",u?"min-w-0 flex-col items-start":"",F[i.align??"center"],S[s]),children:a.map((a,i)=>{const s=r.visible[i],u=null!==r.hovered&&r.hovered!==i,h=a.name??`${i+1}`,m=s?l[i]:"var(--neba-disabled-fg)",f=n(t,{children:[e("span",c?{"aria-hidden":"true",className:"flex size-2.5 shrink-0 items-center justify-center",children:c(i,m)}:{"aria-hidden":"true",className:"size-2.5 shrink-0 rounded-[0.1875rem]",style:{backgroundColor:m}}),e("span",{className:"min-w-0 truncate",children:h}),o?.[i]?e("span",{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:o[i]}):null]});return e("li",{className:"min-w-0",children:d?e("button",{type:"button","aria-pressed":s,onClick:()=>r.toggle(i),onPointerEnter:()=>r.setHovered(i),onPointerLeave:()=>r.setHovered(null),onFocus:()=>r.setHovered(i),onBlur:()=>r.setHovered(null),className:z("flex min-w-0 cursor-pointer items-center gap-1.5 rounded-(--neba-radius-xs)","px-1 py-0.5 text-(--neba-fg)",A,"hover:bg-(--n-soft)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-1",s?"":"text-(--neba-disabled-fg)",u?"opacity-55":""),children:f}):e("span",{className:z("flex min-w-0 items-center gap-1.5 px-1 py-0.5 text-(--neba-fg)",s?"":"text-(--neba-disabled-fg)"),children:f})},a.name??i)})})}function H({steps:a,from:l,to:i,middle:r,align:s,vertical:o,size:c}){return e("div",{className:z("flex",o?"":F[s]),children:n("div",{className:z("grid grid-cols-[auto_auto_auto] items-center gap-x-2",S[c]),children:[e("span",{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:l}),e("span",{"aria-hidden":"true",className:z("flex h-2.5 overflow-hidden rounded-[0.1875rem]",o?"w-20":"w-24"),children:a.map(t=>e("span",{className:"h-full flex-1",style:{backgroundColor:t}},t))}),e("span",{className:"shrink-0 tabular-nums text-(--neba-muted-fg)",children:i}),r?n(t,{children:[e("span",{}),e("span",{className:"text-center tabular-nums text-(--neba-muted-fg)",children:r}),e("span",{})]}):null]})})}function I({heading:t,items:a,x:l,y:i,flip:r,size:s}){return n("div",{role:"status","aria-live":"polite",className:z("pointer-events-none absolute z-10 max-w-56 min-w-24","rounded-(--neba-radius-sm) border p-2","[background-image:var(--neba-grain),var(--neba-sheen)]","[background-blend-mode:overlay,normal] [backdrop-filter:var(--neba-blur)]","bg-(--neba-panel-press) [border-color:var(--n-line)]","[box-shadow:var(--neba-shadow-2),var(--neba-plate-glass)]",S[s]),style:r?{right:`calc(100% - ${l}px + 10px)`,top:i}:{left:l+10,top:i},children:[e("div",{className:"mb-1 font-medium text-(--neba-fg)",children:t}),e("ul",{className:"flex list-none flex-col gap-0.5 p-0",children:a.map(t=>n("li",{className:"flex items-center gap-1.5",children:[e("span",{"aria-hidden":"true",className:"size-2 shrink-0 rounded-[0.125rem]",style:{backgroundColor:t.color}}),t.name?e("span",{className:"min-w-0 flex-1 truncate text-(--neba-muted-fg)",children:t.name}):null,e("span",{className:"ms-auto shrink-0 font-medium tabular-nums text-(--neba-fg)",children:t.label??t.formatted})]},t.seriesIndex))})]})}function _({id:t,caption:a,corner:l,categories:i,series:r,values:s,format:o,locale:c}){return n("table",{id:t,className:C,children:[a?e("caption",{children:a}):null,e("thead",{children:n("tr",{children:[e("th",{scope:"col",children:l??""}),r.map((t,n)=>e("th",{scope:"col",children:t.name??n+1},t.name??n))]})}),e("tbody",{children:i.map((t,a)=>n("tr",{children:[e("th",{scope:"row",children:m(t,c)}),r.map((t,n)=>{const l=s[n]?.[a];return e("td",void 0!==l?.label?{children:l.label}:{children:null==l?.value?"":o(l.value)},t.name??n)})]},a))})]})}function T({legend:t,legendSide:a,children:i,table:r,className:s,...o}){return n(l,{...o,className:z("relative flex gap-3",j[a],s??void 0),children:[e("div",{className:"relative min-w-0 flex-1",children:i}),t,r]})}export function CartesianChart({series:t,categories:l,xAxis:h,yAxis:g,horizontal:v=!1,stacked:C=!1,includeZero:A=!0,bandRatio:P=1,inset:j=!1,headroom:F=0,markInset:H=0,xScale:L="band",marks:V,markRadius:D=24,table:X,swatch:Y,scale:Z,markTooltip:O,height:K,format:U,locale:q,label:G,legend:J,tooltip:Q,empty:ee,size:te="md",variant:ne="text",padded:ae=!1,className:le,children:ie,...re}){const se=a.useRef(null),oe=B(se),ce=N(q),de=a.useId(),ue=R(t),[he,me]=a.useState(null),[fe,xe]=a.useState(null),[pe,ge]=a.useState(null),be=a.useCallback(e=>U?M(q,U).format(e):d(e,q),[U,q]),ve=a.useMemo(()=>y(t),[t]),ye=a.useMemo(()=>t.map((e,t)=>p(e,t)),[t]),ke=s(t),we=a.useMemo(()=>Array.from({length:ke},(e,t)=>r(t,l,ve)),[ke,l,ve]),Me=ve.filter((e,t)=>ue.visible[t]),Ne=u(Me,C),ze="number"==typeof K?K:void 0===K?x[te]:null,Se=c[te],Ce=g,Ae=h,Pe=Z??w(Ne,{min:Ce?.min,max:Ce?.max,tickCount:Ce?.tickCount,includeZero:A}),We="value"===L?o(Me,l):null,Be="value"===L?w(We,{min:Ae?.min,max:Ae?.max,tickCount:Ae?.tickCount,includeZero:!1}):null,Re=Pe.ticks.map((e,t)=>Ce?.tickFormat?String(Ce.tickFormat(e,t)):be(e)),je=Be?Be.ticks.map((e,t)=>Ae?.tickFormat?String(Ae.tickFormat(e,t)):d(e,q)):we.map((e,t)=>Ae?.tickFormat?String(Ae.tickFormat(e,t)):m(e,q)),Fe=Re.reduce((e,t)=>Math.max(e,b(t,Se)),0),Ee=Se+6,He=Ce?.hidden?0:Fe+10+(Ce?.label?Ee:0),Ie=(oe-(v?0:He)-16)/Math.max(1,ke),_e=Be?je:v||Ie-6>=2.4*Se?je.map(e=>k(e,v?150:Ie-6,Se)):je,Te=_e.reduce((e,t)=>Math.max(e,b(t,Se)),0),$e=v?Ae?.hidden?0:Te+10+(Ae?.label?Ee:0):He,Le=v?Ce?.hidden?0:Se+12+(Ce?.label?Ee:0):Ae?.hidden?0:Se+12+(Ae?.label?Ee:0),Ve=(v?Ae:Ce)?.thickness??$e,De=(v?Ce:Ae)?.thickness??Le,Xe=(v||Be?12:Math.max(8,_e.length?Te/2:8))+H,Ye=f[te]+4+F+H,Ze=ze??0,Oe={left:Ve+H,top:Ye,width:Math.max(0,oe-Ve-H-Xe),height:Math.max(0,Ze-Ye-De-H)},Ke=v?Oe.height:Oe.width,Ue=i(j?Math.max(1,ke-1):ke,Ke,P),qe=a.useCallback(e=>j?ke<=1?Ke/2:Ke*e/(ke-1):Ue.centre(e),[j,ke,Ke,Ue]),Ge=a.useCallback(e=>v?Oe.left+Pe.fraction(e)*Oe.width:Oe.top+(1-Pe.fraction(e))*Oe.height,[v,Oe.left,Oe.top,Oe.width,Oe.height,Pe]),Je=a.useCallback((e,t)=>v?{x:Ge(t),y:Oe.top+qe(e)}:{x:Oe.left+qe(e),y:Ge(t)},[v,Ge,qe,Oe.left,Oe.top]),Qe=a.useCallback(e=>v?Oe.top+(1-(Be?.fraction(e)??0))*Oe.height:Oe.left+(Be?.fraction(e)??0)*Oe.width,[v,Oe.left,Oe.top,Oe.width,Oe.height,Be]),et=Ge(Math.min(Math.max(0,Pe.min),Pe.max)),tt={plot:Oe,values:ve,visible:ue.visible,colors:ye,scale:Pe,band:Ue,horizontal:v,valuePx:Ge,categoryPx:qe,point:Je,categoryScale:Be,categoryValuePx:Qe,zeroPx:et,categories:we,format:be,size:te},nt=V?V(tt):W,at=!1===Q?{mode:"none"}:!0===Q||void 0===Q?{}:Q,lt=at.mode??(V?"item":"index"),it=null===fe?null:nt[fe]??null,rt=V?it?it.index:null:he,st=V?nt.length:ke,ot=()=>{me(null),xe(null),ge(null)},ct=e=>{const t=null===e?null:Math.min(st-1,Math.max(0,e));V?xe(t):me(t)},dt=e=>{ge(null);ct(((V?fe:he)??(e>0?-1:st))+e)},ut=null===rt?[]:t.flatMap((e,t)=>{if(!ue.visible[t]||it&&it.series!==t)return[];const n=ve[t]?.[rt];return n&&null!==n.value?[{seriesIndex:t,name:e.name,color:n.color??ye[t],value:n.value,formatted:be(n.value),label:n.label}]:[]}),ht=it&&O?O(it):null,mt=ht?ht.items:"item"===lt&&ut.length>1&&null!==pe?[ut.reduce((e,t)=>Math.abs(Ge(t.value??0)-pe)<Math.abs(Ge(e.value??0)-pe)?t:e)]:ut,ft=it?ve[it.series]?.[it.index]?.x??l?.[it.index]??it.index:void 0,xt=it?it.x:v?Ge(mt[0]?.value??0):Oe.left+qe(rt??0),pt=it?it.y:v?Oe.top+qe(rt??0):Oe.top,gt=it?(it.x-Oe.left)/Math.max(1,Oe.width)>.6:(v?Pe.fraction(mt[0]?.value??0):qe(rt??0)/Math.max(1,Ke))>.6,bt=!1===J?{interactive:!1}:!0===J||void 0===J?{}:J,vt=!0===J||!1!==J&&t.length>1,yt=bt.side??"bottom",kt={...tt,hovered:ue.hovered,activeIndex:rt,marks:nt,activeMark:it},wt=0===ke||null===Ne||"value"===L&&null===We;return e(T,{...re,size:te,variant:ne,padded:ae,className:le,legendSide:yt,legend:vt?e(E,{series:t,colors:ye,options:bt,visibility:ue,size:te,swatch:Y,values:bt.showValue&&null!==rt?t.map((e,t)=>{const n=ve[t]?.[rt]?.value;return null==n?void 0:be(n)}):void 0}):null,table:wt?null:X?.(de)??e(_,{id:de,caption:G,corner:Ae?.label,categories:we,series:t,values:ve,format:be,locale:q}),children:n("div",{ref:se,role:"img",tabIndex:wt?void 0:0,"aria-label":G,"aria-describedby":wt?void 0:de,onPointerMove:e=>{"none"!==lt&&(V?xe(((e,t)=>{const n=se.current;if(!n||0===nt.length)return null;const a=n.getBoundingClientRect(),l=e-a.left,i=t-a.top;let r=null,s=1/0,o=1/0;return nt.forEach((e,t)=>{const n=Math.hypot(e.x-l,e.y-i),a=void 0===e.rx?Math.max(0,n-e.r):Math.hypot(Math.max(0,Math.abs(e.x-l)-e.rx),Math.max(0,Math.abs(e.y-i)-(e.ry??e.rx)));a<=D&&(a<s||a===s&&n<o)&&(s=a,o=n,r=t)}),r})(e.clientX,e.clientY)):me(((e,t)=>{const n=se.current;if(!n||0===ke)return null;const a=n.getBoundingClientRect(),l=v?t-a.top-Oe.top:e-a.left-Oe.left;if(l<-Ue.step||l>Ke+Ue.step)return null;const i=j?ke<=1?0:Math.round(l/Ke*(ke-1)):Math.floor(l/Ue.step);return Math.min(ke-1,Math.max(0,i))})(e.clientX,e.clientY)),"item"===lt&&ge(((e,t)=>{const n=se.current;if(!n)return null;const a=n.getBoundingClientRect();return v?e-a.left:t-a.top})(e.clientX,e.clientY)))},onPointerLeave:ot,onKeyDown:"none"===lt?void 0:e=>{const t=v?"ArrowDown":"ArrowRight",n=v?"ArrowUp":"ArrowLeft";if(e.key===t)dt(1);else if(e.key===n)dt(-1);else if("Home"===e.key)ct(0);else if("End"===e.key)ct(st-1);else{if("Escape"!==e.key)return;ot()}e.preventDefault()},onBlur:ot,className:z("relative w-full","rounded-(--neba-radius-xs)","focus-visible:[outline:2px_solid_var(--n-ring)] focus-visible:outline-offset-2"),style:{height:ze??K},children:[wt?e("div",{className:z("flex h-full items-center justify-center text-(--neba-muted-fg)",S[te]),children:ee??ce.empty.title}):oe>0?n("svg",{width:oe,height:Ze||"100%",viewBox:`0 0 ${oe} ${Ze}`,"aria-hidden":"true",className:"block overflow-visible",children:[e($,{plot:Oe,scale:Pe,band:Ue,horizontal:v,inset:j,categoryPx:qe,valuePx:Ge,tickTexts:Re,categoryTexts:_e,categoryScale:Be,categoryValuePx:Qe,valueAxis:Ce,categoryAxis:Ae,fontSize:Se,zeroPx:et}),null===rt||V||"index"!==lt||!1===at.crosshair?null:(()=>{const t=qe(rt);return e("line",v?{x1:Oe.left,x2:Oe.left+Oe.width,y1:Oe.top+t,y2:Oe.top+t,stroke:"var(--neba-chart-baseline)",strokeWidth:1}:{x1:Oe.left+t,x2:Oe.left+t,y1:Oe.top,y2:Oe.top+Oe.height,stroke:"var(--neba-chart-baseline)",strokeWidth:1})})(),ie(kt)]}):null,null!==rt&&mt.length>0&&"none"!==lt?at.render?e("div",{className:"pointer-events-none absolute z-10",style:gt?{right:`calc(100% - ${xt}px + 10px)`,top:pt}:{left:xt+10,top:pt},children:at.render({index:rt,category:ft??we[rt],items:mt})}):e(I,{heading:ht?ht.heading:m(ft??we[rt],q),items:mt,x:xt,y:pt,flip:gt,size:te}):null]})})}function $({plot:a,scale:l,horizontal:i,categoryPx:r,valuePx:s,tickTexts:o,categoryTexts:c,categoryScale:d,categoryValuePx:u,valueAxis:m,categoryAxis:f,fontSize:x,zeroPx:p}){const y=!1!==m?.grid&&!m?.hidden,k=!f?.hidden&&(f?.grid??null!==d),w=e=>d?u(d.ticks[e]):(i?a.top:a.left)+r(e),M=v(c.length,i?a.height:a.width,i?1.8*x:Math.max(...c.map(e=>b(e,x)),1)+12),N=v(l.ticks.length,i?a.width:a.height,i?Math.max(...o.map(e=>b(e,x)),1)+16:2*x),z=c.length>1?Math.abs(w(1)-w(0)):a.width,S=l.ticks.length>1?Math.abs(s(l.ticks[1])-s(l.ticks[0])):a.height,C=h(c.length,M,z,i?1.8*x:b(c[c.length-1]??"",x)),A=h(l.ticks.length,N,S,i?b(o[o.length-1]??"",x):1.6*x);return n("g",{children:[l.ticks.map((t,r)=>{const c=s(t),d=Math.abs(t)<1e-9;return n("g",{children:[y?e("line",i?{x1:c,x2:c,y1:a.top,y2:a.top+a.height,stroke:d?"var(--neba-chart-baseline)":"var(--neba-chart-grid)",strokeWidth:1}:{x1:a.left,x2:a.left+a.width,y1:c,y2:c,stroke:d?"var(--neba-chart-baseline)":"var(--neba-chart-grid)",strokeWidth:1}):null,m?.hidden||!g(r,l.ticks.length,N,A)?null:e("text",i?{x:c,y:a.top+a.height+x+6,textAnchor:0===r?"start":r===l.ticks.length-1?"end":"middle",fontSize:x,fill:"var(--neba-muted-fg)",className:"tabular-nums",children:o[r]}:{x:a.left-8,y:c,textAnchor:"end",dominantBaseline:"central",fontSize:x,fill:"var(--neba-muted-fg)",className:"tabular-nums",children:o[r]})]},t)}),f?.hidden?null:n(t,{children:[e("line",i?{x1:p,x2:p,y1:a.top,y2:a.top+a.height,stroke:"var(--neba-chart-axis)",strokeWidth:1}:{x1:a.left,x2:a.left+a.width,y1:p,y2:p,stroke:"var(--neba-chart-axis)",strokeWidth:1}),c.map((t,l)=>{const r=w(l),s=g(l,c.length,M,C);return i?s?e("text",{x:a.left-8,y:r,textAnchor:"end",dominantBaseline:"central",fontSize:x,fill:"var(--neba-muted-fg)",className:d?"tabular-nums":void 0,children:t},l):null:n("g",{children:[k?e("line",{x1:r,x2:r,y1:a.top,y2:a.top+a.height,stroke:"var(--neba-chart-grid)",strokeWidth:1}):null,s?e("text",{x:r,y:a.top+a.height+x+6,textAnchor:d?0===l?"start":l===c.length-1?"end":"middle":"middle",fontSize:x,fill:"var(--neba-muted-fg)",className:d?"tabular-nums":void 0,children:t}):null]},l)})]}),m?.label?e("text",{x:i?a.left+a.width:a.left,y:i?a.top+a.height+2*x+12:a.top-8,textAnchor:i?"end":"start",fontSize:x,fill:"var(--neba-muted-fg)",fontWeight:500,children:m.label}):null,f?.label&&!i?e("text",{x:a.left+a.width,y:a.top+a.height+2*x+12,textAnchor:"end",fontSize:x,fill:"var(--neba-muted-fg)",fontWeight:500,children:f.label}):null]})}export{_ as ChartDataTable,E as ChartLegendBar,H as ChartScaleLegend,T as ChartSurface,I as ChartTooltipPanel,B as useMeasuredWidth,R as useVisibility};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The marks a LineChart and an AreaChart draw.
3
+ *
4
+ * They are one picture with one part switched off, which is exactly the case
5
+ * `internal/` exists for: an area is a line with the space under it filled, and
6
+ * a stacked area is that with each band sitting on the one below. Writing the
7
+ * path arithmetic twice would mean a `curve="smooth"` that curves differently
8
+ * depending on which of the two components a caller reached for.
9
+ *
10
+ * Sparkline deliberately does *not* come through here. It has no axes, no
11
+ * legend and no stacking, and what it needs from `chart.ts` is two function
12
+ * calls — routing it through a component built for a full plot would cost it
13
+ * the thing that makes it a sparkline.
14
+ */
15
+ import * as React from 'react';
16
+ import type { CartesianContext } from './chart-frame';
17
+ import type { NebaChartCurve, NebaChartValueLabels } from '../types';
18
+ /** Whether a point gets a dot on it. */
19
+ export type ChartMarkers = 'none' | 'auto' | 'all';
20
+ export interface LineSeriesProps {
21
+ context: CartesianContext;
22
+ curve: NebaChartCurve;
23
+ /** Fills the space between the line and whatever is under it. */
24
+ filled: boolean;
25
+ /** Each band sits on the total of the ones before it. */
26
+ stacked: boolean;
27
+ markers: ChartMarkers;
28
+ valueLabels: NebaChartValueLabels;
29
+ /**
30
+ * Bridges a gap instead of breaking at it. Off by default, and it should
31
+ * stay off unless the caller knows the gap is an artefact of collection
32
+ * rather than a month where nothing happened.
33
+ */
34
+ connectNulls: boolean;
35
+ /**
36
+ * Fades the line from a paler step of its own hue at the old end to the full
37
+ * colour at the new one. One hue throughout — a stroke that changes hue along
38
+ * its length is a second series pretending to be one.
39
+ */
40
+ gradient: boolean;
41
+ /** Unique per chart instance, so two charts' gradient defs cannot collide. */
42
+ idPrefix: string;
43
+ }
44
+ export declare function LineSeries({ context, curve, filled, stacked, markers, valueLabels, connectNulls, gradient, idPrefix }: LineSeriesProps): React.JSX.Element;
@@ -0,0 +1 @@
1
+ import{jsx as l,jsxs as e}from"react/jsx-runtime";import{areaPath as t,chartFontSizes as r,linePath as n,lineWidths as o,markerRadii as a,markGap as i}from"./chart";export function LineSeries({context:u,curve:s,filled:f,stacked:c,markers:p,valueLabels:d,connectNulls:x,gradient:h,idPrefix:m}){const{values:v,visible:k,colors:$,hovered:b,activeIndex:y,plot:g,point:j,zeroPx:C,size:L,format:W}=u,z=o[L],B=a[L],E=k.indexOf(!0),G=[],M=[];return v.forEach((l,e)=>{const t=l.map((l,e)=>M[e]??0);G.push(t),c&&k[e]&&l.forEach((l,e)=>{M[e]=(M[e]??0)+(l.value??0)})}),e("g",{children:[e("defs",{children:[h?$.map((t,r)=>e("linearGradient",{id:`${m}-stroke-${r}`,x1:"0",y1:"0",x2:"1",y2:"0",children:[l("stop",{offset:"0%",stopColor:`color-mix(in oklab, ${t} 45%, transparent)`}),l("stop",{offset:"100%",stopColor:t})]},`stroke-${r}`)):null,f&&!c?$.map((t,r)=>e("linearGradient",{id:`${m}-fill-${r}`,x1:"0",y1:"0",x2:"0",y2:"1",children:[l("stop",{offset:"0%",stopColor:`color-mix(in oklab, ${t} 28%, transparent)`}),l("stop",{offset:"100%",stopColor:`color-mix(in oklab, ${t} 2%, transparent)`})]},`fill-${r}`)):null]}),v.map((o,a)=>{if(!k[a])return null;const u=$[a],v=null!==b&&b!==a,M=o.map((l,e)=>{if(null===l.value)return null;const t=c?G[a][e]+l.value:l.value;return j(e,t)}),N=x?M.filter(Boolean):M,P=o.map((l,e)=>null===l.value?null:c?j(e,G[a][e]):{x:j(e,l.value).x,y:C}),S=f&&c,w=function(l,e){if("all"===e)return()=>!0;if("last"===e){let e=-1;for(let t=l.length-1;t>=0;t--)if(null!==l[t].value){e=t;break}return l=>l===e}let t=1/0,r=-1/0;for(const e of l)null!==e.value&&(t=Math.min(t,e.value),r=Math.max(r,e.value));return e=>{const n=l[e].value;return null!==n&&(n===t||n===r)}}(o,d);return e("g",{opacity:v?.28:1,children:[f?l("path",{d:t(N,x?P.filter(Boolean):P,s),fill:c?`color-mix(in oklab, ${u} 70%, transparent)`:`url(#${m}-fill-${a})`,stroke:"none"}):null,S&&a!==E?l("path",{d:n(x?P.filter(Boolean):P,s),fill:"none",stroke:"var(--neba-chart-gap)",strokeWidth:i}):null,S?null:l("path",{d:n(N,s),fill:"none",stroke:h?`url(#${m}-stroke-${a})`:u,strokeWidth:z,strokeLinecap:"round",strokeLinejoin:"round"}),M.map((e,t)=>{if(!e)return null;return"all"===p||"auto"===p&&o.length<=14||t===y?l("circle",{cx:e.x,cy:e.y,r:t===y?B+1:B,fill:o[t].color??u,stroke:"var(--neba-chart-gap)",strokeWidth:i},t):null}),"none"===d?null:M.map((e,t)=>{const n=o[t].value;return e&&null!==n&&w(t)?l("text",{x:e.x,y:e.y-B-5,textAnchor:e.x>g.left+g.width-24?"end":e.x<g.left+24?"start":"middle",fontSize:r[L],fontWeight:500,fill:"var(--neba-fg)",className:"tabular-nums",children:o[t].label??W(n)},`label-${t}`):null})]},a)})]})}