basalt-ui 2.2.0 → 2.4.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 (63) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/MIGRATING.md +78 -12
  3. package/agent/rules/basalt-state.md +1 -1
  4. package/configs/lefthook.yml +4 -1
  5. package/dist/charts/BandStrip.d.ts +7 -7
  6. package/dist/charts/BandStrip.d.ts.map +1 -1
  7. package/dist/charts/Bars.d.ts +4 -4
  8. package/dist/charts/Bars.d.ts.map +1 -1
  9. package/dist/charts/CartesianChart.d.ts.map +1 -1
  10. package/dist/charts/CartesianChart.js +6 -2
  11. package/dist/charts/ChartCard.d.ts +10 -10
  12. package/dist/charts/ChartCard.d.ts.map +1 -1
  13. package/dist/charts/ChartCard.js +2 -1
  14. package/dist/charts/Donut.d.ts +5 -5
  15. package/dist/charts/Donut.d.ts.map +1 -1
  16. package/dist/charts/DualPanel.d.ts +14 -10
  17. package/dist/charts/DualPanel.d.ts.map +1 -1
  18. package/dist/charts/DualPanel.js +32 -14
  19. package/dist/charts/Heatmap.d.ts +15 -15
  20. package/dist/charts/Heatmap.d.ts.map +1 -1
  21. package/dist/charts/Heatmap.js +2 -2
  22. package/dist/charts/Lines.js +2 -2
  23. package/dist/charts/MirroredBars.d.ts +9 -9
  24. package/dist/charts/MirroredBars.d.ts.map +1 -1
  25. package/dist/charts/MirroredBars.js +8 -7
  26. package/dist/charts/Sparkline.d.ts +6 -6
  27. package/dist/charts/Sparkline.d.ts.map +1 -1
  28. package/dist/charts/StackedArea.d.ts +2 -2
  29. package/dist/charts/StackedArea.d.ts.map +1 -1
  30. package/dist/charts/compile.d.ts +25 -2
  31. package/dist/charts/compile.d.ts.map +1 -1
  32. package/dist/charts/compile.js +204 -34
  33. package/dist/charts/index.d.ts +1 -0
  34. package/dist/charts/index.d.ts.map +1 -1
  35. package/dist/charts/index.js +3 -1
  36. package/dist/charts/marks.d.ts +8 -0
  37. package/dist/charts/marks.d.ts.map +1 -1
  38. package/dist/charts/marks.js +22 -1
  39. package/dist/charts/panel.js +2 -2
  40. package/dist/charts/types.d.ts +101 -61
  41. package/dist/charts/types.d.ts.map +1 -1
  42. package/dist/state/fields.d.ts +19 -3
  43. package/dist/state/fields.d.ts.map +1 -1
  44. package/dist/state/fields.js +14 -8
  45. package/llms.txt +2 -2
  46. package/package.json +1 -1
  47. package/src/charts/BandStrip.tsx +12 -10
  48. package/src/charts/Bars.tsx +4 -4
  49. package/src/charts/CartesianChart.tsx +7 -2
  50. package/src/charts/ChartCard.tsx +17 -11
  51. package/src/charts/Donut.tsx +5 -5
  52. package/src/charts/DualPanel.tsx +50 -21
  53. package/src/charts/Heatmap.tsx +14 -14
  54. package/src/charts/Lines.tsx +2 -2
  55. package/src/charts/MirroredBars.tsx +16 -15
  56. package/src/charts/Sparkline.tsx +6 -6
  57. package/src/charts/StackedArea.tsx +2 -2
  58. package/src/charts/compile.ts +285 -36
  59. package/src/charts/index.ts +1 -0
  60. package/src/charts/marks.ts +35 -1
  61. package/src/charts/panel.tsx +2 -2
  62. package/src/charts/types.ts +105 -57
  63. package/src/state/fields.ts +55 -19
@@ -27,7 +27,7 @@ export type BarsBar<T> = Pick<
27
27
  'key' | 'label' | 'color' | 'getValue' | 'formatValue' | 'tooltip' | 'legend' | 'role' | 'note'
28
28
  > & {
29
29
  /** Default 0.85. */
30
- fillOpacity?: number
30
+ fillOpacity?: number | undefined
31
31
  }
32
32
 
33
33
  /** A line overlay; `axis: 'right'` reads the chart's `y2`. */
@@ -54,11 +54,11 @@ export type BarsProps<T, X extends ChartX = ChartX> = Omit<
54
54
  'marks' | 'series'
55
55
  > & {
56
56
  bars: readonly BarsBar<T>[]
57
- lines?: readonly BarsLine<T>[]
57
+ lines?: readonly BarsLine<T>[] | undefined
58
58
  /** Default `'stacked'`. `'normalized'` stacks each x to its share of the total. */
59
- layout?: 'stacked' | 'grouped' | 'normalized'
59
+ layout?: 'stacked' | 'grouped' | 'normalized' | undefined
60
60
  /** Per-bar opacity (a partial week, an estimate). Overrides the series' `fillOpacity`. */
61
- barOpacity?: (d: T, key: string) => number
61
+ barOpacity?: ((d: T, key: string) => number) | undefined
62
62
  }
63
63
 
64
64
  const DEFAULT_BAR_OPACITY = 0.85
@@ -9,7 +9,7 @@
9
9
  import { useCallback, useId, useMemo, useState } from 'react'
10
10
  import type { CSSProperties, ReactElement, ReactNode } from 'react'
11
11
  import { useInChartCard } from './card-context'
12
- import { compileCartesian } from './compile'
12
+ import { compileCartesian, refLegendSeries } from './compile'
13
13
  import type { CartesianDefinition } from './compile'
14
14
  import { ChartEngine, idPrefixOf } from './host'
15
15
  import { ChartLegend, legendEntries } from './legend'
@@ -170,9 +170,14 @@ export function CartesianRung<T, X extends ChartX>(
170
170
  (ctx: ShellContext) => compileCartesian({ ...stable, ...ctx }),
171
171
  [stable],
172
172
  )
173
+ // Reference lines that name themselves join the legend after the series (role `reference`).
174
+ const legendSeries = useMemo(
175
+ () => [...stable.series, ...refLegendSeries<T>(stable.refLines)],
176
+ [stable.series, stable.refLines],
177
+ )
173
178
  return (
174
179
  <ChartShell
175
- series={series}
180
+ series={legendSeries}
176
181
  compile={compile}
177
182
  ariaLabel={ariaLabel}
178
183
  {...(legend !== undefined && { legend })}
@@ -92,32 +92,38 @@ export type ChartCardSlot = 'root' | 'header' | 'body'
92
92
 
93
93
  export type ChartCardProps = BasaltProps &
94
94
  SlotStylesProps<ChartCardSlot> & {
95
- title?: string
95
+ title?: string | undefined
96
96
  icon?: ReactNode
97
97
  /** A muted line below the title row; does not by itself render the header. */
98
- subtitle?: string
98
+ subtitle?: string | undefined
99
99
  /** `WidgetHeader`'s info glyph beside the title. */
100
- info?: string
100
+ info?: string | undefined
101
101
  /** A pre-formatted metric value, with `delta` on the hero row. */
102
- value?: string
103
- delta?: number
104
- deltaPeriod?: string
105
- deltaPolarity?: DeltaPolarity
102
+ value?: string | undefined
103
+ delta?: number | undefined
104
+ deltaPeriod?: string | undefined
105
+ deltaPolarity?: DeltaPolarity | undefined
106
106
  /** A mono count tag after the title. */
107
- count?: number
107
+ count?: number | undefined
108
108
  /** Right-aligned controls. */
109
109
  actions?: ReactNode
110
110
  /** A resolved state replaces `children` with its placeholder; the header stays. */
111
- state?: ChartState
111
+ state?: ChartState | undefined
112
112
  /** Body height while a placeholder shows. Default: the chart height law, i.e. exactly the box an
113
113
  * unsized chart takes — pass the chart's own `height` when it states one, so a `<Suspense
114
114
  * fallback={<ChartCard state={{ pending: true }} …/>}>` reserves the final size. */
115
- placeholderHeight?: number | ResponsiveChartHeight
115
+ placeholderHeight?: number | ResponsiveChartHeight | undefined
116
116
  /** A retry button or a "clear filters" link under the placeholder. */
117
117
  stateAction?: ReactNode
118
118
  children?: ReactNode
119
119
  }
120
120
 
121
+ /** Drops explicit `undefined`s: `WidgetHeader` is exact-optional, this props type is not. */
122
+ const definedOnly = <T extends object>(o: T): { [K in keyof T]?: Exclude<T[K], undefined> } =>
123
+ Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined)) as {
124
+ [K in keyof T]?: Exclude<T[K], undefined>
125
+ }
126
+
121
127
  /** A header renders when one of these is set (a subtitle or delta alone does not). */
122
128
  const HEADER_TRIGGERS = ['title', 'info', 'value', 'icon', 'count'] as const
123
129
 
@@ -150,7 +156,7 @@ export function ChartCard({
150
156
  <div className={cx(classes.header, classNames?.header)}>
151
157
  <WidgetHeader
152
158
  tier="widget"
153
- {...header}
159
+ {...definedOnly(header)}
154
160
  title={header.title ?? ''}
155
161
  {...(actions !== undefined && {
156
162
  actions: <span data-basalt-tier="widget">{actions}</span>,
@@ -34,13 +34,13 @@ export type DonutProps<K extends string = string> = BasaltProps & {
34
34
  colorForKey: (key: K) => string
35
35
  formatValue: (v: number) => string
36
36
  /** Legend and tooltip label for a key. Default: the key. */
37
- seriesLabel?: (key: K) => string
37
+ seriesLabel?: ((key: K) => string) | undefined
38
38
  /** The ring's centre text, and the smaller line under it. */
39
- centerLabel?: string
40
- centerSubLabel?: string
39
+ centerLabel?: string | undefined
40
+ centerSubLabel?: string | undefined
41
41
  /** Default 240. */
42
- height?: number | ResponsiveChartHeight
43
- state?: ChartState
42
+ height?: number | ResponsiveChartHeight | undefined
43
+ state?: ChartState | undefined
44
44
  }
45
45
 
46
46
  /** Slices kept before the rest fold into "Other". */
@@ -14,7 +14,7 @@ import { useCallback, useMemo } from 'react'
14
14
  import type { ReactElement } from 'react'
15
15
  import { VX, alpha } from '../tokens'
16
16
  import { resolveContainerClass } from '../tokens/size-classes'
17
- import { defaultFormatX, defaultNumberFormat, visibleSeries } from './compile'
17
+ import { defaultFormatX, defaultNumberFormat, engineRow, seriesRow, visibleSeries } from './compile'
18
18
  import { barMark, emphasis, lineMark, markersOf, thinFill } from './marks'
19
19
  import { PanelRung, paneX, paneY, rowsOf } from './panel'
20
20
  import type { PaneBuilder, PanelInput, PanelPlan } from './panel'
@@ -61,15 +61,17 @@ export type DualPanelBar<T> = {
61
61
  positive: string
62
62
  /** The fill below zero. */
63
63
  negative: string
64
- /** Tick and tooltip formatter. */
64
+ /** Tick formatter, and the tooltip's too unless `tooltipFormat` is given. */
65
65
  format: (v: number) => string
66
+ /** The tooltip row's formatter. Default: `format`. */
67
+ tooltipFormat?: ((v: number) => string) | undefined
66
68
  /** The tooltip row's value, for a unit or a decimal `format` cannot carry. */
67
- formatValue?: (v: number, d: T) => string
69
+ formatValue?: ((v: number, d: T) => string) | undefined
68
70
  /** Default `'auto'`: a symmetric `[-maxAbs, maxAbs]` from the data, rounded to nice ticks. A tuple
69
71
  * is used verbatim. */
70
- domain?: readonly [number, number] | 'auto'
72
+ domain?: readonly [number, number] | 'auto' | undefined
71
73
  /** When `'auto'`: floors `maxAbs`, so a plateau does not amplify to fill the pane. */
72
- maxAbsFloor?: number
74
+ maxAbsFloor?: number | undefined
73
75
  }
74
76
 
75
77
  export type DualPanelProps<T, X extends Date | number = Date | number> = Pick<
@@ -91,15 +93,24 @@ export type DualPanelProps<T, X extends Date | number = Date | number> = Pick<
91
93
  series: readonly DualPanelLine<T>[]
92
94
  /** Top pane y axis. Default domain `'auto'`: the visible lines' span plus 8%, rounded to nice
93
95
  * ticks (not zero-based: the interesting range is often a narrow band far from zero). */
94
- top?: { domain?: readonly [number, number] | 'auto'; format?: (v: number) => string }
96
+ top?:
97
+ | {
98
+ domain?: readonly [number, number] | 'auto' | undefined
99
+ format?: ((v: number) => string) | undefined
100
+ /** The lines' tooltip formatter. Default: `format`. */
101
+ tooltipFormat?: ((v: number) => string) | undefined
102
+ }
103
+ | undefined
95
104
  /**
96
105
  * Shades the band between two top lines (by key), where both are visible. `aboveFill` colours the
97
106
  * side where `to` runs above `from`; omitted, both sides take `fill`.
98
107
  */
99
- fillBetween?: { from: string; to: string; fill: string; aboveFill?: string }
108
+ fillBetween?:
109
+ | { from: string; to: string; fill: string; aboveFill?: string | undefined }
110
+ | undefined
100
111
  bar: DualPanelBar<T>
101
112
  /** The top pane's share of the chart height. Default 0.62. */
102
- topFraction?: number
113
+ topFraction?: number | undefined
103
114
  }
104
115
 
105
116
  type FillRow<T, X> = { x: X; from: number; to: number; series: string; datum: T }
@@ -150,6 +161,8 @@ export function DualPanel<T, X extends Date | number = Date | number>(
150
161
  )
151
162
  const all = useMemo(() => [...lines, barSeries], [lines, barSeries])
152
163
  const topFormat = top?.format ?? defaultNumberFormat
164
+ const topTooltipFormat = top?.tooltipFormat ?? topFormat
165
+ const barTooltipFormat = bar.tooltipFormat ?? bar.format
153
166
 
154
167
  const plan = useCallback(
155
168
  ({ hidden, highlighted }: PanelInput): PanelPlan<T> => {
@@ -300,26 +313,42 @@ export function DualPanel<T, X extends Date | number = Date | number>(
300
313
  for (const s of visible) {
301
314
  const v = s.getValue(d)
302
315
  if (s.tooltip === false || v === null || !Number.isFinite(v)) continue
303
- out.push({
304
- label: s.note === undefined ? s.label : `${s.label} · ${s.note}`,
305
- value: s.formatValue ? s.formatValue(v, d) : topFormat(v),
306
- color: s.color,
307
- ...(highlighted === s.key && { active: true }),
308
- })
316
+ out.push(
317
+ seriesRow(
318
+ s,
319
+ s.formatValue ? s.formatValue(v, d) : topTooltipFormat(v),
320
+ highlighted === s.key,
321
+ ),
322
+ )
309
323
  }
310
324
  const v = barOn ? bar.getValue(d) : null
311
325
  if (v !== null && Number.isFinite(v))
312
- out.push({
313
- label: bar.label,
314
- value: bar.formatValue ? bar.formatValue(v, d) : bar.format(v),
315
- color: v >= 0 ? bar.positive : bar.negative,
316
- ...(highlighted === BAR_KEY && { active: true }),
317
- })
326
+ out.push(
327
+ engineRow({
328
+ label: bar.label,
329
+ value: bar.formatValue ? bar.formatValue(v, d) : barTooltipFormat(v),
330
+ color: v >= 0 ? bar.positive : bar.negative,
331
+ active: highlighted === BAR_KEY,
332
+ }),
333
+ )
318
334
  return out
319
335
  },
320
336
  }
321
337
  },
322
- [data, x, lines, barSeries, top, fillBetween, bar, topFraction, topFormat, formatX],
338
+ [
339
+ data,
340
+ x,
341
+ lines,
342
+ barSeries,
343
+ top,
344
+ fillBetween,
345
+ bar,
346
+ topFraction,
347
+ topFormat,
348
+ topTooltipFormat,
349
+ barTooltipFormat,
350
+ formatX,
351
+ ],
323
352
  )
324
353
 
325
354
  return <PanelRung {...rung} series={all} plan={plan} />
@@ -18,7 +18,7 @@ import type { CSSProperties, ReactElement } from 'react'
18
18
  import type { BasaltProps } from '../common/props'
19
19
  import { alpha, VX } from '../tokens'
20
20
  import { resolveContainerClass } from '../tokens/size-classes'
21
- import { strideTicks } from './compile'
21
+ import { engineRow, strideTicks } from './compile'
22
22
  import type { CartesianDefinition } from './compile'
23
23
  import { ChartEngine, idPrefixOf } from './host'
24
24
  import { useCoarsePointer } from '../common/use-media-query'
@@ -38,28 +38,28 @@ export type HeatmapProps<T> = BasaltProps & {
38
38
  /** The intensity; `null` is an absent cell (flat neutral), never a zero. */
39
39
  getValue: (d: T) => number | null
40
40
  /** Explicit band order. Default: first seen in `data`. */
41
- rows?: readonly string[]
42
- cols?: readonly string[]
41
+ rows?: readonly string[] | undefined
42
+ cols?: readonly string[] | undefined
43
43
  /** The ink at full intensity, a `VX.*` ref or a series token. Default `VX.line`. */
44
- color?: string
44
+ color?: string | undefined
45
45
  /** The value range the color scale spans. Default `[0, max]` of the data. */
46
- domain?: readonly [number, number]
46
+ domain?: readonly [number, number] | undefined
47
47
  /** Tooltip, legend-end and `aria` value format. Default: the number as-is. */
48
- formatValue?: (v: number) => string
48
+ formatValue?: ((v: number) => string) | undefined
49
49
  /** Band tick and tooltip header labels. Default: the band key. */
50
- formatRow?: (row: string) => string
51
- formatCol?: (col: string) => string
50
+ formatRow?: ((row: string) => string) | undefined
51
+ formatCol?: ((col: string) => string) | undefined
52
52
  /** `false` hides the gradient legend; `label` titles it. */
53
- legend?: false | { label?: string }
53
+ legend?: false | { label?: string | undefined } | undefined
54
54
  /** Rows after the value row, per cell (a sample count, a failure reason). Called with the datum. */
55
- tooltip?: false | { rows?: (d: T) => readonly ChartTooltipRow[] }
55
+ tooltip?: (false | { rows?: ((d: T) => readonly ChartTooltipRow[]) | undefined }) | undefined
56
56
  /** A fixed height, or one per container class. Default: by row count (160–420px). */
57
- height?: number | ResponsiveChartHeight
57
+ height?: number | ResponsiveChartHeight | undefined
58
58
  /** Fill the parent's height instead. Overrides `height`. CSS-owned like every other kind's box
59
59
  * (`ChartBox`, no measuring, SSR-stable), so the parent needs a definite CSS height — a grid or
60
60
  * flex stretch, `h-full`, an explicit height — which no kind can read off an auto-height parent. */
61
- matchHeight?: boolean
62
- state?: ChartState
61
+ matchHeight?: boolean | undefined
62
+ state?: ChartState | undefined
63
63
  }
64
64
 
65
65
  /** Intensity steps: quantized, so the gradient legend and the cells are the same ramp. */
@@ -244,7 +244,7 @@ export function Heatmap<T>(props: HeatmapProps<T>): ReactElement {
244
244
  ...(point.color && { color: point.color }),
245
245
  },
246
246
  ]
247
- return { title: header(c), rows: [...value, ...extra] }
247
+ return { title: header(c), rows: [...value, ...extra].map(engineRow) }
248
248
  },
249
249
  }
250
250
  : false,
@@ -17,7 +17,7 @@ import { VX } from '../tokens'
17
17
  import { CartesianRung } from './CartesianChart'
18
18
  import { areaGradientId } from './compile'
19
19
  import { chartCurve } from './curves'
20
- import { lineMark, markersOf, yScaleOf } from './marks'
20
+ import { drawnRows, lineMark, markersOf, yScaleOf } from './marks'
21
21
  import { rowX } from './types'
22
22
  import type {
23
23
  CartesianChartProps,
@@ -120,7 +120,7 @@ export function Lines<T, X extends ChartX = ChartX>(props: LinesProps<T, X>): Re
120
120
  if (!s.area) continue
121
121
  out.push(
122
122
  decorative(
123
- areaY(plot.rows(s.key), {
123
+ areaY(drawnRows(plot, s), {
124
124
  id: `${s.key}-area`,
125
125
  x: rowX,
126
126
  y2: 'y',
@@ -21,7 +21,7 @@ import { useCallback, useMemo } from 'react'
21
21
  import type { ReactElement } from 'react'
22
22
  import { VX, alpha } from '../tokens'
23
23
  import { resolveContainerClass } from '../tokens/size-classes'
24
- import { defaultFormatX, defaultNumberFormat, visibleSeries } from './compile'
24
+ import { defaultFormatX, defaultNumberFormat, seriesRow, visibleSeries } from './compile'
25
25
  import { barMark, emphasis } from './marks'
26
26
  import { PanelRung, paneX, paneY, rowsOf } from './panel'
27
27
  import type { PaneBuilder, PanelInput, PanelPlan } from './panel'
@@ -35,11 +35,11 @@ export type MirroredBarPane = {
35
35
  * entry throws: the pane would vanish, which reads as a measured zero. */
36
36
  key: string
37
37
  /** The pane's upper bound. `'auto'` (default) is its own visible maximum; a number pins it. */
38
- max?: number | 'auto'
38
+ max?: number | 'auto' | undefined
39
39
  /** When `'auto'`: floors the upper bound, so a quiet window does not amplify noise to full height. */
40
- autoMaxFloor?: number
40
+ autoMaxFloor?: number | undefined
41
41
  /** Tick count for this pane's own axis. Default 3. */
42
- ticks?: number
42
+ ticks?: number | undefined
43
43
  /** Tick and tooltip formatter, in the pane's OWN units. */
44
44
  format: (v: number) => string
45
45
  }
@@ -71,18 +71,18 @@ export type MirroredBarsProps<T, X extends ChartX = ChartX> = Pick<
71
71
  /** Drawn below the baseline. */
72
72
  down: MirroredBarPane
73
73
  /** The up pane's share of the height. Default 0.35: the pair is usually asymmetric. */
74
- upFraction?: number
74
+ upFraction?: number | undefined
75
75
  /** 0..1 of a bar's width that no source sample covers, drawn neutral across both panes. */
76
- getAbsentFraction?: (d: T) => number
76
+ getAbsentFraction?: ((d: T) => number) | undefined
77
77
  /** Per-datum bar opacity: a real but qualified measurement (a short bucket) drawn dimmer. */
78
- getBarOpacity?: (d: T) => number
78
+ getBarOpacity?: ((d: T) => number) | undefined
79
79
  /**
80
80
  * Collapse adjacent data where one band per datum would be sub-pixel. `merge` is the consumer's
81
81
  * (max, sum, or a rate from summed parts) and must keep `group[0]`'s x, the slot start.
82
82
  */
83
- fold?: { minBandPx?: number; merge: (group: T[]) => T }
83
+ fold?: { minBandPx?: number | undefined; merge: (group: T[]) => T } | undefined
84
84
  /** Default `'leading'`: x is a slot's start. */
85
- cursorResolution?: CartesianChartProps<T, X>['cursorResolution']
85
+ cursorResolution?: CartesianChartProps<T, X>['cursorResolution'] | undefined
86
86
  }
87
87
 
88
88
  const DEFAULT_UP_FRACTION = 0.35
@@ -277,12 +277,13 @@ export function MirroredBars<T, X extends ChartX = ChartX>(
277
277
  // Each pane's row falls back to ITS OWN formatter: the panes are in different units.
278
278
  const fallback =
279
279
  s.key === up.key ? up.format : s.key === down.key ? down.format : defaultNumberFormat
280
- out.push({
281
- label: s.note === undefined ? s.label : `${s.label} · ${s.note}`,
282
- value: s.formatValue ? s.formatValue(v, d) : fallback(v),
283
- color: s.color,
284
- ...(highlighted === s.key && { active: true }),
285
- })
280
+ out.push(
281
+ seriesRow(
282
+ s,
283
+ s.formatValue ? s.formatValue(v, d) : fallback(v),
284
+ highlighted === s.key,
285
+ ),
286
+ )
286
287
  }
287
288
  return out
288
289
  },
@@ -29,18 +29,18 @@ export type SparklineProps = BasaltProps & {
29
29
  /** Height in px. */
30
30
  height: number
31
31
  /** Width in px. Default: the container's, measured by the host. */
32
- width?: number
32
+ width?: number | undefined
33
33
  /** Default `'line'`. */
34
- mark?: 'line' | 'bar'
34
+ mark?: 'line' | 'bar' | undefined
35
35
  /** A `VX.*` ref or a series token. Default `VX.faint`. */
36
- color?: string
36
+ color?: string | undefined
37
37
  /** Paints the last point in `emphasisColor` — the one reading a trend beside a KPI is for. */
38
- emphasizeLast?: boolean
38
+ emphasizeLast?: boolean | undefined
39
39
  /** Default `VX.accent`. */
40
- emphasisColor?: string
40
+ emphasisColor?: string | undefined
41
41
  /** Pending / error / empty, the same contract as every other kind. The placeholder fills the
42
42
  * sparkline's own `width` × `height`, so a loading tile does not shift when the trend lands. */
43
- state?: ChartState
43
+ state?: ChartState | undefined
44
44
  }
45
45
 
46
46
  type Point = { i: number; v: number | null }
@@ -25,7 +25,7 @@ export type StackedAreaBand<T> = Pick<
25
25
  'key' | 'label' | 'color' | 'getValue' | 'formatValue' | 'tooltip' | 'legend' | 'role' | 'note'
26
26
  > & {
27
27
  /** Default 0.85. */
28
- fillOpacity?: number
28
+ fillOpacity?: number | undefined
29
29
  }
30
30
 
31
31
  export type StackedAreaProps<T, X extends ChartX = ChartX> = Omit<
@@ -35,7 +35,7 @@ export type StackedAreaProps<T, X extends ChartX = ChartX> = Omit<
35
35
  /** The bands, bottom to top. */
36
36
  series: readonly StackedAreaBand<T>[]
37
37
  /** No `scale`: a log axis has no additive zero to stack from. */
38
- y?: Omit<NonNullable<CartesianChartProps<T, X>['y']>, 'scale'>
38
+ y?: Omit<NonNullable<CartesianChartProps<T, X>['y']>, 'scale'> | undefined
39
39
  }
40
40
 
41
41
  export function StackedArea<T, X extends ChartX = ChartX>(