nuxt-charts 3.0.0-beta.4 → 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.
package/README.md CHANGED
@@ -4,6 +4,11 @@ Beautiful chart components for Nuxt — Area, Bar, Line, Donut, Bubble, Radar, R
4
4
 
5
5
  Powered by [vccs](https://vue-charts.com) (Vue port of Recharts). Drop-in config-prop API from nuxt-charts v2.
6
6
 
7
+ Nuxt UI v4 is a first-class, zero-config integration: chart series, surfaces,
8
+ text, borders, radius, typography, and dark mode inherit its semantic design
9
+ tokens. Nuxt UI is not a dependency; every token has a standalone fallback, so
10
+ the same components work in any Nuxt project.
11
+
7
12
  ## Install
8
13
 
9
14
  ```bash
@@ -179,6 +184,25 @@ evenly (preserving both endpoints) and emit one development warning. Override
179
184
  this with `maxDataPoints`, but use pre-aggregation for genuinely dense data:
180
185
  SVG creates DOM work per mark, so raising the limit can block the UI.
181
186
 
187
+ ## Theming
188
+
189
+ With Nuxt UI, no chart-specific setup is required. Categories without an
190
+ explicit `color` use `--ui-primary`, `--ui-secondary`, `--ui-success`,
191
+ `--ui-info`, `--ui-warning`, and `--ui-error`; chart chrome follows Nuxt UI's
192
+ background, text, border, radius, and font tokens.
193
+
194
+ Without Nuxt UI, built-in light and dark defaults are used. Customize globally
195
+ with `--vc-*` variables (or the backwards-compatible `--chart-color-0` through
196
+ `--chart-color-7`), and customize one chart with the `theme` prop:
197
+
198
+ ```vue
199
+ <LineChart
200
+ :data="data"
201
+ :categories="categories"
202
+ :theme="{ colors: ['var(--brand)', 'var(--accent)'] }"
203
+ />
204
+ ```
205
+
182
206
  ## Auto-imported enums & types
183
207
 
184
208
  - Enums: `CurveType`, `LegendPosition`, `Orientation`, `DonutType`
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3"
6
6
  },
7
- "version": "3.0.0-beta.4",
7
+ "version": "3.0.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "unknown"
@@ -1 +1 @@
1
- @layer vue-chrts{.vue-chrts :focus,.vue-chrts :focus-visible,.vue-chrts:focus,.vue-chrts:focus-visible{outline:none}.vue-chrts{--vc-grid-color:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-grid-dash:3 3;--vc-grid-width:1px;--vc-axis-line-color:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-axis-line-width:1px;--vc-surface-bg:var(--ui-bg,var(--background,oklch(1 0 0)));--vc-reference-line-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-candle-up:var(--ui-success,oklch(0.696 0.17 162.48));--vc-candle-down:var(--ui-error,oklch(0.637 0.237 25.331));--vc-bg-pattern-color:var(--vc-grid-color);--vc-legend-size:0.75rem;--vc-legend-weight:400;--vc-tick-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-tick-size:var(--vc-legend-size);--vc-tick-weight:var(--vc-legend-weight);--vc-axis-label-color:var(--ui-text-highlighted,var(--foreground,oklch(0.205 0 0)));--vc-axis-label-size:var(--vc-legend-size);--vc-axis-label-weight:500}.vue-chrts .v-charts-cartesian-axis .v-charts-label{fill:var(--vc-axis-label-color);font-size:var(--vc-axis-label-size);font-weight:var(--vc-axis-label-weight)}.vue-chrts{--vc-legend-gap:0.75rem;--vc-legend-inset:0.75rem;--vc-legend-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-legend-dot-size:0.5rem;--vc-funnel-value-size:var(--vc-legend-size);--vc-funnel-value-color:var(--vc-axis-label-color);--vc-funnel-value-weight:600;--vc-funnel-label-color:var(--vc-tick-color);--vc-funnel-label-weight:500;--vc-funnel-badge-bg:var(--vc-surface-bg);--vc-funnel-badge-color:var(--vc-tick-color);--vc-funnel-badge-border:var(--vc-axis-line-color);--vc-funnel-badge-weight:600;--vc-funnel-badge-opacity:0.82;--vc-hover-fill:color-mix(in oklab,var(--ui-text-highlighted,var(--foreground,oklch(0.205 0 0))) 6%,transparent);--vc-hover-stroke:transparent;--vc-hover-radius:6px;--vc-tooltip-bg:var(--ui-bg,var(--popover,oklch(1 0 0)));--vc-tooltip-fg:var(--ui-text-highlighted,var(--popover-foreground,oklch(0.205 0 0)));--vc-tooltip-muted:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-tooltip-border:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-tooltip-radius:0.5rem;--vc-tooltip-padding:0.375rem 0.625rem;--vc-tooltip-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.vue-chrts .v-charts-xAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-x-tick-color,var(--vc-tick-color));font-size:var(--vc-x-tick-size,var(--vc-tick-size));font-weight:var(--vc-x-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-yAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-y-tick-color,var(--vc-tick-color));font-size:var(--vc-y-tick-size,var(--vc-tick-size));font-weight:var(--vc-y-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-polar-angle-axis-tick-value,.vue-chrts .v-charts-polar-radius-axis-tick-value{fill:var(--vc-tick-color);font-size:var(--vc-tick-size);font-weight:var(--vc-tick-weight)}.vue-chrts.vc-dash-animated .v-charts-area-curve,.vue-chrts.vc-dash-animated .v-charts-line-curve{animation:vc-dash-march 1s linear infinite}@keyframes vc-dash-march{to{stroke-dashoffset:-6}}@media (prefers-reduced-motion:reduce){.vue-chrts.vc-dash-animated .v-charts-area-curve,.vue-chrts.vc-dash-animated .v-charts-line-curve{animation:none}}.vue-chrts:is(.dark,[data-theme=dark],.dark *,[data-theme=dark] *),:is(.dark,[data-theme=dark]) .vue-chrts{--vc-grid-color:var(--ui-border,var(--border,oklch(0.269 0 0)));--vc-axis-line-color:var(--ui-border,var(--border,oklch(0.269 0 0)));--vc-surface-bg:var(--ui-bg,var(--background,oklch(0.145 0 0)));--vc-tick-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-axis-label-color:var(--ui-text-highlighted,var(--foreground,oklch(0.985 0 0)));--vc-legend-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-hover-fill:color-mix(in oklab,var(--ui-text-highlighted,oklch(0.985 0 0)) 8%,transparent);--vc-tooltip-bg:var(--ui-bg,var(--popover,oklch(0.205 0 0)));--vc-tooltip-fg:var(--ui-text-highlighted,var(--popover-foreground,oklch(0.985 0 0)));--vc-tooltip-muted:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-tooltip-border:var(--ui-border,var(--border,oklch(0.269 0 0)))}}
1
+ @layer vue-chrts{.vue-chrts :focus,.vue-chrts :focus-visible,.vue-chrts:focus,.vue-chrts:focus-visible{outline:none}.vue-chrts{--vc-font-family:var(--font-sans,ui-sans-serif,system-ui,sans-serif);--vc-series-0:var(--chart-color-0,var(--ui-primary,oklch(0.63 0.18 155)));--vc-series-1:var(--chart-color-1,var(--ui-secondary,oklch(0.62 0.19 255)));--vc-series-2:var(--chart-color-2,var(--ui-success,oklch(0.64 0.17 145)));--vc-series-3:var(--chart-color-3,var(--ui-info,oklch(0.68 0.15 235)));--vc-series-4:var(--chart-color-4,var(--ui-warning,oklch(0.75 0.16 75)));--vc-series-5:var(--chart-color-5,var(--ui-error,oklch(0.63 0.22 25)));--vc-series-6:var(--chart-color-6,oklch(0.66 0.18 305));--vc-series-7:var(--chart-color-7,oklch(0.7 0.15 195));font-family:var(--vc-font-family);--vc-grid-color:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-grid-dash:3 3;--vc-grid-width:1px;--vc-axis-line-color:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-axis-line-width:1px;--vc-surface-bg:var(--ui-bg,var(--background,oklch(1 0 0)));--vc-reference-line-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-candle-up:var(--ui-success,oklch(0.696 0.17 162.48));--vc-candle-down:var(--ui-error,oklch(0.637 0.237 25.331));--vc-bg-pattern-color:var(--vc-grid-color);--vc-legend-size:0.75rem;--vc-legend-weight:400;--vc-tick-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-tick-size:var(--vc-legend-size);--vc-tick-weight:var(--vc-legend-weight);--vc-axis-label-color:var(--ui-text-highlighted,var(--foreground,oklch(0.205 0 0)));--vc-axis-label-size:var(--vc-legend-size);--vc-axis-label-weight:500}.vue-chrts .v-charts-cartesian-axis .v-charts-label{fill:var(--vc-axis-label-color);font-size:var(--vc-axis-label-size);font-weight:var(--vc-axis-label-weight)}.vue-chrts{--vc-legend-gap:0.75rem;--vc-legend-inset:0.75rem;--vc-legend-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-legend-dot-size:0.5rem;--vc-funnel-value-size:var(--vc-legend-size);--vc-funnel-value-color:var(--vc-axis-label-color);--vc-funnel-value-weight:600;--vc-funnel-label-color:var(--vc-tick-color);--vc-funnel-label-weight:500;--vc-funnel-badge-bg:var(--vc-surface-bg);--vc-funnel-badge-color:var(--vc-tick-color);--vc-funnel-badge-border:var(--vc-axis-line-color);--vc-funnel-badge-weight:600;--vc-funnel-badge-opacity:0.82;--vc-hover-fill:color-mix(in oklab,var(--ui-text-highlighted,var(--foreground,oklch(0.205 0 0))) 6%,transparent);--vc-hover-stroke:transparent;--vc-hover-radius:6px;--vc-tooltip-bg:var(--ui-bg-elevated,var(--popover,oklch(1 0 0)));--vc-tooltip-fg:var(--ui-text-highlighted,var(--popover-foreground,oklch(0.205 0 0)));--vc-tooltip-muted:var(--ui-text-muted,var(--muted-foreground,oklch(0.556 0 0)));--vc-tooltip-border:var(--ui-border,var(--border,oklch(0.922 0 0)));--vc-tooltip-radius:var(--ui-radius,0.5rem);--vc-tooltip-padding:0.375rem 0.625rem;--vc-tooltip-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1)}.vue-chrts .v-charts-xAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-x-tick-color,var(--vc-tick-color));font-size:var(--vc-x-tick-size,var(--vc-tick-size));font-weight:var(--vc-x-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-yAxis .v-charts-cartesian-axis-tick-value{fill:var(--vc-y-tick-color,var(--vc-tick-color));font-size:var(--vc-y-tick-size,var(--vc-tick-size));font-weight:var(--vc-y-tick-weight,var(--vc-tick-weight))}.vue-chrts .v-charts-polar-angle-axis-tick-value,.vue-chrts .v-charts-polar-radius-axis-tick-value{fill:var(--vc-tick-color);font-size:var(--vc-tick-size);font-weight:var(--vc-tick-weight)}.vue-chrts.vc-dash-animated .v-charts-area-curve,.vue-chrts.vc-dash-animated .v-charts-line-curve{animation:vc-dash-march 1s linear infinite}@keyframes vc-dash-march{to{stroke-dashoffset:-6}}@media (prefers-reduced-motion:reduce){.vue-chrts.vc-dash-animated .v-charts-area-curve,.vue-chrts.vc-dash-animated .v-charts-line-curve{animation:none}}.vue-chrts:is(.dark,[data-theme=dark],.dark *,[data-theme=dark] *),:is(.dark,[data-theme=dark]) .vue-chrts{--vc-grid-color:var(--ui-border,var(--border,oklch(0.269 0 0)));--vc-axis-line-color:var(--ui-border,var(--border,oklch(0.269 0 0)));--vc-surface-bg:var(--ui-bg,var(--background,oklch(0.145 0 0)));--vc-tick-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-axis-label-color:var(--ui-text-highlighted,var(--foreground,oklch(0.985 0 0)));--vc-legend-color:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-hover-fill:color-mix(in oklab,var(--ui-text-highlighted,oklch(0.985 0 0)) 8%,transparent);--vc-tooltip-bg:var(--ui-bg-elevated,var(--popover,oklch(0.205 0 0)));--vc-tooltip-fg:var(--ui-text-highlighted,var(--popover-foreground,oklch(0.985 0 0)));--vc-tooltip-muted:var(--ui-text-muted,var(--muted-foreground,oklch(0.708 0 0)));--vc-tooltip-border:var(--ui-border,var(--border,oklch(0.269 0 0)))}}
@@ -60,7 +60,7 @@ const segments = computed(() => {
60
60
  warnDataLimit("DonutChart", normalized.length, limit);
61
61
  const values = sampleData(normalized, limit);
62
62
  return values.map(({ row, value, sourceIndex, name }) => {
63
- const color = cats[sourceIndex]?.color ?? `var(--chart-color-${sourceIndex})`;
63
+ const color = cats[sourceIndex]?.color ?? `var(--vc-series-${sourceIndex % 8})`;
64
64
  return {
65
65
  ...row && typeof row === "object" ? row : {},
66
66
  name,
@@ -64,8 +64,8 @@ const stages = computed(() => {
64
64
  name,
65
65
  value,
66
66
  formattedValue: props.valueFormatter?.(value, sourceIndex),
67
- fill: cats[sourceIndex]?.color ?? `var(--chart-color-${sourceIndex})`,
68
- color: cats[sourceIndex]?.color ?? `var(--chart-color-${sourceIndex})`
67
+ fill: cats[sourceIndex]?.color ?? `var(--vc-series-${sourceIndex % 8})`,
68
+ color: cats[sourceIndex]?.color ?? `var(--vc-series-${sourceIndex % 8})`
69
69
  }));
70
70
  });
71
71
  const accessibleRows = computed(() => stages.value.map((stage) => ({ label: stage.name, values: [{ label: "Value", value: stage.formattedValue ?? stage.value }] })));
@@ -16,7 +16,7 @@ import PolarCenterSync from "./internal/PolarCenterSync";
16
16
  import { categoriesToSeries } from "../utils/categories";
17
17
  import { legendPositionToLegendProps, resolveLegendWrapperStyle } from "../utils/legend";
18
18
  import { toCssProperties } from "../utils/style";
19
- import { themeToVars } from "../utils/theme";
19
+ import { resolveHoverVisible, themeToVars } from "../utils/theme";
20
20
  import { DEFAULT_MAX_DATA_POINTS, normalizeNamedValues, sampleData, warnDataLimit } from "../utils/data";
21
21
  const props = defineProps({
22
22
  data: { type: Array, required: true },
@@ -60,7 +60,7 @@ const bars = computed(() => {
60
60
  ...row && typeof row === "object" ? row : {},
61
61
  name,
62
62
  value,
63
- fill: cats[sourceIndex]?.color ?? `var(--chart-color-${sourceIndex})`
63
+ fill: cats[sourceIndex]?.color ?? `var(--vc-series-${sourceIndex % 8})`
64
64
  }));
65
65
  });
66
66
  const angles = computed(() => {
@@ -74,6 +74,24 @@ const tooltipContent = computed(
74
74
  () => tooltipContentFor(props.tooltipVariant, props.tooltipRoundness, props.tooltipTitleFormatter)
75
75
  );
76
76
  const accessibleRows = computed(() => bars.value.map((bar) => ({ label: bar.name, values: [{ label: "Value", value: bar.value }] })));
77
+ const hiddenTooltipContent = () => null;
78
+ const radiusInPixels = (radius, fallback) => {
79
+ if (typeof radius === "number") return radius;
80
+ const percentage = Number.parseFloat(radius);
81
+ return Number.isFinite(percentage) ? props.height / 2 * percentage / 100 : fallback;
82
+ };
83
+ const hoverStrokeWidth = computed(() => {
84
+ const outer = radiusInPixels(props.outerRadius ?? "100%", props.height / 2);
85
+ const inner = radiusInPixels(props.innerRadius ?? "30%", props.height * 0.15);
86
+ return Math.max((outer - inner) / Math.max(bars.value.length, 1) * 0.9, 1);
87
+ });
88
+ const cursor = computed(
89
+ () => resolveHoverVisible(props.theme) ? {
90
+ fill: "none",
91
+ stroke: "var(--vc-hover-fill)",
92
+ strokeWidth: hoverStrokeWidth.value
93
+ } : false
94
+ );
77
95
  const legend = computed(() => legendPositionToLegendProps(props.legendPosition));
78
96
  const legendWrapperStyle = computed(
79
97
  () => resolveLegendWrapperStyle(props.legendPosition, toCssProperties(props.legendStyle))
@@ -113,7 +131,11 @@ const onCenter = (next) => {
113
131
  :is-animation-active="duration !== void 0 && duration !== 0"
114
132
  :transition="{ duration: (duration ?? 400) / 1e3, ease: 'easeOut' }"
115
133
  />
116
- <Tooltip v-if="!hideTooltip" :content="tooltipContent" :is-animation-active="false" />
134
+ <Tooltip
135
+ :content="hideTooltip ? hiddenTooltipContent : tooltipContent"
136
+ :cursor="cursor"
137
+ :is-animation-active="false"
138
+ />
117
139
  <Legend
118
140
  v-if="!hideLegend"
119
141
  :align="legend.align"
@@ -55,11 +55,11 @@ const nodeLabel = (node) => {
55
55
  const input = node;
56
56
  return props.label?.(input) ?? String(input.name ?? input.id ?? "");
57
57
  };
58
- const resolvedNodeColor = (node) => props.nodeColor?.(node) ?? "var(--chart-color-0)";
58
+ const resolvedNodeColor = (node) => props.nodeColor?.(node) ?? "var(--vc-series-0)";
59
59
  const resolvedLinkColor = (link) => {
60
60
  const layoutLink = link;
61
61
  const inputLink = layoutLink.__source === void 0 ? layoutLink : { ...layoutLink, source: layoutLink.__source };
62
- return props.linkColor?.(inputLink) ?? "var(--chart-color-0)";
62
+ return props.linkColor?.(inputLink) ?? "var(--vc-series-0)";
63
63
  };
64
64
  function handleMouseEnter(item, type) {
65
65
  activeColor.value = type === "node" ? resolvedNodeColor(item) : resolvedLinkColor(item);
@@ -135,7 +135,7 @@ const accessibleRows = computed(() => chartData.value.links.map((link) => ({
135
135
  :width="nodeProps.width"
136
136
  :height="nodeProps.height"
137
137
  :fill="resolvedNodeColor(nodeProps.payload)"
138
- stroke="var(--vc-surface, #fff)"
138
+ stroke="var(--vc-surface-bg, #fff)"
139
139
  />
140
140
  <text
141
141
  :x="nodeProps.payload.depth === 0 ? nodeProps.x - 8 : nodeProps.x + nodeProps.width + 8"
@@ -296,6 +296,7 @@ const resolvedYAxes = computed(() => {
296
296
  v-if="showXGrid || showYGrid"
297
297
  :horizontal="showYGrid"
298
298
  :vertical="showXGrid"
299
+ :sync-with-ticks="true"
299
300
  :stroke="gridStroke"
300
301
  stroke-dasharray="var(--vc-grid-dash)"
301
302
  :stroke-width="'var(--vc-grid-width)'"
@@ -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;
@@ -129,6 +129,11 @@ export interface ChartPadding {
129
129
  * scale legend, axis ticks, axis titles, and radar labels together.
130
130
  */
131
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[];
132
137
  /** Grid + axis (domain) lines. */
133
138
  grid?: {
134
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) => ({
@@ -4,6 +4,9 @@ export function themeToVars(theme) {
4
4
  const set = (name, value) => {
5
5
  if (value !== void 0) vars[name] = String(value);
6
6
  };
7
+ theme.colors?.slice(0, 8).forEach((color, index) => {
8
+ set(`--vc-series-${index}`, color);
9
+ });
7
10
  set("--vc-grid-color", theme.grid?.color);
8
11
  set("--vc-grid-dash", theme.grid?.dash);
9
12
  set("--vc-grid-width", theme.grid?.width);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-charts",
3
- "version": "3.0.0-beta.4",
3
+ "version": "3.0.0",
4
4
  "description": "Beautiful chart components for Nuxt (vccs engine) — Area, Bar, Line, Donut, Bubble, Radar, Radial Bar, Funnel, Sankey, Candlestick, Status Tracker",
5
5
  "license": "MIT",
6
6
  "author": "Dennis Adriaansen <adriaansendennis@gmail.com>",