nuxt-charts 3.0.0-beta.0 → 3.0.0-beta.2

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/dist/module.json CHANGED
@@ -4,9 +4,9 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3"
6
6
  },
7
- "version": "3.0.0-beta.0",
7
+ "version": "3.0.0-beta.2",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
- "unbuild": "3.6.1"
10
+ "unbuild": "unknown"
11
11
  }
12
12
  }
@@ -1 +1 @@
1
- @layer vue-chrts{.vc-tooltip{background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));font-size:var(--vc-legend-size,.75rem);line-height:1.5;min-width:8rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none}.vc-tooltip,.vc-tooltip__label{color:var(--vc-tooltip-fg,oklch(.205 0 0))}.vc-tooltip__label{font-weight:500;margin:0 0 .25rem}.vc-tooltip__list{display:flex;flex-direction:column;gap:.125rem;list-style:none;margin:0;padding:0}.vc-tooltip__item{align-items:center;display:flex;gap:.375rem}.vc-tooltip__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:.5rem;width:.5rem}.vc-tooltip__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-tooltip__value{color:var(--vc-tooltip-fg,oklch(.205 0 0));font-variant-numeric:tabular-nums;font-weight:500;margin-left:auto}.vc-legend{flex-wrap:wrap;font-size:var(--vc-legend-size,.75rem);font-weight:var(--vc-legend-weight,400);gap:var(--vc-legend-gap,.75rem);justify-content:center;line-height:1.5;list-style:none;margin:0;padding:0}.vc-legend,.vc-legend__item{align-items:center;display:flex}.vc-legend__item{gap:.375rem}.vc-legend__item--inactive{opacity:.4}.vc-legend__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-legend__label{color:var(--vc-legend-color,oklch(.556 0 0))}.vc-candlestick-chart{cursor:crosshair;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.vc-candlestick-chart__svg{display:block;overflow:visible;width:100%}.vc-funnel-layered{position:relative;width:100%}.vc-funnel-layered__tooltip{align-items:center;background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));color:var(--vc-tooltip-fg,oklch(.205 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);gap:.375rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none;position:absolute;transform:translate(-50%,calc(-100% - 10px));white-space:nowrap}.vc-funnel-layered__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-funnel-layered__value{font-variant-numeric:tabular-nums;font-weight:600}.vc-funnel-layered__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-funnel-layered-shape{opacity:.96;transition:opacity .15s}.vc-funnel-layered-shape:hover{opacity:1}.vc-status-tracker{color:var(--foreground,oklch(.205 0 0));font-family:inherit;width:100%}.vc-status-tracker__header{align-items:baseline;display:flex;gap:1rem;justify-content:space-between;margin-bottom:.75rem}.vc-status-tracker__summary,.vc-status-tracker__title{font-size:.875rem;line-height:1.25rem;margin:0}.vc-status-tracker__title{font-weight:600}.vc-status-tracker__summary{color:var(--muted-foreground,oklch(.556 0 0));font-variant-numeric:tabular-nums}.vc-status-tracker__track{display:flex;overflow:hidden;width:100%}.vc-status-tracker__bar{display:block;flex:0 0 auto;height:100%;min-width:1px;transition:opacity .16s ease}.vc-status-tracker__bar:hover{opacity:.78}.vc-status-tracker__bar--rounded-start{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.vc-status-tracker__bar--rounded-end{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.vc-status-tracker__bar--empty:hover{opacity:1}.vc-status-tracker__labels{gap:1rem;justify-content:space-between;margin-top:.5rem}.vc-status-tracker__labels,.vc-status-tracker__legend{color:var(--vc-legend-color,oklch(.556 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);line-height:1rem}.vc-status-tracker__legend{flex-wrap:wrap;gap:.5rem 1rem;list-style:none;margin:.75rem 0 0;padding:0}.vc-status-tracker__legend-item{align-items:center;display:inline-flex;gap:.375rem}.vc-status-tracker__legend-dot{border-radius:9999px;flex:0 0 auto;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}}
1
+ @layer vue-chrts{.vc-tooltip{background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));font-size:var(--vc-legend-size,.75rem);line-height:1.5;min-width:8rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none}.vc-tooltip,.vc-tooltip__label{color:var(--vc-tooltip-fg,oklch(.205 0 0))}.vc-tooltip__label{font-weight:500;margin:0 0 .25rem}.vc-tooltip__list{display:flex;flex-direction:column;gap:.125rem;list-style:none;margin:0;padding:0}.vc-tooltip__item{align-items:center;display:flex;gap:.375rem}.vc-tooltip__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:.5rem;width:.5rem}.vc-tooltip__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-tooltip__value{color:var(--vc-tooltip-fg,oklch(.205 0 0));font-variant-numeric:tabular-nums;font-weight:500;margin-left:auto}.vc-legend{flex-wrap:wrap;font-size:var(--vc-legend-size,.75rem);font-weight:var(--vc-legend-weight,400);gap:var(--vc-legend-gap,.75rem);justify-content:center;line-height:1.5;list-style:none;margin:0;padding:0}.vc-legend,.vc-legend__item{align-items:center;display:flex}.vc-legend__item{gap:.375rem}.vc-legend__item--inactive{opacity:.4}.vc-legend__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-legend__label{color:var(--vc-legend-color,oklch(.556 0 0))}.vc-candlestick-chart{cursor:crosshair;position:relative;-webkit-user-select:none;-moz-user-select:none;user-select:none;width:100%}.vc-candlestick-chart__svg{display:block;overflow:visible;width:100%}.vc-funnel-layered{position:relative;width:100%}.vc-funnel-layered__tooltip{align-items:center;background:var(--vc-tooltip-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:var(--vc-tooltip-radius,.5rem);box-shadow:var(--vc-tooltip-shadow,0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1));color:var(--vc-tooltip-fg,oklch(.205 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);gap:.375rem;padding:var(--vc-tooltip-padding,.375rem .625rem);pointer-events:none;position:absolute;transform:translate(-50%,calc(-100% - 10px));white-space:nowrap}.vc-funnel-layered__name{color:var(--vc-tooltip-muted,oklch(.556 0 0))}.vc-funnel-layered__value{font-variant-numeric:tabular-nums;font-weight:600}.vc-funnel-layered__dot{border-radius:9999px;display:inline-block;flex-shrink:0;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}.vc-funnel-layered-shape{opacity:.96;transition:opacity .15s}.vc-funnel-layered-shape:hover{opacity:1}.vc-status-tracker{color:var(--vc-axis-label-color,var(--ui-text-highlighted,var(--foreground,oklch(.205 0 0))));font-family:inherit;width:100%}.vc-status-tracker__header{align-items:baseline;display:flex;gap:1rem;justify-content:space-between;margin-bottom:.75rem}.vc-status-tracker__summary,.vc-status-tracker__title{font-size:.875rem;line-height:1.25rem;margin:0}.vc-status-tracker__title{font-weight:600}.vc-status-tracker__summary{color:var(--vc-tick-color,var(--ui-text-muted,var(--muted-foreground,oklch(.556 0 0))));font-variant-numeric:tabular-nums}.vc-status-tracker__track{display:flex;overflow:hidden;width:100%}.vc-status-tracker__bar{display:block;flex:0 0 auto;height:100%;min-width:1px;transition:opacity .16s ease}.vc-status-tracker__bar:hover{opacity:.78}.vc-status-tracker__bar--rounded-start{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.vc-status-tracker__bar--rounded-end{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.vc-status-tracker__bar--empty:hover{opacity:1}.vc-status-tracker__labels{gap:1rem;justify-content:space-between;margin-top:.5rem}.vc-status-tracker__labels,.vc-status-tracker__legend{color:var(--vc-legend-color,oklch(.556 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);line-height:1rem}.vc-status-tracker__legend{flex-wrap:wrap;gap:.5rem 1rem;list-style:none;margin:.75rem 0 0;padding:0}.vc-status-tracker__legend-item{align-items:center;display:inline-flex;gap:.375rem}.vc-status-tracker__legend-dot{border-radius:9999px;flex:0 0 auto;height:var(--vc-legend-dot-size,.5rem);width:var(--vc-legend-dot-size,.5rem)}}
@@ -1 +1 @@
1
- @layer vue-chrts{.vue-chrts{--vc-grid-color:var(--border,oklch(0.922 0 0));--vc-grid-dash:3 3;--vc-grid-width:1px;--vc-axis-line-color:var(--border,oklch(0.922 0 0));--vc-axis-line-width:1px;--vc-legend-size:0.75rem;--vc-legend-weight:400;--vc-tick-color: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(--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(--muted-foreground,oklch(0.556 0 0));--vc-legend-dot-size:0.5rem;--vc-hover-fill:color-mix(in oklab,var(--foreground,oklch(0.205 0 0)) 6%,transparent);--vc-hover-stroke:transparent;--vc-hover-radius:6px;--vc-tooltip-bg:var(--popover,oklch(1 0 0));--vc-tooltip-fg:var(--popover-foreground,oklch(0.205 0 0));--vc-tooltip-muted:var(--muted-foreground,oklch(0.556 0 0));--vc-tooltip-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:is(.dark,[data-theme=dark],.dark *,[data-theme=dark] *),:is(.dark,[data-theme=dark]) .vue-chrts{--vc-grid-color:var(--border,oklch(0.269 0 0));--vc-axis-line-color:var(--border,oklch(0.269 0 0));--vc-tick-color:var(--muted-foreground,oklch(0.708 0 0));--vc-axis-label-color:var(--foreground,oklch(0.985 0 0));--vc-legend-color:var(--muted-foreground,oklch(0.708 0 0));--vc-hover-fill:color-mix(in oklab,oklch(0.985 0 0) 8%,transparent);--vc-tooltip-bg:var(--popover,oklch(0.205 0 0));--vc-tooltip-fg:var(--popover-foreground,oklch(0.985 0 0));--vc-tooltip-muted:var(--muted-foreground,oklch(0.708 0 0));--vc-tooltip-border:var(--border,oklch(0.269 0 0))}}
1
+ @layer vue-chrts{.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-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-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: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)))}}
@@ -3,7 +3,6 @@ import { computed } from "vue";
3
3
  import {
4
4
  CartesianGrid,
5
5
  Legend,
6
- ResponsiveContainer,
7
6
  Scatter,
8
7
  ScatterChart,
9
8
  Tooltip,
@@ -11,6 +10,7 @@ import {
11
10
  YAxis,
12
11
  ZAxis
13
12
  } from "vccs";
13
+ import ChartContainer from "./internal/ChartContainer";
14
14
  import ChartTooltip from "./internal/ChartTooltip.vue";
15
15
  import ChartLegend from "./internal/ChartLegend.vue";
16
16
  import { categoriesToSeries } from "../utils/categories";
@@ -147,7 +147,7 @@ const groups = computed(() => {
147
147
 
148
148
  <template>
149
149
  <div class="vue-chrts" :style="themeVars">
150
- <ResponsiveContainer width="100%" :height="height">
150
+ <ChartContainer width="100%" :height="height">
151
151
  <ScatterChart>
152
152
  <CartesianGrid
153
153
  v-if="(xGridLine ?? true) || (yGridLine ?? true)"
@@ -208,6 +208,6 @@ const groups = computed(() => {
208
208
  </template>
209
209
  </Legend>
210
210
  </ScatterChart>
211
- </ResponsiveContainer>
211
+ </ChartContainer>
212
212
  </div>
213
213
  </template>
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { computed } from "vue";
3
- import { Legend, Pie, PieChart, ResponsiveContainer, Tooltip } from "vccs";
3
+ import { Legend, Pie, PieChart, Tooltip } from "vccs";
4
+ import ChartContainer from "./internal/ChartContainer";
4
5
  import ChartTooltip from "./internal/ChartTooltip.vue";
5
6
  import ChartLegend from "./internal/ChartLegend.vue";
6
7
  import { DonutType } from "../enums";
@@ -69,7 +70,7 @@ const legendWrapperStyle = computed(
69
70
 
70
71
  <template>
71
72
  <div class="donut-chart vue-chrts" :style="{ position: 'relative', width: '100%', height: `${height ?? (radius ? radius * 2 : 200)}px`, ...themeVars }">
72
- <ResponsiveContainer width="100%" height="100%">
73
+ <ChartContainer width="100%" height="100%">
73
74
  <PieChart>
74
75
  <Pie
75
76
  :data="segments"
@@ -96,7 +97,7 @@ const legendWrapperStyle = computed(
96
97
  </template>
97
98
  </Legend>
98
99
  </PieChart>
99
- </ResponsiveContainer>
100
+ </ChartContainer>
100
101
 
101
102
  <!-- Centered overlay for custom content (v2 parity: default slot). -->
102
103
  <div
@@ -5,9 +5,9 @@ import {
5
5
  FunnelChart as VccsFunnelChart,
6
6
  LabelList,
7
7
  Legend,
8
- ResponsiveContainer,
9
8
  Tooltip
10
9
  } from "vccs";
10
+ import ChartContainer from "./internal/ChartContainer";
11
11
  import ChartTooltip from "./internal/ChartTooltip.vue";
12
12
  import ChartLegend from "./internal/ChartLegend.vue";
13
13
  import FunnelLayeredShape, {
@@ -85,7 +85,7 @@ function hideTooltip() {
85
85
  class="vc-funnel-layered vue-chrts"
86
86
  :style="{ height: `${height}px`, ...themeVars }"
87
87
  >
88
- <ResponsiveContainer width="100%" height="100%">
88
+ <ChartContainer width="100%" height="100%">
89
89
  <VccsFunnelChart :margin="{ top: 16, right: 0, bottom: 8, left: 0 }">
90
90
  <Funnel
91
91
  :data="layeredData"
@@ -104,7 +104,7 @@ function hideTooltip() {
104
104
  </template>
105
105
  </Funnel>
106
106
  </VccsFunnelChart>
107
- </ResponsiveContainer>
107
+ </ChartContainer>
108
108
 
109
109
  <div
110
110
  v-if="!hideTooltip && activeDatum"
@@ -123,7 +123,7 @@ function hideTooltip() {
123
123
  </div>
124
124
 
125
125
  <div v-else class="vue-chrts" :style="themeVars">
126
- <ResponsiveContainer width="100%" :height="height">
126
+ <ChartContainer width="100%" :height="height">
127
127
  <VccsFunnelChart>
128
128
  <Funnel
129
129
  :data="stages"
@@ -147,6 +147,6 @@ function hideTooltip() {
147
147
  </template>
148
148
  </Legend>
149
149
  </VccsFunnelChart>
150
- </ResponsiveContainer>
150
+ </ChartContainer>
151
151
  </div>
152
152
  </template>
@@ -7,9 +7,9 @@ import {
7
7
  PolarRadiusAxis,
8
8
  Radar,
9
9
  RadarChart as VccsRadarChart,
10
- ResponsiveContainer,
11
10
  Tooltip
12
11
  } from "vccs";
12
+ import ChartContainer from "./internal/ChartContainer";
13
13
  import ChartTooltip from "./internal/ChartTooltip.vue";
14
14
  import ChartLegend from "./internal/ChartLegend.vue";
15
15
  import { categoriesToSeries } from "../utils/categories";
@@ -45,7 +45,7 @@ const themeVars = computed(() => themeToVars(props.theme));
45
45
 
46
46
  <template>
47
47
  <div class="vue-chrts" :style="themeVars">
48
- <ResponsiveContainer width="100%" :height="height">
48
+ <ChartContainer width="100%" :height="height">
49
49
  <VccsRadarChart :data="data">
50
50
  <PolarGrid stroke="var(--vc-grid-color)" />
51
51
  <PolarAngleAxis :data-key="angleKey" :tick-formatter="angleFormatter" />
@@ -85,6 +85,6 @@ const themeVars = computed(() => themeToVars(props.theme));
85
85
  </template>
86
86
  </Legend>
87
87
  </VccsRadarChart>
88
- </ResponsiveContainer>
88
+ </ChartContainer>
89
89
  </div>
90
90
  </template>
@@ -4,9 +4,9 @@ import {
4
4
  Legend,
5
5
  RadialBar,
6
6
  RadialBarChart as VccsRadialBarChart,
7
- ResponsiveContainer,
8
7
  Tooltip
9
8
  } from "vccs";
9
+ import ChartContainer from "./internal/ChartContainer";
10
10
  import ChartTooltip from "./internal/ChartTooltip.vue";
11
11
  import ChartLegend from "./internal/ChartLegend.vue";
12
12
  import { categoriesToSeries } from "../utils/categories";
@@ -49,7 +49,7 @@ const legendWrapperStyle = computed(
49
49
 
50
50
  <template>
51
51
  <div class="vue-chrts" :style="themeVars">
52
- <ResponsiveContainer width="100%" :height="height">
52
+ <ChartContainer width="100%" :height="height">
53
53
  <VccsRadialBarChart
54
54
  :data="bars"
55
55
  :inner-radius="innerRadius ?? '30%'"
@@ -76,6 +76,6 @@ const legendWrapperStyle = computed(
76
76
  </template>
77
77
  </Legend>
78
78
  </VccsRadialBarChart>
79
- </ResponsiveContainer>
79
+ </ChartContainer>
80
80
  </div>
81
81
  </template>
@@ -4,11 +4,11 @@ import {
4
4
  CartesianGrid,
5
5
  Legend,
6
6
  ReferenceLine,
7
- ResponsiveContainer,
8
7
  Tooltip,
9
8
  XAxis,
10
9
  YAxis
11
10
  } from "vccs";
11
+ import ChartContainer from "./ChartContainer";
12
12
  import { legendPositionToLegendProps, resolveLegendWrapperStyle } from "../../utils/legend";
13
13
  import {
14
14
  AXIS_TICK_MARGIN,
@@ -212,7 +212,7 @@ const resolvedYAxes = computed(() => {
212
212
 
213
213
  <template>
214
214
  <div class="vue-chrts" :style="rootStyle">
215
- <ResponsiveContainer width="100%" :height="height">
215
+ <ChartContainer width="100%" :height="height">
216
216
  <component :is="container" v-bind="mergedContainerProps">
217
217
  <CartesianGrid
218
218
  v-if="showXGrid || showYGrid"
@@ -316,6 +316,6 @@ const resolvedYAxes = computed(() => {
316
316
  </template>
317
317
  </Legend>
318
318
  </component>
319
- </ResponsiveContainer>
319
+ </ChartContainer>
320
320
  </div>
321
321
  </template>
@@ -0,0 +1,91 @@
1
+ import { type PropType, type VNode } from "vue";
2
+ type Size = number | string;
3
+ /**
4
+ * Drop-in replacement for `vccs`' `ResponsiveContainer`.
5
+ *
6
+ * Upstream renders children through `resolveDynamicComponent(() => renderChildren())`,
7
+ * which produces a new component type every render and so unmounts + remounts the
8
+ * whole chart subtree. Charts that dispatch on `mouseenter` (radial bar, radar) then
9
+ * loop forever — remount recreates the `<path>` under the cursor, which refires
10
+ * `mouseenter` — and freeze the tab. Rendering the cloned children directly keeps
11
+ * the subtree stable.
12
+ */
13
+ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
14
+ width: {
15
+ type: PropType<Size>;
16
+ default: string;
17
+ };
18
+ height: {
19
+ type: PropType<Size>;
20
+ default: string;
21
+ };
22
+ aspect: {
23
+ type: NumberConstructor;
24
+ default: undefined;
25
+ };
26
+ minWidth: {
27
+ type: PropType<Size>;
28
+ default: number;
29
+ };
30
+ minHeight: {
31
+ type: PropType<Size>;
32
+ default: undefined;
33
+ };
34
+ maxHeight: {
35
+ type: PropType<Size>;
36
+ default: undefined;
37
+ };
38
+ id: {
39
+ type: StringConstructor;
40
+ default: undefined;
41
+ };
42
+ onResize: {
43
+ type: PropType<(width: number, height: number) => void>;
44
+ default: undefined;
45
+ };
46
+ }>, () => VNode<import("vue").RendererNode, import("vue").RendererElement, {
47
+ [key: string]: any;
48
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
49
+ width: {
50
+ type: PropType<Size>;
51
+ default: string;
52
+ };
53
+ height: {
54
+ type: PropType<Size>;
55
+ default: string;
56
+ };
57
+ aspect: {
58
+ type: NumberConstructor;
59
+ default: undefined;
60
+ };
61
+ minWidth: {
62
+ type: PropType<Size>;
63
+ default: number;
64
+ };
65
+ minHeight: {
66
+ type: PropType<Size>;
67
+ default: undefined;
68
+ };
69
+ maxHeight: {
70
+ type: PropType<Size>;
71
+ default: undefined;
72
+ };
73
+ id: {
74
+ type: StringConstructor;
75
+ default: undefined;
76
+ };
77
+ onResize: {
78
+ type: PropType<(width: number, height: number) => void>;
79
+ default: undefined;
80
+ };
81
+ }>> & Readonly<{}>, {
82
+ width: Size;
83
+ height: Size;
84
+ aspect: number;
85
+ minWidth: Size;
86
+ minHeight: Size;
87
+ maxHeight: Size;
88
+ id: string;
89
+ onResize: (width: number, height: number) => void;
90
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
91
+ export default _default;
@@ -0,0 +1,111 @@
1
+ import {
2
+ cloneVNode,
3
+ computed,
4
+ defineComponent,
5
+ Fragment,
6
+ h,
7
+ onBeforeUnmount,
8
+ onMounted,
9
+ ref
10
+ } from "vue";
11
+ const isPercent = (value) => typeof value === "string" && value.endsWith("%");
12
+ const toCssSize = (value) => value == null ? void 0 : typeof value === "number" ? `${value}px` : value;
13
+ function flatten(vnodes) {
14
+ const result = [];
15
+ for (const vnode of vnodes) {
16
+ if (vnode.type === Fragment && Array.isArray(vnode.children))
17
+ result.push(...flatten(vnode.children));
18
+ else result.push(vnode);
19
+ }
20
+ return result;
21
+ }
22
+ export default defineComponent({
23
+ name: "ChartContainer",
24
+ inheritAttrs: false,
25
+ props: {
26
+ width: { type: [Number, String], default: "100%" },
27
+ height: { type: [Number, String], default: "100%" },
28
+ aspect: { type: Number, default: void 0 },
29
+ minWidth: { type: [Number, String], default: 0 },
30
+ minHeight: { type: [Number, String], default: void 0 },
31
+ maxHeight: { type: [Number, String], default: void 0 },
32
+ id: { type: String, default: void 0 },
33
+ onResize: { type: Function, default: void 0 }
34
+ },
35
+ setup(props, { slots }) {
36
+ const containerRef = ref();
37
+ const sizes = ref({ width: -1, height: -1 });
38
+ const calculatedWidth = computed(
39
+ () => isPercent(props.width) ? sizes.value.width : Number(props.width)
40
+ );
41
+ const calculatedHeight = computed(() => {
42
+ if (props.aspect && props.aspect > 0 && (props.height == null || props.height === "auto"))
43
+ return calculatedWidth.value / props.aspect;
44
+ return isPercent(props.height) ? sizes.value.height : Number(props.height);
45
+ });
46
+ const finalWidth = computed(() => {
47
+ if (props.aspect && props.aspect > 0 && (props.width == null || props.width === "auto"))
48
+ return calculatedHeight.value * props.aspect;
49
+ return calculatedWidth.value;
50
+ });
51
+ const isReady = computed(() => sizes.value.width >= 0 && sizes.value.height >= 0);
52
+ const containerStyle = computed(() => ({
53
+ width: toCssSize(props.width),
54
+ height: toCssSize(props.height),
55
+ minWidth: toCssSize(props.minWidth),
56
+ minHeight: toCssSize(props.minHeight),
57
+ maxHeight: toCssSize(props.maxHeight)
58
+ }));
59
+ function setSize(width, height) {
60
+ const next = { width: Math.round(width), height: Math.round(height) };
61
+ if (next.width === sizes.value.width && next.height === sizes.value.height) return;
62
+ sizes.value = next;
63
+ props.onResize?.(next.width, next.height);
64
+ }
65
+ let observer = null;
66
+ onMounted(() => {
67
+ const el = containerRef.value;
68
+ if (!el) return;
69
+ const rect = el.getBoundingClientRect();
70
+ setSize(rect.width, rect.height);
71
+ observer = new ResizeObserver((entries) => {
72
+ const { width, height } = entries[0].contentRect;
73
+ setSize(width, height);
74
+ });
75
+ observer.observe(el);
76
+ });
77
+ onBeforeUnmount(() => {
78
+ observer?.disconnect();
79
+ observer = null;
80
+ });
81
+ function renderChildren() {
82
+ if (!isReady.value) return [];
83
+ const raw = slots.default?.();
84
+ if (!raw) return [];
85
+ return flatten(raw).map(
86
+ (child, index) => cloneVNode(child, {
87
+ width: finalWidth.value,
88
+ height: calculatedHeight.value,
89
+ key: child.key || `chart-container-child-${index}`,
90
+ style: {
91
+ maxWidth: `${sizes.value.width}px`,
92
+ maxHeight: `${sizes.value.height}px`,
93
+ width: "100%",
94
+ height: "100%",
95
+ ...child.props?.style
96
+ }
97
+ })
98
+ );
99
+ }
100
+ return () => h(
101
+ "div",
102
+ {
103
+ id: props.id,
104
+ ref: containerRef,
105
+ class: "vcharts-responsive-container",
106
+ style: containerStyle.value
107
+ },
108
+ renderChildren()
109
+ );
110
+ }
111
+ });
@@ -72,14 +72,14 @@ export default { name: "FunnelLayeredShape" };
72
72
  :x2="geometry.startX"
73
73
  :y1="geometry.dividerStartY"
74
74
  :y2="geometry.dividerEndY"
75
- :stroke="`hsl(var(--background, 0 0% 100%))`"
75
+ stroke="var(--vc-surface-bg)"
76
76
  :stroke-width="5"
77
77
  />
78
78
 
79
79
  <text
80
80
  :x="geometry.middleX"
81
81
  :y="geometry.topLabelY"
82
- :fill="`hsl(var(--foreground, 222.2 84% 4.9%))`"
82
+ fill="var(--vc-axis-label-color)"
83
83
  :font-size="16"
84
84
  :font-weight="700"
85
85
  text-anchor="middle"
@@ -93,16 +93,16 @@ export default { name: "FunnelLayeredShape" };
93
93
  :width="geometry.badgeWidth"
94
94
  :height="30"
95
95
  :rx="15"
96
- :fill="`hsl(var(--background, 0 0% 100%))`"
96
+ fill="var(--vc-surface-bg)"
97
97
  fill-opacity="0.82"
98
- :stroke="`hsl(var(--border, 214.3 31.8% 91.4%))`"
98
+ stroke="var(--vc-axis-line-color)"
99
99
  stroke-opacity="0.7"
100
100
  :stroke-width="1"
101
101
  />
102
102
  <text
103
103
  :x="geometry.middleX"
104
104
  :y="geometry.centerY + 5"
105
- :fill="`hsl(var(--foreground, 222.2 84% 4.9%))`"
105
+ fill="var(--vc-axis-label-color)"
106
106
  :font-size="14"
107
107
  :font-weight="600"
108
108
  text-anchor="middle"
@@ -113,7 +113,7 @@ export default { name: "FunnelLayeredShape" };
113
113
  <text
114
114
  :x="geometry.middleX"
115
115
  :y="geometry.bottomLabelY"
116
- :fill="`hsl(var(--muted-foreground, 215.4 16.3% 46.9%))`"
116
+ fill="var(--vc-tick-color)"
117
117
  :font-size="15"
118
118
  :font-weight="500"
119
119
  text-anchor="middle"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuxt-charts",
3
- "version": "3.0.0-beta.0",
3
+ "version": "3.0.0-beta.2",
4
4
  "description": "Beautiful chart components for Nuxt (vccs engine) — Area, Bar, Line, Donut, Bubble, Radar, Radial Bar, Funnel, Candlestick, Status Tracker",
5
5
  "license": "MIT",
6
6
  "author": "Dennis Adriaansen <adriaansendennis@gmail.com>",
@@ -46,6 +46,20 @@
46
46
  "files": [
47
47
  "dist"
48
48
  ],
49
+ "scripts": {
50
+ "prepack": "nuxt-module-build build",
51
+ "dev": "nuxi dev playground",
52
+ "build": "nuxt-module-build build",
53
+ "build:playground": "nuxi build playground",
54
+ "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
55
+ "release": "node ../../tools/release.mjs --package nuxt-charts",
56
+ "lint": "eslint .",
57
+ "typecheck": "pnpm run test:types",
58
+ "test": "vitest run",
59
+ "test:watch": "vitest watch",
60
+ "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
61
+ "release:dry": "node ../../tools/release.mjs --package nuxt-charts --dry-run"
62
+ },
49
63
  "dependencies": {
50
64
  "@types/d3-array": "^3.2.2",
51
65
  "@types/d3-scale": "^4.0.9",
@@ -58,7 +72,7 @@
58
72
  "d3-shape": "^3.2.0",
59
73
  "d3-zoom": "^3.0.0",
60
74
  "motion-v": "^2.3.0",
61
- "vccs": "^0.4.0"
75
+ "vccs": "^0.5.0"
62
76
  },
63
77
  "devDependencies": {
64
78
  "@nuxt/devtools": "^3.1.1",
@@ -67,10 +81,10 @@
67
81
  "@nuxt/kit": "^4.3.0",
68
82
  "@nuxt/module-builder": "^1.0.2",
69
83
  "@nuxt/schema": "^4.3.0",
70
- "@nuxt/test-utils": "^3.23.0",
84
+ "@nuxt/test-utils": "^4.2.0",
71
85
  "@tailwindcss/vite": "^4.2.2",
72
86
  "@types/node": "latest",
73
- "@vitejs/plugin-vue": "^5.2.4",
87
+ "@vitejs/plugin-vue": "^6.0.8",
74
88
  "@vue/test-utils": "^2.4.11",
75
89
  "eslint": "^9.39.2",
76
90
  "happy-dom": "^20.10.6",
@@ -78,23 +92,12 @@
78
92
  "tailwindcss": "^4.2.2",
79
93
  "typescript": "~5.9.3",
80
94
  "vitest": "^4.0.18",
95
+ "vue": "^3.5.42",
81
96
  "vue-tsc": "^3.2.4"
82
97
  },
98
+ "packageManager": "pnpm@10.33.0",
83
99
  "publishConfig": {
84
100
  "access": "public",
85
101
  "tag": "beta"
86
- },
87
- "scripts": {
88
- "dev": "nuxi dev playground",
89
- "build": "nuxt-module-build build",
90
- "build:playground": "nuxi build playground",
91
- "dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
92
- "release": "node ../../tools/release.mjs --package nuxt-charts",
93
- "lint": "eslint .",
94
- "typecheck": "pnpm run test:types",
95
- "test": "vitest run",
96
- "test:watch": "vitest watch",
97
- "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit",
98
- "release:dry": "node ../../tools/release.mjs --package nuxt-charts --dry-run"
99
102
  }
100
- }
103
+ }