nuxt-charts 3.0.0-beta.3 → 3.0.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 (62) hide show
  1. package/README.md +46 -1
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +0 -1
  4. package/dist/runtime/assets/components.css +1 -1
  5. package/dist/runtime/assets/theme.css +1 -1
  6. package/dist/runtime/components/AreaChart.vue +7 -1
  7. package/dist/runtime/components/BarChart.vue +7 -1
  8. package/dist/runtime/components/BubbleChart.vue +43 -17
  9. package/dist/runtime/components/CandlestickChart.vue +60 -18
  10. package/dist/runtime/components/DonutChart.vue +28 -9
  11. package/dist/runtime/components/FunnelChart.vue +31 -8
  12. package/dist/runtime/components/LineChart.vue +7 -1
  13. package/dist/runtime/components/RadarChart.vue +25 -4
  14. package/dist/runtime/components/RadialBarChart.vue +48 -8
  15. package/dist/runtime/components/SankeyChart.vue +32 -9
  16. package/dist/runtime/components/StatusTrackerChart.vue +33 -7
  17. package/dist/runtime/components/internal/CandlestickTooltip.vue +6 -4
  18. package/dist/runtime/components/internal/CandlestickTooltip.vue.d.ts +1 -0
  19. package/dist/runtime/components/internal/CartesianFrame.vue +37 -9
  20. package/dist/runtime/components/internal/ChartAccessibility.vue +20 -0
  21. package/dist/runtime/components/internal/{ChartSkeleton.d.vue.ts → ChartAccessibility.vue.d.ts} +13 -10
  22. package/dist/runtime/components/internal/ChartEmptyState.vue +12 -0
  23. package/dist/runtime/components/internal/{CandlestickTooltip.d.vue.ts → ChartEmptyState.vue.d.ts} +2 -12
  24. package/dist/runtime/components/internal/ChartLegend.vue.d.ts +1 -1
  25. package/dist/runtime/components/internal/ChartTooltip.vue +2 -1
  26. package/dist/runtime/components/internal/CubeBarShape.vue.d.ts +1 -1
  27. package/dist/runtime/components/internal/FunnelClassicShape.vue +2 -1
  28. package/dist/runtime/components/internal/FunnelLayeredShape.vue +2 -1
  29. package/dist/runtime/components/internal/FunnelTooltip.vue +2 -1
  30. package/dist/runtime/components/internal/tooltipContent.d.ts +1 -1
  31. package/dist/runtime/components/internal/tooltipContent.js +6 -2
  32. package/dist/runtime/types/charts.d.ts +44 -34
  33. package/dist/runtime/types/shared.d.ts +5 -11
  34. package/dist/runtime/utils/categories.d.ts +1 -1
  35. package/dist/runtime/utils/categories.js +2 -2
  36. package/dist/runtime/utils/data.d.ts +19 -0
  37. package/dist/runtime/utils/data.js +50 -0
  38. package/dist/runtime/utils/format.d.ts +5 -0
  39. package/dist/runtime/utils/format.js +12 -0
  40. package/dist/runtime/utils/index.d.ts +2 -0
  41. package/dist/runtime/utils/index.js +2 -0
  42. package/dist/runtime/utils/theme.js +3 -0
  43. package/package.json +2 -2
  44. package/dist/runtime/components/AreaChart.d.vue.ts +0 -23
  45. package/dist/runtime/components/BarChart.d.vue.ts +0 -23
  46. package/dist/runtime/components/BubbleChart.d.vue.ts +0 -23
  47. package/dist/runtime/components/CandlestickChart.d.vue.ts +0 -19
  48. package/dist/runtime/components/DonutChart.d.vue.ts +0 -21
  49. package/dist/runtime/components/FunnelChart.d.vue.ts +0 -26
  50. package/dist/runtime/components/LineChart.d.vue.ts +0 -23
  51. package/dist/runtime/components/RadarChart.d.vue.ts +0 -19
  52. package/dist/runtime/components/RadialBarChart.d.vue.ts +0 -19
  53. package/dist/runtime/components/SankeyChart.d.vue.ts +0 -36
  54. package/dist/runtime/components/StatusTrackerChart.d.vue.ts +0 -19
  55. package/dist/runtime/components/internal/CartesianFrame.d.vue.ts +0 -57
  56. package/dist/runtime/components/internal/ChartLegend.d.vue.ts +0 -34
  57. package/dist/runtime/components/internal/ChartTooltip.d.vue.ts +0 -3
  58. package/dist/runtime/components/internal/CubeBarShape.d.vue.ts +0 -36
  59. package/dist/runtime/components/internal/FunnelClassicShape.d.vue.ts +0 -81
  60. package/dist/runtime/components/internal/FunnelLayeredShape.d.vue.ts +0 -63
  61. package/dist/runtime/components/internal/FunnelTooltip.d.vue.ts +0 -16
  62. package/dist/runtime/components/internal/VariantBarShape.d.vue.ts +0 -36
@@ -28,6 +28,9 @@ import ChartTooltip from "./ChartTooltip.vue";
28
28
  import ChartLegend from "./ChartLegend.vue";
29
29
  import ChartBackground from "./ChartBackground";
30
30
  import ChartSkeleton from "./ChartSkeleton.vue";
31
+ import ChartEmptyState from "./ChartEmptyState.vue";
32
+ import ChartAccessibility from "./ChartAccessibility.vue";
33
+ import { DEFAULT_MAX_DATA_POINTS, normalizeNumericRows, sampleData, warnDataLimit } from "../../utils/data";
31
34
  const props = defineProps({
32
35
  data: { type: Array, required: true },
33
36
  height: { type: Number, required: true },
@@ -58,7 +61,6 @@ const props = defineProps({
58
61
  xAxisConfig: { type: Object, required: false },
59
62
  yAxisConfig: { type: Object, required: false },
60
63
  yAxes: { type: Object, required: false },
61
- tooltip: { type: Object, required: false },
62
64
  referenceLines: { type: Array, required: false },
63
65
  syncId: { type: String, required: false },
64
66
  minMaxTicksOnly: { type: Boolean, required: false },
@@ -67,6 +69,12 @@ const props = defineProps({
67
69
  crosshairConfig: { type: Object, required: false },
68
70
  theme: { type: Object, required: false },
69
71
  backgroundPattern: { type: String, required: false },
72
+ ariaLabel: { type: String, required: false },
73
+ ariaDescription: { type: String, required: false },
74
+ accessibleDataTable: { type: Boolean, required: false },
75
+ maxDataPoints: { type: Number, required: false },
76
+ emptyLabel: { type: String, required: false },
77
+ error: { type: String, required: false },
70
78
  legendVariant: { type: String, required: false },
71
79
  tooltipVariant: { type: String, required: false },
72
80
  tooltipRoundness: { type: String, required: false },
@@ -81,6 +89,23 @@ const props = defineProps({
81
89
  skeletonShape: { type: String, required: false },
82
90
  percentAxis: { type: Boolean, required: false }
83
91
  });
92
+ const numericKeys = computed(() => Object.keys(props.categories));
93
+ const normalizedData = computed(() => normalizeNumericRows(props.data, numericKeys.value));
94
+ const dataLimit = computed(() => props.maxDataPoints ?? DEFAULT_MAX_DATA_POINTS);
95
+ const chartData = computed(() => {
96
+ warnDataLimit("Cartesian chart", normalizedData.value.length, dataLimit.value);
97
+ return sampleData(normalizedData.value, dataLimit.value);
98
+ });
99
+ const accessibleRows = computed(() => {
100
+ const series = categoriesToSeries(props.categories);
101
+ return chartData.value.map((row, index) => ({
102
+ label: props.xAxisKey === void 0 ? String(index + 1) : String(row[props.xAxisKey] ?? index + 1),
103
+ values: series.map((item) => ({
104
+ label: String(item.name),
105
+ value: row[item.dataKey]
106
+ }))
107
+ }));
108
+ });
84
109
  const slots = defineSlots();
85
110
  const legend = computed(() => legendPositionToLegendProps(props.legendPosition));
86
111
  const backgroundScope = useId();
@@ -89,7 +114,7 @@ const showYGrid = computed(() => props.yGridLine ?? true);
89
114
  const categoryIndexByValue = computed(() => {
90
115
  const map = /* @__PURE__ */ new Map();
91
116
  if (props.xAxisKey === void 0) return map;
92
- props.data.forEach((row, i) => {
117
+ chartData.value.forEach((row, i) => {
93
118
  map.set(row[props.xAxisKey], i);
94
119
  });
95
120
  return map;
@@ -134,7 +159,7 @@ const yAxis = computed(
134
159
  );
135
160
  const categoryAxisTicks = computed(() => {
136
161
  if (xAxis.value.ticks) return xAxis.value.ticks;
137
- return equidistantCategoryTicks(props.data, props.xNumTicks, props.xAxisKey);
162
+ return equidistantCategoryTicks(chartData.value, props.xNumTicks, props.xAxisKey);
138
163
  });
139
164
  const hasEquidistantCategoryTicks = computed(
140
165
  () => xAxis.value.ticks === void 0 && categoryAxisTicks.value !== void 0
@@ -178,7 +203,7 @@ const yAxisLine = computed(() => props.yDomainLine ?? true ? axisLineStyle : fal
178
203
  const xTickLineProp = computed(() => showXTickLine.value ? tickLineStyle : false);
179
204
  const yTickLineProp = computed(() => showYTickLine.value ? tickLineStyle : false);
180
205
  const mergedContainerProps = computed(() => ({
181
- data: props.data,
206
+ data: chartData.value,
182
207
  layout: layout.value,
183
208
  syncId: props.syncId,
184
209
  ...props.containerProps
@@ -188,7 +213,7 @@ const SMALL_CATEGORY_AXIS_MAX = 12;
188
213
  function resolveCategoryAxisInterval(configured, isCategoryAxis) {
189
214
  if (configured !== void 0) return configured;
190
215
  if (hasEquidistantCategoryTicks.value) return 0;
191
- if (isCategoryAxis && props.data.length <= SMALL_CATEGORY_AXIS_MAX) return 0;
216
+ if (isCategoryAxis && chartData.value.length <= SMALL_CATEGORY_AXIS_MAX) return 0;
192
217
  return void 0;
193
218
  }
194
219
  const xAxisInterval = computed(
@@ -215,7 +240,7 @@ const tooltipContent = computed(() => {
215
240
  if (titleFormatter && row != null) {
216
241
  label = titleFormatter(row);
217
242
  } else if (formatLabel != null && label !== void 0 && label !== "") {
218
- const rowIndex = row != null ? props.data.indexOf(row) : -1;
243
+ const rowIndex = row != null ? chartData.value.indexOf(row) : -1;
219
244
  const index = rowIndex >= 0 ? rowIndex : typeof label === "number" ? label : Number(label);
220
245
  label = formatLabel(label, Number.isNaN(index) ? 0 : index);
221
246
  }
@@ -247,14 +272,16 @@ const resolvedYAxes = computed(() => {
247
272
  </script>
248
273
 
249
274
  <template>
250
- <div class="vue-chrts" :class="frameClass" :style="rootStyle">
275
+ <div class="vue-chrts" :class="frameClass" :style="rootStyle" role="group" :aria-label="ariaLabel ?? 'Chart'">
276
+ <ChartAccessibility :label="ariaLabel ?? 'Chart'" :description="ariaDescription" :rows="accessibleRows" :show-table="accessibleDataTable !== false" />
251
277
  <ChartSkeleton
252
278
  v-if="loading"
253
279
  :height="height"
254
280
  :shape="skeletonShape ?? 'bars'"
255
281
  :label="loadingLabel ?? 'Loading'"
256
282
  />
257
- <ChartContainer v-else width="100%" :height="height">
283
+ <ChartEmptyState v-else-if="error || chartData.length === 0" :height="height" :message="error || emptyLabel" />
284
+ <ChartContainer v-if="!loading && !error" width="100%" :height="height" :aria-hidden="chartData.length === 0">
258
285
  <component :is="container" v-bind="mergedContainerProps">
259
286
  <!--
260
287
  First child on purpose: vccs has no z-index layer, so document order is
@@ -269,6 +296,7 @@ const resolvedYAxes = computed(() => {
269
296
  v-if="showXGrid || showYGrid"
270
297
  :horizontal="showYGrid"
271
298
  :vertical="showXGrid"
299
+ :sync-with-ticks="true"
272
300
  :stroke="gridStroke"
273
301
  stroke-dasharray="var(--vc-grid-dash)"
274
302
  :stroke-width="'var(--vc-grid-width)'"
@@ -343,7 +371,7 @@ const resolvedYAxes = computed(() => {
343
371
  :key="i"
344
372
  :x="line.x"
345
373
  :y="line.y"
346
- :stroke="line.color ?? '#888'"
374
+ :stroke="line.color ?? 'var(--vc-reference-line-color)'"
347
375
  :stroke-width="line.strokeWidth ?? 1"
348
376
  :stroke-dasharray="line.strokeDasharray"
349
377
  :label="line.label"
@@ -0,0 +1,20 @@
1
+ <script setup>
2
+ import { computed, useId } from "vue";
3
+ const props = defineProps({
4
+ label: { type: String, required: false, default: void 0 },
5
+ description: { type: String, required: false, default: void 0 },
6
+ rows: { type: Array, required: false, default: () => [] },
7
+ showTable: { type: Boolean, required: false, default: true }
8
+ });
9
+ const descriptionId = useId();
10
+ const columns = computed(() => props.rows?.[0]?.values ?? []);
11
+ </script>
12
+
13
+ <template>
14
+ <span v-if="description" :id="descriptionId" class="vc-sr-only">{{ description }}</span>
15
+ <table v-if="showTable !== false && rows?.length" class="vc-sr-only">
16
+ <caption>{{ label ?? "Chart data" }}</caption>
17
+ <thead><tr><th scope="col">Category</th><th v-for="column in columns" :key="column.label" scope="col">{{ column.label }}</th></tr></thead>
18
+ <tbody><tr v-for="(row, index) in rows" :key="index"><th scope="row">{{ row.label }}</th><td v-for="value in row.values" :key="value.label">{{ value.value }}</td></tr></tbody>
19
+ </table>
20
+ </template>
@@ -1,18 +1,21 @@
1
+ interface AccessibleRow {
2
+ label: string;
3
+ values: Array<{
4
+ label: string;
5
+ value: unknown;
6
+ }>;
7
+ }
1
8
  type __VLS_Props = {
2
- /** Height of the placeholder in pixels, matching the chart it stands in for. */
3
- height?: number;
4
- /** Silhouette to draw: a bar chart, a filled curve, or a ring. */
5
- shape?: "bars" | "wave" | "ring";
6
- /** Number of bars in the `bars` silhouette. */
7
- bars?: number;
8
- /** Text in the loading pill. Set empty to hide the pill. */
9
9
  label?: string;
10
+ description?: string;
11
+ rows?: AccessibleRow[];
12
+ showTable?: boolean;
10
13
  };
11
14
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
12
- height: number;
13
15
  label: string;
14
- bars: number;
15
- shape: "bars" | "wave" | "ring";
16
+ description: string;
17
+ rows: AccessibleRow[];
18
+ showTable: boolean;
16
19
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
20
  declare const _default: typeof __VLS_export;
18
21
  export default _default;
@@ -0,0 +1,12 @@
1
+ <script setup>
2
+ defineProps({
3
+ height: { type: Number, required: true },
4
+ message: { type: String, required: false }
5
+ });
6
+ </script>
7
+
8
+ <template>
9
+ <div class="vc-empty-state" :style="{ height: `${height}px` }" role="status">
10
+ {{ message ?? "No valid data" }}
11
+ </div>
12
+ </template>
@@ -1,16 +1,6 @@
1
- interface Row {
2
- label: string | number;
3
- open: number;
4
- high: number;
5
- low: number;
6
- close: number;
7
- volume?: number;
8
- }
9
1
  type __VLS_Props = {
10
- row: Row;
11
- upColor: string;
12
- downColor: string;
13
- valueFormatter?: (value: number) => string;
2
+ height: number;
3
+ message?: string;
14
4
  };
15
5
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
16
6
  declare const _default: typeof __VLS_export;
@@ -27,8 +27,8 @@ type __VLS_Props = {
27
27
  };
28
28
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
29
29
  variant: LegendIndicatorVariant;
30
- payload: LegendItem[];
31
30
  colors: Record<string, string>;
31
+ payload: LegendItem[];
32
32
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
33
33
  declare const _default: typeof __VLS_export;
34
34
  export default _default;
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { formatNumber } from "../../utils/format";
2
3
  import { computed } from "vue";
3
4
  defineOptions({ name: "ChartTooltip", inheritAttrs: false });
4
5
  const props = defineProps({
@@ -14,7 +15,7 @@ const items = computed(
14
15
  () => (props.payload ?? []).filter((p) => p.value !== null && p.value !== void 0)
15
16
  );
16
17
  function formatValue(value) {
17
- if (typeof value === "number") return value.toLocaleString();
18
+ if (typeof value === "number") return formatNumber(value);
18
19
  return String(value);
19
20
  }
20
21
  </script>
@@ -23,13 +23,13 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
23
23
  fill: string;
24
24
  radius: number;
25
25
  background: CubeColumnBand | null;
26
+ emptyColor: string;
26
27
  x: number | null;
27
28
  y: number | null;
28
29
  gap: number;
29
30
  preferredSize: number;
30
31
  minSize: number;
31
32
  minOpacity: number;
32
- emptyColor: string;
33
33
  includeEmpty: boolean;
34
34
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
35
35
  declare const _default: typeof __VLS_export;
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { formatNumber } from "../../utils/format";
2
3
  import { computed } from "vue";
3
4
  const props = defineProps({
4
5
  x: { type: Number, required: false },
@@ -79,7 +80,7 @@ export default { name: "FunnelClassicShape", inheritAttrs: false };
79
80
  stroke="none"
80
81
  text-anchor="middle"
81
82
  >
82
- {{ payload.formattedValue ?? payload.value.toLocaleString() }}
83
+ {{ payload.formattedValue ?? formatNumber(payload.value) }}
83
84
  </text>
84
85
  <text
85
86
  v-if="geometry.showName"
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { formatNumber } from "../../utils/format";
2
3
  import { computed } from "vue";
3
4
  const props = defineProps({
4
5
  payload: { type: Object, required: false },
@@ -116,7 +117,7 @@ export default { name: "FunnelLayeredShape", inheritAttrs: false };
116
117
  stroke="none"
117
118
  text-anchor="middle"
118
119
  >
119
- {{ payload.formattedValue ?? payload.value.toLocaleString() }}
120
+ {{ payload.formattedValue ?? formatNumber(payload.value) }}
120
121
  </text>
121
122
 
122
123
  <template v-if="geometry.showBadge">
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { formatNumber } from "../../utils/format";
2
3
  defineProps({
3
4
  datum: { type: Object, required: true },
4
5
  x: { type: Number, required: true },
@@ -20,7 +21,7 @@ defineProps({
20
21
  <span class="vc-funnel-layered__dot" :style="{ background: datum.color }" />
21
22
  <span class="vc-funnel-layered__name">{{ datum.name }}</span>
22
23
  <strong class="vc-funnel-layered__value">
23
- {{ datum.formattedValue ?? datum.value.toLocaleString() }}
24
+ {{ datum.formattedValue ?? formatNumber(datum.value) }}
24
25
  </strong>
25
26
  </div>
26
27
  </template>
@@ -8,6 +8,6 @@ import type { TooltipRoundness, TooltipVariant } from "../../utils/variants.js";
8
8
  * function does — and keeps the wrapper in one place instead of repeating it
9
9
  * in every polar adapter.
10
10
  */
11
- export declare function tooltipContentFor(variant: TooltipVariant | undefined, roundness: TooltipRoundness | undefined): (tooltipProps: TooltipContentProps) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
11
+ export declare function tooltipContentFor(variant: TooltipVariant | undefined, roundness: TooltipRoundness | undefined, titleFormatter?: (data: unknown) => string | number): (tooltipProps: TooltipContentProps) => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
12
12
  [key: string]: any;
13
13
  }>;
@@ -1,5 +1,9 @@
1
1
  import { h } from "vue";
2
2
  import ChartTooltip from "./ChartTooltip.vue";
3
- export function tooltipContentFor(variant, roundness) {
4
- return (tooltipProps) => h(ChartTooltip, { ...tooltipProps, variant, roundness });
3
+ export function tooltipContentFor(variant, roundness, titleFormatter) {
4
+ return (tooltipProps) => {
5
+ const row = tooltipProps.payload?.[0]?.payload;
6
+ const label = titleFormatter && row != null ? titleFormatter(row) : tooltipProps.label;
7
+ return h(ChartTooltip, { ...tooltipProps, label, variant, roundness });
8
+ };
5
9
  }
@@ -14,12 +14,28 @@ import type { DitherVariant } from "../utils/dither.js";
14
14
  import type { StrokeGradientStop } from "../utils/gradient.js";
15
15
  import type { BackgroundVariant } from "../utils/background.js";
16
16
  import type { AreaFillVariant, BarVariant, DotVariant, LegendIndicatorVariant, RadarVariant, RadialVariant, StrokeVariant, TooltipRoundness, TooltipVariant } from "../utils/variants.js";
17
- import type { AxisConfig, AxisId, BulletLegendItemInterface, ChartPadding, ChartTheme, CrosshairConfig, MarkerConfig, TooltipConfig, YAxisConfig, axisFormatter } from "./shared.js";
17
+ import type { AxisConfig, AxisId, BulletLegendItemInterface, ChartPadding, ChartTheme, CrosshairConfig, MarkerConfig, YAxisConfig, axisFormatter } from "./shared.js";
18
+ /** Keys whose declared value is numeric (nullable/optional numeric fields included). */
19
+ export type NumericKeys<T> = {
20
+ [K in keyof T]-?: NonNullable<T[K]> extends number ? K : never;
21
+ }[keyof T];
18
22
  /**
19
23
  * Chrome styling shared by every chart, cartesian or polar. Each field selects
20
24
  * one of the built-in variants; omit them all for the shipped defaults.
21
25
  */
22
26
  export interface ChartStyleProps {
27
+ /** Accessible name for the chart. Falls back to a chart-type label. */
28
+ ariaLabel?: string;
29
+ /** Longer screen-reader description of the chart's purpose or trend. */
30
+ ariaDescription?: string;
31
+ /** Render a visually-hidden data table. Default true. */
32
+ accessibleDataTable?: boolean;
33
+ /** Maximum rows rendered as SVG/DOM marks. Default 2,000. */
34
+ maxDataPoints?: number;
35
+ /** Message shown when no valid plotted values remain. */
36
+ emptyLabel?: string;
37
+ /** Error message rendered in place of the chart. */
38
+ error?: string;
23
39
  /** Shape of the colour swatch beside each legend entry. Default `rounded-square`. */
24
40
  legendVariant?: LegendIndicatorVariant;
25
41
  /** Tooltip surface treatment. `frosted-glass` blurs what sits behind it. */
@@ -121,8 +137,6 @@ export interface CartesianChartBaseProps<T> extends ChartStyleProps {
121
137
  * top-level `yLabel` / `yDomain` / `yAxisConfig` props.
122
138
  */
123
139
  yAxes?: Record<AxisId, YAxisConfig>;
124
- /** Tooltip behaviour config. */
125
- tooltip?: TooltipConfig;
126
140
  /** Reference lines drawn across the plot area. New in v3. */
127
141
  referenceLines?: ReferenceLineConfig[];
128
142
  /**
@@ -256,7 +270,7 @@ export interface ValueLabel {
256
270
  }
257
271
  export interface BarChartProps<T> extends CartesianChartBaseProps<T> {
258
272
  /** The data keys (series) plotted on the value axis. */
259
- yAxis: (keyof T)[];
273
+ yAxis: NumericKeys<T>[];
260
274
  /** The data key used for the category axis. */
261
275
  xAxis?: keyof T;
262
276
  /** Stack the bars instead of grouping them. */
@@ -357,8 +371,8 @@ export interface SizeOptions {
357
371
  maxRadius?: number;
358
372
  }
359
373
  /** v2 accepted Unovis-style function accessors; v3 also accepts row field keys. */
360
- export type BubbleAccessor<T> = keyof T | ((datum: T) => number | string | Date | null | undefined);
361
- export interface BubbleChartProps<T> extends CartesianChartBaseProps<T> {
374
+ export type BubbleAccessor<T> = NumericKeys<T> | ((datum: T) => number | null | undefined);
375
+ export type BubbleChartProps<T> = Omit<CartesianChartBaseProps<T>, "backgroundPattern" | "referenceLines" | "syncId" | "yAxes" | "yExplicitTicks"> & {
362
376
  /** Data key or accessor for the bubble's x value. */
363
377
  xAccessor: BubbleAccessor<T>;
364
378
  /** Data key or accessor for the bubble's y value. */
@@ -376,7 +390,7 @@ export interface BubbleChartProps<T> extends CartesianChartBaseProps<T> {
376
390
  opacity?: number;
377
391
  /** Options controlling bubble sizes. */
378
392
  sizeOptions?: SizeOptions;
379
- }
393
+ };
380
394
  /**
381
395
  * Candlestick (OHLC) chart props. New in v3 — no `vccs` primitive exists, so the
382
396
  * adapter composes a `vccs` `<ComposedChart>` (for the real axes, grid, scales
@@ -387,7 +401,7 @@ export interface BubbleChartProps<T> extends CartesianChartBaseProps<T> {
387
401
  * accessors read `label`/`open`/`high`/`low`/`close`/`volume`, so a row shaped
388
402
  * like `{ label, open, high, low, close, volume? }` works with no config.
389
403
  */
390
- export interface CandlestickChartProps<T> {
404
+ export interface CandlestickChartProps<T> extends ChartStyleProps {
391
405
  /** The data to render. Each element is one candle. */
392
406
  data: T[];
393
407
  /** Chart height in pixels. */
@@ -395,18 +409,18 @@ export interface CandlestickChartProps<T> {
395
409
  /** Row field used for the x (category) axis label. Default `"label"`. */
396
410
  xAccessor?: keyof T;
397
411
  /** Row field for the open price. Default `"open"`. */
398
- openAccessor?: keyof T;
412
+ openAccessor?: NumericKeys<T>;
399
413
  /** Row field for the high price. Default `"high"`. */
400
- highAccessor?: keyof T;
414
+ highAccessor?: NumericKeys<T>;
401
415
  /** Row field for the low price. Default `"low"`. */
402
- lowAccessor?: keyof T;
416
+ lowAccessor?: NumericKeys<T>;
403
417
  /** Row field for the close price. Default `"close"`. */
404
- closeAccessor?: keyof T;
418
+ closeAccessor?: NumericKeys<T>;
405
419
  /** Optional row field for the traded volume. Default `"volume"`. */
406
- volumeAccessor?: keyof T;
407
- /** Colour for rising candles (close ≥ open). Default `#10b981`. */
420
+ volumeAccessor?: NumericKeys<T>;
421
+ /** Colour for rising candles. Defaults to the `--vc-candle-up` theme token. */
408
422
  upColor?: string;
409
- /** Colour for falling candles (close < open). Default `#ef4444`. */
423
+ /** Colour for falling candles. Defaults to the `--vc-candle-down` theme token. */
410
424
  downColor?: string;
411
425
  /** Max candle body width in pixels. Default 18. */
412
426
  candleWidth?: number;
@@ -438,12 +452,14 @@ export interface CandlestickChartProps<T> {
438
452
  hideYAxis?: boolean;
439
453
  /** Hide the tooltip. */
440
454
  hideTooltip?: boolean;
441
- /** Tooltip behaviour config. */
442
- tooltip?: TooltipConfig;
443
455
  }
444
456
  export interface DonutChartProps<T = unknown> extends ChartStyleProps {
445
- /** Segment values, in the same order as `categories`. */
446
- data: number[];
457
+ /** Record data (preferred), or positional values retained for v2 compatibility. */
458
+ data: T[] | number[];
459
+ /** Record field containing the segment label. */
460
+ nameKey?: keyof T;
461
+ /** Record field containing the numeric segment value. Required for record data. */
462
+ valueKey?: keyof T;
447
463
  /** Maps each segment to its legend representation (label, colour). */
448
464
  categories: Record<string, BulletLegendItemInterface>;
449
465
  /** Full ring or half-circle gauge. */
@@ -487,8 +503,6 @@ export interface DonutChartProps<T = unknown> extends ChartStyleProps {
487
503
  hideTooltip?: boolean;
488
504
  /** Custom formatter for tooltip titles. */
489
505
  tooltipTitleFormatter?: (data: T) => string | number;
490
- /** Tooltip behaviour config. */
491
- tooltip?: TooltipConfig;
492
506
  /**
493
507
  * Per-chart appearance overrides (legend, hover, tooltip). Layers over the
494
508
  * global `--vc-*` token defaults; omit to use the shipped theme.
@@ -564,8 +578,6 @@ export interface RadarChartProps<T> extends ChartStyleProps {
564
578
  bottom?: number;
565
579
  left?: number;
566
580
  };
567
- /** Tooltip behaviour config. */
568
- tooltip?: TooltipConfig;
569
581
  /**
570
582
  * Per-chart appearance overrides (legend, hover, tooltip). Layers over the
571
583
  * global `--vc-*` token defaults; omit to use the shipped theme.
@@ -580,8 +592,10 @@ export interface RadarChartProps<T> extends ChartStyleProps {
580
592
  * aligned with `categories`.
581
593
  */
582
594
  export interface RadialBarChartProps<T = unknown> extends ChartStyleProps {
583
- /** Segment values, in the same order as `categories`. */
584
- data: number[];
595
+ /** Record data (preferred), or positional values retained for v2 compatibility. */
596
+ data: T[] | number[];
597
+ nameKey?: keyof T;
598
+ valueKey?: keyof T;
585
599
  /** Maps each segment to its legend representation (label, colour). */
586
600
  categories: Record<string, BulletLegendItemInterface>;
587
601
  /** Chart height in pixels. */
@@ -614,8 +628,6 @@ export interface RadialBarChartProps<T = unknown> extends ChartStyleProps {
614
628
  hideTooltip?: boolean;
615
629
  /** Custom formatter for tooltip titles. */
616
630
  tooltipTitleFormatter?: (data: T) => string | number;
617
- /** Tooltip behaviour config. */
618
- tooltip?: TooltipConfig;
619
631
  /**
620
632
  * Per-chart appearance overrides (legend, hover, tooltip). Layers over the
621
633
  * global `--vc-*` token defaults; omit to use the shipped theme.
@@ -644,8 +656,10 @@ export interface FunnelLabelSizes {
644
656
  name?: number;
645
657
  }
646
658
  export interface FunnelChartProps<T = unknown> extends ChartStyleProps {
647
- /** Stage values, in the same order as `categories`. Largest first reads top-down. */
648
- data: number[];
659
+ /** Record data (preferred), or positional values retained for v2 compatibility. */
660
+ data: T[] | number[];
661
+ nameKey?: keyof T;
662
+ valueKey?: keyof T;
649
663
  /** Maps each stage to its legend representation (label, colour). */
650
664
  categories: Record<string, BulletLegendItemInterface>;
651
665
  /** Chart height in pixels. */
@@ -695,8 +709,6 @@ export interface FunnelChartProps<T = unknown> extends ChartStyleProps {
695
709
  hideTooltip?: boolean;
696
710
  /** Custom formatter for tooltip titles. */
697
711
  tooltipTitleFormatter?: (data: T) => string | number;
698
- /** Tooltip behaviour config. */
699
- tooltip?: TooltipConfig;
700
712
  /**
701
713
  * Per-chart appearance overrides (legend, hover, tooltip). Layers over the
702
714
  * global `--vc-*` token defaults; omit to use the shipped theme.
@@ -718,7 +730,7 @@ export interface StatusTrackerDatum {
718
730
  * `data` is expected oldest-to-newest. When the container cannot fit every bar,
719
731
  * older records are dropped and the newest records stay visible on the right.
720
732
  */
721
- export interface StatusTrackerChartProps<T extends StatusTrackerDatum = StatusTrackerDatum> {
733
+ export interface StatusTrackerChartProps<T extends StatusTrackerDatum = StatusTrackerDatum> extends ChartStyleProps {
722
734
  /** Status samples ordered oldest-to-newest. */
723
735
  data: T[];
724
736
  /** Maps each status key to its display label and colour. */
@@ -810,8 +822,6 @@ export interface SankeyChartProps<N extends SankeyInputNode = SankeyInputNode, L
810
822
  iterations?: number;
811
823
  /** Hide the tooltip. */
812
824
  hideTooltip?: boolean;
813
- /** Tooltip behaviour config. */
814
- tooltip?: TooltipConfig;
815
825
  /**
816
826
  * Per-chart appearance overrides (legend, hover, tooltip). Layers over the
817
827
  * global `--vc-*` token defaults; omit to use the shipped theme.
@@ -82,17 +82,6 @@ export interface AxisConfig {
82
82
  minMaxTicksOnlyShowGridLines?: boolean;
83
83
  tickValues?: readonly number[] | readonly Date[];
84
84
  }
85
- /**
86
- * Tooltip behaviour options. Mapped onto `vccs` `<Tooltip>`.
87
- */
88
- export interface TooltipConfig {
89
- /** Hide delay in milliseconds. */
90
- hideDelay?: number;
91
- /** Show delay in milliseconds. */
92
- showDelay?: number;
93
- /** If `true`, the tooltip follows the cursor. */
94
- followCursor?: boolean;
95
- }
96
85
  /**
97
86
  * @deprecated Unovis-only. `vccs` has no crosshair primitive; retained as an
98
87
  * inert type so v2 templates keep type-checking. Has no effect.
@@ -140,6 +129,11 @@ export interface ChartPadding {
140
129
  * scale legend, axis ticks, axis titles, and radar labels together.
141
130
  */
142
131
  export interface ChartTheme {
132
+ /**
133
+ * Per-chart series palette. Entries override `--vc-series-0` through
134
+ * `--vc-series-7`; omitted entries continue to inherit host design tokens.
135
+ */
136
+ colors?: string[];
143
137
  /** Grid + axis (domain) lines. */
144
138
  grid?: {
145
139
  /** Line colour. Token: `--vc-grid-color`. */
@@ -21,7 +21,7 @@ export interface SeriesDescriptor {
21
21
  dataKey: string;
22
22
  /** Display name shown in legend / tooltip. */
23
23
  name: string;
24
- /** Resolved colour. Falls back to `var(--chart-color-N)` for CSS-var theming. */
24
+ /** Resolved colour. Falls back to the library's design-system-aware series token. */
25
25
  color: string;
26
26
  /** Whether the series is hidden. */
27
27
  hidden: boolean;
@@ -4,8 +4,8 @@ export function normalizeAxisId(id) {
4
4
  return /^-?\d+$/.test(id) ? Number(id) : id;
5
5
  }
6
6
  function resolveColor(color, index) {
7
- if (Array.isArray(color)) return color[0] ?? `var(--chart-color-${index})`;
8
- return color ?? `var(--chart-color-${index})`;
7
+ if (Array.isArray(color)) return color[0] ?? `var(--vc-series-${index % 8})`;
8
+ return color ?? `var(--vc-series-${index % 8})`;
9
9
  }
10
10
  export function categoriesToSeries(categories) {
11
11
  return Object.entries(categories).map(([dataKey, item], index) => ({
@@ -0,0 +1,19 @@
1
+ /** Default ceiling for DOM/SVG data marks. Consumers may lower or raise it. */
2
+ export declare const DEFAULT_MAX_DATA_POINTS = 2000;
3
+ /** Convert numeric API input without allowing NaN or infinity into geometry. */
4
+ export declare function toFiniteNumber(value: unknown): number | undefined;
5
+ /** Evenly retain the first/last values and representative values in between. */
6
+ export declare function sampleData<T>(data: readonly T[], limit?: number): T[];
7
+ /** Keep only finite positional values. Invalid entries are gaps, never zeroes. */
8
+ export declare function normalizeValues(data: readonly unknown[]): number[];
9
+ export interface NamedValue<T = unknown> {
10
+ row: T | undefined;
11
+ name: string;
12
+ value: number;
13
+ sourceIndex: number;
14
+ }
15
+ /** Resolve both the v2 positional API and the v3 record-based API. */
16
+ export declare function normalizeNamedValues<T>(data: readonly number[] | readonly T[], categoryNames: readonly string[], nameKey?: keyof T, valueKey?: keyof T): NamedValue<T>[];
17
+ /** Normalize selected row fields and discard rows with any invalid plotted value. */
18
+ export declare function normalizeNumericRows<T>(data: readonly T[], keys: readonly (keyof T)[]): T[];
19
+ export declare function warnDataLimit(chart: string, received: number, limit: number): void;
@@ -0,0 +1,50 @@
1
+ export const DEFAULT_MAX_DATA_POINTS = 2e3;
2
+ export function toFiniteNumber(value) {
3
+ if (value === null || value === void 0 || value === "") return void 0;
4
+ const number = typeof value === "number" ? value : Number(value);
5
+ return Number.isFinite(number) ? number : void 0;
6
+ }
7
+ export function sampleData(data, limit = DEFAULT_MAX_DATA_POINTS) {
8
+ const size = Math.max(1, Math.floor(limit));
9
+ if (data.length <= size) return [...data];
10
+ if (size === 1) return [data[data.length - 1]];
11
+ return Array.from(
12
+ { length: size },
13
+ (_, index) => data[Math.round(index * (data.length - 1) / (size - 1))]
14
+ );
15
+ }
16
+ export function normalizeValues(data) {
17
+ return data.flatMap((value) => {
18
+ const number = toFiniteNumber(value);
19
+ return number === void 0 ? [] : [number];
20
+ });
21
+ }
22
+ export function normalizeNamedValues(data, categoryNames, nameKey, valueKey) {
23
+ return data.flatMap((entry, sourceIndex) => {
24
+ const recordMode = valueKey !== void 0 && typeof entry === "object" && entry !== null;
25
+ const row = recordMode ? entry : void 0;
26
+ const value = toFiniteNumber(recordMode ? row[valueKey] : entry);
27
+ if (value === void 0) return [];
28
+ const rawName = recordMode && nameKey !== void 0 ? row[nameKey] : categoryNames[sourceIndex];
29
+ return [{ row, value, sourceIndex, name: String(rawName ?? sourceIndex) }];
30
+ });
31
+ }
32
+ export function normalizeNumericRows(data, keys) {
33
+ return data.flatMap((row) => {
34
+ const copy = { ...row };
35
+ for (const key of keys) {
36
+ const value = toFiniteNumber(row[key]);
37
+ if (value === void 0) return [];
38
+ copy[key] = value;
39
+ }
40
+ return [copy];
41
+ });
42
+ }
43
+ const warned = /* @__PURE__ */ new Set();
44
+ export function warnDataLimit(chart, received, limit) {
45
+ if (!import.meta.dev || received <= limit || warned.has(chart)) return;
46
+ warned.add(chart);
47
+ console.warn(
48
+ `[nuxt-charts] ${chart} received ${received.toLocaleString()} rows; rendering a ${limit.toLocaleString()}-row sample. Set maxDataPoints to override.`
49
+ );
50
+ }