nuxt-charts 3.0.0-beta.1 → 3.0.0-beta.3

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 (82) hide show
  1. package/README.md +77 -7
  2. package/dist/module.json +2 -2
  3. package/dist/module.mjs +20 -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.d.vue.ts +5 -1
  7. package/dist/runtime/components/AreaChart.vue +84 -9
  8. package/dist/runtime/components/AreaChart.vue.d.ts +5 -1
  9. package/dist/runtime/components/BarChart.d.vue.ts +5 -1
  10. package/dist/runtime/components/BarChart.vue +125 -8
  11. package/dist/runtime/components/BarChart.vue.d.ts +5 -1
  12. package/dist/runtime/components/BubbleChart.d.vue.ts +5 -1
  13. package/dist/runtime/components/BubbleChart.vue +74 -13
  14. package/dist/runtime/components/BubbleChart.vue.d.ts +5 -1
  15. package/dist/runtime/components/DonutChart.vue +67 -15
  16. package/dist/runtime/components/FunnelChart.d.vue.ts +8 -1
  17. package/dist/runtime/components/FunnelChart.vue +127 -35
  18. package/dist/runtime/components/FunnelChart.vue.d.ts +8 -1
  19. package/dist/runtime/components/LineChart.d.vue.ts +5 -1
  20. package/dist/runtime/components/LineChart.vue +72 -7
  21. package/dist/runtime/components/LineChart.vue.d.ts +5 -1
  22. package/dist/runtime/components/RadarChart.vue +93 -12
  23. package/dist/runtime/components/RadialBarChart.vue +40 -8
  24. package/dist/runtime/components/SankeyChart.d.vue.ts +36 -0
  25. package/dist/runtime/components/SankeyChart.vue +146 -0
  26. package/dist/runtime/components/SankeyChart.vue.d.ts +36 -0
  27. package/dist/runtime/components/internal/AreaVariantDefs.d.ts +68 -0
  28. package/dist/runtime/components/internal/AreaVariantDefs.js +165 -0
  29. package/dist/runtime/components/internal/BarVariantDefs.d.ts +74 -0
  30. package/dist/runtime/components/internal/BarVariantDefs.js +200 -0
  31. package/dist/runtime/components/internal/CartesianFrame.d.vue.ts +18 -1
  32. package/dist/runtime/components/internal/CartesianFrame.vue +65 -14
  33. package/dist/runtime/components/internal/CartesianFrame.vue.d.ts +18 -1
  34. package/dist/runtime/components/internal/ChartBackground.d.ts +44 -0
  35. package/dist/runtime/components/internal/ChartBackground.js +53 -0
  36. package/dist/runtime/components/internal/ChartDot.d.ts +85 -0
  37. package/dist/runtime/components/internal/ChartDot.js +59 -0
  38. package/dist/runtime/components/internal/ChartLegend.d.vue.ts +24 -1
  39. package/dist/runtime/components/internal/ChartLegend.vue +11 -3
  40. package/dist/runtime/components/internal/ChartLegend.vue.d.ts +24 -1
  41. package/dist/runtime/components/internal/ChartSkeleton.d.vue.ts +18 -0
  42. package/dist/runtime/components/internal/ChartSkeleton.vue +64 -0
  43. package/dist/runtime/components/internal/ChartSkeleton.vue.d.ts +18 -0
  44. package/dist/runtime/components/internal/ChartTooltip.vue +8 -2
  45. package/dist/runtime/components/internal/CubeBarShape.d.vue.ts +9 -1
  46. package/dist/runtime/components/internal/CubeBarShape.vue +8 -8
  47. package/dist/runtime/components/internal/CubeBarShape.vue.d.ts +9 -1
  48. package/dist/runtime/components/internal/FunnelClassicShape.d.vue.ts +81 -0
  49. package/dist/runtime/components/internal/FunnelClassicShape.vue +97 -0
  50. package/dist/runtime/components/internal/FunnelClassicShape.vue.d.ts +81 -0
  51. package/dist/runtime/components/internal/FunnelLayeredShape.d.vue.ts +21 -0
  52. package/dist/runtime/components/internal/FunnelLayeredShape.vue +71 -37
  53. package/dist/runtime/components/internal/FunnelLayeredShape.vue.d.ts +21 -0
  54. package/dist/runtime/components/internal/FunnelTooltip.d.vue.ts +16 -0
  55. package/dist/runtime/components/internal/FunnelTooltip.vue +26 -0
  56. package/dist/runtime/components/internal/FunnelTooltip.vue.d.ts +16 -0
  57. package/dist/runtime/components/internal/PolarCenterSync.d.ts +38 -0
  58. package/dist/runtime/components/internal/PolarCenterSync.js +27 -0
  59. package/dist/runtime/components/internal/RadarGradientDefs.d.ts +46 -0
  60. package/dist/runtime/components/internal/RadarGradientDefs.js +46 -0
  61. package/dist/runtime/components/internal/SegmentVariantDefs.d.ts +67 -0
  62. package/dist/runtime/components/internal/SegmentVariantDefs.js +51 -0
  63. package/dist/runtime/components/internal/StrokeGradientDefs.d.ts +36 -0
  64. package/dist/runtime/components/internal/StrokeGradientDefs.js +35 -0
  65. package/dist/runtime/components/internal/VariantBarShape.d.vue.ts +36 -0
  66. package/dist/runtime/components/internal/VariantBarShape.vue +53 -0
  67. package/dist/runtime/components/internal/VariantBarShape.vue.d.ts +36 -0
  68. package/dist/runtime/components/internal/tooltipContent.d.ts +13 -0
  69. package/dist/runtime/components/internal/tooltipContent.js +5 -0
  70. package/dist/runtime/types/charts.d.ts +192 -12
  71. package/dist/runtime/types/shared.d.ts +37 -0
  72. package/dist/runtime/types.d.ts +3 -0
  73. package/dist/runtime/utils/axis.d.ts +12 -1
  74. package/dist/runtime/utils/axis.js +23 -0
  75. package/dist/runtime/utils/background.d.ts +36 -0
  76. package/dist/runtime/utils/background.js +140 -0
  77. package/dist/runtime/utils/gradient.d.ts +8 -0
  78. package/dist/runtime/utils/gradient.js +3 -0
  79. package/dist/runtime/utils/theme.js +14 -0
  80. package/dist/runtime/utils/variants.d.ts +101 -0
  81. package/dist/runtime/utils/variants.js +48 -0
  82. package/package.json +6 -15
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # nuxt-charts
2
2
 
3
- Beautiful chart components for Nuxt — Area, Bar, Line, Donut, Bubble, Radar, Radial Bar, Funnel, Candlestick and Status Tracker.
3
+ Beautiful chart components for Nuxt — Area, Bar, Line, Donut, Bubble, Radar, Radial Bar, Funnel, Sankey, Candlestick and Status Tracker.
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
 
@@ -21,14 +21,15 @@ export default defineNuxtConfig({
21
21
 
22
22
  | Component | Notes |
23
23
  |---|---|
24
- | `AreaChart` | Gradients, dither fills, stacked |
25
- | `BarChart` | Grouped, stacked, horizontal, cube bars |
26
- | `LineChart` | Multi-series, curve types |
24
+ | `AreaChart` | Gradients, dither fills, textured fills, stacked |
25
+ | `BarChart` | Grouped, stacked, horizontal, cube bars, patterned fills |
26
+ | `LineChart` | Multi-series, curve types, dashed / animated strokes |
27
27
  | `DonutChart` | Center slot for labels |
28
28
  | `BubbleChart` | Scatter with size encoding |
29
29
  | `RadarChart` | New in v3 |
30
30
  | `RadialBarChart` | New in v3 |
31
31
  | `FunnelChart` | New in v3 |
32
+ | `SankeyChart` | New in v3 |
32
33
  | `CandlestickChart` | New in v3 |
33
34
  | `StatusTrackerChart` | New in v3 |
34
35
 
@@ -71,10 +72,74 @@ Each axis accepts `orientation`, `label`, `domain`, `numTicks`, `formatter`,
71
72
  the top-level `yLabel` / `yDomain` / `yAxisConfig` props. Supported on
72
73
  `LineChart`, `AreaChart` and `BarChart` (vertical orientation).
73
74
 
75
+ ## Style variants
76
+
77
+ Every treatment below is opt-in — a chart that sets none of them renders exactly
78
+ as it did before. The playground's `/variants` page shows them side by side.
79
+
80
+ ### Series fills
81
+
82
+ | Prop | Chart | Values |
83
+ |---|---|---|
84
+ | `variant` | `BarChart` | `solid` (default), `cubes`, `hatched`, `duotone`, `duotone-reverse`, `gradient`, `stripped` |
85
+ | `variant` | `AreaChart` | `gradient`, `gradient-reverse`, `solid`, `dotted`, `lines`, `hatched` |
86
+ | `variant` | `RadarChart` | `filled` (default), `lines`, `gradient` (inside to outside), `gradient-reverse` (outside to inside) |
87
+ | `variant` | `RadialBarChart` | `full` (default), `semi` |
88
+ | `variant` | `DonutChart` | `flat` (default), `gradient` |
89
+
90
+ On `AreaChart` the fill treatments layer over the v2 `gradient` fade and yield to
91
+ `dither`, which is a texture of its own.
92
+
93
+ ### Series detail
94
+
95
+ - `strokeVariant` — `solid`, `dashed`, `animated-dashed` (line + area).
96
+ - `dotVariant` — `default`, `border`, `colored-border`, `ping` (line, area,
97
+ radar), sized by `dotSize`.
98
+ - `glow` — a soft outer glow (bar, line, area, donut).
99
+ - `bufferBar` — renders the final bar as a projection: a hollow hatch with an
100
+ outline, for a period that is still accruing.
101
+ - `hoverHighlight` / `maxHighlight` — dim every bar but the hovered one, or the
102
+ tallest.
103
+ - `percent` — with `stacked`, normalise each category to 100% and label the
104
+ value axis as percentages.
105
+
106
+ ### Chart chrome
107
+
108
+ - `backgroundPattern` — one of eleven textures painted behind the plot area and
109
+ faded out at the edges: `dots`, `grid`, `cross-hatch`, `diagonal-lines`,
110
+ `plus`, `falling-triangles`, `4-pointed-star`, `tiny-checkers`,
111
+ `overlapping-circles`, `wiggle-lines`, `bubbles`.
112
+ - `legendVariant` — `square`, `circle`, `circle-outline`, `rounded-square`
113
+ (default), `rounded-square-outline`, `vertical-bar`, `horizontal-bar`.
114
+ - `tooltipVariant` (`default`, `frosted-glass`) and `tooltipRoundness`
115
+ (`sm`, `md`, `lg`, `xl`).
116
+ - `loading` — a shimmering placeholder in place of the chart, with the
117
+ silhouette matched to the chart type; `loadingLabel` names or hides its pill.
118
+ - `gridType` on `RadarChart` — `polygon` (default) or `circle`.
119
+
120
+ ```vue
121
+ <template>
122
+ <BarChart
123
+ :data="data"
124
+ :categories="categories"
125
+ :y-axis="['desktop']"
126
+ x-axis="month"
127
+ :height="320"
128
+ variant="duotone"
129
+ background-pattern="dots"
130
+ legend-variant="circle"
131
+ tooltip-variant="frosted-glass"
132
+ max-highlight
133
+ />
134
+ </template>
135
+ ```
136
+
137
+ The animated stroke and the loading shimmer both stop when the viewer's system
138
+ asks for reduced motion. Every generated SVG paint is scoped to its chart, so
139
+ several charts on one page never collide.
140
+
74
141
  ### Deferred / removed
75
142
 
76
- - **`SankeyChart`** — deferred: the published `vccs` release does not yet export
77
- a Sankey chart. Returns once `vccs` ships it.
78
143
  - **`DualChart`** — planned for v3.1 (maps onto the `vccs` `ComposedChart`).
79
144
  - **`GanttChart`, `DagreGraph`, `Maps`** — removed in v3. They were Unovis /
80
145
  d3-geo specific and have no `vccs` equivalent.
@@ -98,12 +163,17 @@ export default defineNuxtConfig({
98
163
  - Enums: `CurveType`, `LegendPosition`, `Orientation`, `DonutType`
99
164
  - Types: `AreaChartProps`, `BarChartProps`, `LineChartProps`, `BubbleChartProps`,
100
165
  `DonutChartProps`, `RadarChartProps`, `RadialBarChartProps`, `FunnelChartProps`,
166
+ `CandlestickChartProps`,
167
+ `SankeyChartProps`, `SankeyInputNode`, `SankeyInputLink`,
101
168
  `StatusTrackerChartProps`, `StatusTrackerDatum`, `BulletLegendItemInterface`,
102
169
  `AxisConfig`, `TooltipConfig`, `ValueLabel`, `ReferenceLineConfig`
170
+ - Style variant unions: `BarVariant`, `AreaFillVariant`, `StrokeVariant`,
171
+ `DotVariant`, `DitherVariant`, `BackgroundVariant`, `LegendIndicatorVariant`,
172
+ `TooltipVariant`, `TooltipRoundness`, `RadarVariant`, `RadialVariant`
103
173
 
104
174
  ## Migrating from v2
105
175
 
106
- See the [Upgrade to v3](https://nuxtcharts.com/docs/getting-started/upgrade-to-v3) guide. Specialty charts (maps, gantt, dual, sankey, dagre) are not in v3 yet — stay on `nuxt-charts@2` if you need them.
176
+ See the [Upgrade to v3](https://nuxtcharts.com/docs/getting-started/upgrade-to-v3) guide. Specialty charts (maps, gantt, dual, dagre) are not in v3 yet — stay on `nuxt-charts@2` if you need them.
107
177
 
108
178
  ## License
109
179
 
package/dist/module.json CHANGED
@@ -4,9 +4,9 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3"
6
6
  },
7
- "version": "3.0.0-beta.1",
7
+ "version": "3.0.0-beta.3",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
- "unbuild": "3.6.1"
10
+ "unbuild": "unknown"
11
11
  }
12
12
  }
package/dist/module.mjs CHANGED
@@ -9,6 +9,7 @@ const COMPONENTS = {
9
9
  RadarChart: "RadarChart",
10
10
  RadialBarChart: "RadialBarChart",
11
11
  FunnelChart: "FunnelChart",
12
+ SankeyChart: "SankeyChart",
12
13
  CandlestickChart: "CandlestickChart",
13
14
  StatusTrackerChart: "StatusTrackerChart"
14
15
  };
@@ -47,6 +48,11 @@ const resolveImports = (config, resolverUrl) => {
47
48
  "RadarChartProps",
48
49
  "RadialBarChartProps",
49
50
  "FunnelChartProps",
51
+ "FunnelLabelSizes",
52
+ "SankeyChartProps",
53
+ "SankeyInputNode",
54
+ "SankeyInputLink",
55
+ "SankeyNodeAlign",
50
56
  "CandlestickChartProps",
51
57
  "StatusTrackerChartProps",
52
58
  "StatusTrackerDatum",
@@ -59,7 +65,20 @@ const resolveImports = (config, resolverUrl) => {
59
65
  // (MarkerConfig drives line/area dot rendering; CrosshairConfig is inert
60
66
  // but kept so old templates type-check), so keep them auto-importable.
61
67
  "MarkerConfig",
62
- "CrosshairConfig"
68
+ "CrosshairConfig",
69
+ // Style variant unions, so a consumer can annotate a variant it stores or
70
+ // passes around instead of widening it to `string`.
71
+ "BarVariant",
72
+ "AreaFillVariant",
73
+ "StrokeVariant",
74
+ "DotVariant",
75
+ "DitherVariant",
76
+ "BackgroundVariant",
77
+ "LegendIndicatorVariant",
78
+ "TooltipVariant",
79
+ "TooltipRoundness",
80
+ "RadarVariant",
81
+ "RadialVariant"
63
82
  ]
64
83
  });
65
84
  };
@@ -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(--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
+ @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));color:var(--vc-tooltip-fg,oklch(.205 0 0));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--frosted-glass{backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);background:color-mix(in oklab,var(--vc-tooltip-bg,oklch(1 0 0)) 70%,transparent)}.vc-tooltip--sm{border-radius:.125rem}.vc-tooltip--md{border-radius:.375rem}.vc-tooltip--lg{border-radius:.5rem}.vc-tooltip--xl{border-radius:.75rem}.vc-tooltip__label{color:var(--vc-tooltip-fg,oklch(.205 0 0));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__dot--square{border-radius:0}.vc-legend__dot--rounded-square{border-radius:2px}.vc-legend__dot--circle{border-radius:9999px}.vc-legend__dot--vertical-bar{border-radius:2px;height:calc(var(--vc-legend-dot-size, .5rem)*1.5);width:calc(var(--vc-legend-dot-size, .5rem)*.5)}.vc-legend__dot--horizontal-bar{border-radius:2px;height:calc(var(--vc-legend-dot-size, .5rem)*.5);width:calc(var(--vc-legend-dot-size, .5rem)*1.5)}.vc-legend__dot--circle-outline,.vc-legend__dot--rounded-square-outline{box-sizing:border-box;height:calc(var(--vc-legend-dot-size, .5rem)*1.25);-webkit-mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);mask:linear-gradient(#fff 0 0) content-box,linear-gradient(#fff 0 0);-webkit-mask-composite:xor;mask-composite:exclude;padding:1.5px;width:calc(var(--vc-legend-dot-size, .5rem)*1.25)}.vc-legend__dot--circle-outline{border-radius:9999px}.vc-legend__dot--rounded-square-outline{border-radius:3px}.vc-legend__label{color:var(--vc-legend-color,oklch(.556 0 0))}.vc-skeleton{align-items:stretch;box-sizing:border-box;color:var(--vc-tick-color,oklch(.556 0 0));display:flex;overflow:hidden;padding:8% 4%;position:relative;width:100%}.vc-skeleton__bars{align-items:flex-end;display:flex;gap:2%;height:100%;width:100%}.vc-skeleton__bar{background:currentColor;border-radius:2px 2px 0 0;flex:1;opacity:.14}.vc-skeleton__wave{height:100%;opacity:.14;width:100%}.vc-skeleton__ring{aspect-ratio:1;border:1.75rem solid;border-radius:9999px;height:100%;margin:auto;opacity:.14}.vc-skeleton__shimmer{animation:vc-skeleton-sweep 1.8s linear infinite;background:linear-gradient(105deg,transparent 35%,currentColor 50%,transparent 65%);inset:0;opacity:.1;position:absolute}@keyframes vc-skeleton-sweep{0%{transform:translateX(-100%)}to{transform:translateX(100%)}}.vc-skeleton__pill{align-items:center;background:var(--vc-surface-bg,oklch(1 0 0));border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:.375rem;color:var(--vc-tick-color,oklch(.556 0 0));display:flex;font-size:var(--vc-legend-size,.75rem);gap:.375rem;height:-moz-fit-content;height:fit-content;inset:0;line-height:1.5;margin:auto;padding:.125rem .5rem;position:absolute;width:-moz-fit-content;width:fit-content}.vc-skeleton__spinner{animation:vc-skeleton-spin .7s linear infinite;border:1px solid var(--vc-tooltip-border,oklch(.922 0 0));border-radius:9999px;border-top:1px solid;height:.75rem;width:.75rem}@keyframes vc-skeleton-spin{to{transform:rotate(1turn)}}@media (prefers-reduced-motion:reduce){.vc-skeleton__shimmer,.vc-skeleton__spinner{animation:none}}.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{position:relative}.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-funnel .v-charts-label-list .v-charts-label{fill:var(--vc-funnel-value-color,oklch(.205 0 0));font-size:var(--vc-funnel-value-size,.75rem);font-variant-numeric:tabular-nums;font-weight:var(--vc-funnel-value-weight,600)}.vc-funnel-classic-shape{cursor:default}.vc-funnel-classic-shape__shadow{opacity:var(--vc-funnel-shadow-opacity,.16)}.vc-funnel-classic-shape__body{opacity:var(--vc-funnel-shape-opacity,.92);transition:opacity .15s ease}.vc-funnel-classic-shape__highlight{fill:none;stroke:hsla(0,0%,100%,.24);stroke-width:1;vector-effect:non-scaling-stroke}.vc-funnel-classic-shape:hover .vc-funnel-classic-shape__body{opacity:var(--vc-funnel-shape-hover-opacity,1)}.vc-funnel-classic-shape__name,.vc-funnel-classic-shape__value{font-family:inherit;paint-order:stroke;pointer-events:none;stroke:rgba(0,0,0,.12);stroke-linejoin:round;stroke-width:2px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vc-funnel-classic-shape__value{fill:var(--vc-funnel-inside-value-color,#fff);font-variant-numeric:tabular-nums}.vc-funnel-classic-shape__name{fill:var(--vc-funnel-inside-label-color,#fff);opacity:.78}.vc-funnel-layered-shape__divider{stroke:var(--vc-surface-bg,oklch(1 0 0))}.vc-funnel-layered-shape__badge-text,.vc-funnel-layered-shape__name,.vc-funnel-layered-shape__value{font-family:inherit;pointer-events:none;stroke:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vc-funnel-layered-shape__value{fill:var(--vc-funnel-value-color,var(--vc-axis-label-color,oklch(.205 0 0)));font-variant-numeric:tabular-nums;font-weight:var(--vc-funnel-value-weight,600)}.vc-funnel-layered-shape__badge{fill:var(--vc-funnel-badge-bg,var(--vc-surface-bg,oklch(1 0 0)));fill-opacity:var(--vc-funnel-badge-opacity,.82);stroke:var(--vc-funnel-badge-border,var(--vc-axis-line-color,oklch(.922 0 0)));stroke-opacity:.7}.vc-funnel-layered-shape__badge-text{fill:var(--vc-funnel-badge-color,var(--vc-tick-color,oklch(.556 0 0)));font-variant-numeric:tabular-nums;font-weight:var(--vc-funnel-badge-weight,600)}.vc-funnel-layered-shape__name{fill:var(--vc-funnel-label-color,var(--vc-tick-color,oklch(.556 0 0)));font-weight:var(--vc-funnel-label-weight,500)}.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:var(--vc-legend-inset,.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(--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)))}}
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-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)))}}
@@ -5,7 +5,11 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
5
5
  } ? P : {});
6
6
  expose: (exposed: {}) => void;
7
7
  attrs: any;
8
- slots: {};
8
+ slots: {
9
+ tooltip?: (props: {
10
+ values: T | undefined;
11
+ }) => unknown;
12
+ };
9
13
  emit: {};
10
14
  }>) => import("vue").VNode & {
11
15
  __ctx?: Awaited<typeof __VLS_setup>;
@@ -3,12 +3,16 @@ import { computed, useId } from "vue";
3
3
  import { Area, AreaChart as VccsAreaChart } from "vccs";
4
4
  import CartesianFrame from "./internal/CartesianFrame.vue";
5
5
  import GradientDefs from "./internal/GradientDefs";
6
+ import StrokeGradientDefs from "./internal/StrokeGradientDefs";
6
7
  import { categoriesToSeries } from "../utils/categories";
7
8
  import { curveTypeToVccs } from "../utils/curve";
8
9
  import { markerToDot, normalizeMarkerConfig, toStrokeDasharray } from "../utils/marker";
9
- import { DEFAULT_GRADIENT_STOPS, gradientId } from "../utils/gradient";
10
+ import { DEFAULT_GRADIENT_STOPS, gradientId, strokeGradientId } from "../utils/gradient";
10
11
  import DitherDefs from "./internal/DitherDefs";
12
+ import AreaVariantDefs, { areaFillId } from "./internal/AreaVariantDefs";
13
+ import ChartDot from "./internal/ChartDot";
11
14
  import { ditherId } from "../utils/dither";
15
+ import { strokeDasharrayFor, variantId } from "../utils/variants";
12
16
  const props = defineProps({
13
17
  xAxis: { type: null, required: false },
14
18
  curveType: { type: String, required: false },
@@ -19,9 +23,16 @@ const props = defineProps({
19
23
  ditherTile: { type: Number, required: false },
20
24
  ditherWash: { type: Number, required: false },
21
25
  lineWidth: { type: Number, required: false },
26
+ strokeGradient: { type: Array, required: false },
22
27
  stacked: { type: Boolean, required: false },
28
+ percent: { type: Boolean, required: false },
23
29
  lineDashArray: { type: [Array, String], required: false },
24
30
  markerConfig: { type: Object, required: false },
31
+ variant: { type: String, required: false },
32
+ strokeVariant: { type: String, required: false },
33
+ dotVariant: { type: String, required: false },
34
+ dotSize: { type: Number, required: false },
35
+ glow: { type: Boolean, required: false },
25
36
  data: { type: Array, required: true },
26
37
  height: { type: Number, required: true },
27
38
  xLabel: { type: String, required: false },
@@ -58,7 +69,13 @@ const props = defineProps({
58
69
  xExplicitTicks: { type: Array, required: false },
59
70
  yExplicitTicks: { type: Array, required: false },
60
71
  crosshairConfig: { type: Object, required: false },
61
- theme: { type: Object, required: false }
72
+ theme: { type: Object, required: false },
73
+ backgroundPattern: { type: String, required: false },
74
+ legendVariant: { type: String, required: false },
75
+ tooltipVariant: { type: String, required: false },
76
+ tooltipRoundness: { type: String, required: false },
77
+ loading: { type: Boolean, required: false },
78
+ loadingLabel: { type: String, required: false }
62
79
  });
63
80
  const gradientScope = useId();
64
81
  const markers = computed(() => normalizeMarkerConfig(props.markerConfig));
@@ -70,16 +87,21 @@ const series = computed(
70
87
  );
71
88
  const curve = computed(() => curveTypeToVccs(props.curveType));
72
89
  const stackId = computed(() => props.stacked ? "stack" : void 0);
90
+ const chartContainerProps = computed(
91
+ () => props.stacked && props.percent ? { stackOffset: "expand" } : {}
92
+ );
73
93
  const fillOpacity = computed(() => props.hideArea ? 0 : 0.6);
74
- const dashArray = computed(() => toStrokeDasharray(props.lineDashArray));
75
94
  const useDither = computed(
76
95
  () => !props.hideArea && props.dither !== void 0 && props.dither !== false
77
96
  );
78
97
  const ditherVariant = computed(
79
98
  () => typeof props.dither === "string" ? props.dither : "bayer"
80
99
  );
100
+ const useFillVariant = computed(
101
+ () => !props.hideArea && props.variant !== void 0 && !useDither.value
102
+ );
81
103
  const useGradientFill = computed(
82
- () => !props.hideArea && props.gradient !== false && !useDither.value
104
+ () => !props.hideArea && props.gradient !== false && !useDither.value && !useFillVariant.value
83
105
  );
84
106
  const useDitherFade = computed(
85
107
  () => useDither.value && props.gradient !== false
@@ -96,16 +118,45 @@ const ditherWashStops = computed(() => {
96
118
  stopOpacity: stop.stopOpacity * scale
97
119
  }));
98
120
  });
121
+ const paintedSeries = computed(
122
+ () => series.value.map((s) => ({ dataKey: s.dataKey, color: s.color }))
123
+ );
99
124
  function fillFor(dataKey, color) {
100
125
  if (useDither.value) return `url(#${ditherId(dataKey, gradientScope)})`;
126
+ if (useFillVariant.value) return `url(#${areaFillId(props.variant, dataKey, gradientScope)})`;
101
127
  if (useGradientFill.value) return `url(#${gradientId(dataKey, gradientScope)})`;
102
128
  return color;
103
129
  }
130
+ function strokeFor(dataKey, color) {
131
+ return props.strokeGradient?.length ? `url(#${strokeGradientId(dataKey, gradientScope)})` : color;
132
+ }
133
+ function glowFor(dataKey) {
134
+ return props.glow ? `url(#${variantId("glow", dataKey, gradientScope)})` : void 0;
135
+ }
136
+ const dashArray = computed(
137
+ () => toStrokeDasharray(props.lineDashArray) ?? strokeDasharrayFor(props.strokeVariant)
138
+ );
139
+ const frameClass = computed(
140
+ () => props.strokeVariant === "animated-dashed" ? "vc-dash-animated" : void 0
141
+ );
142
+ const showDots = computed(() => props.dotVariant !== void 0);
104
143
  const xAxisKey = computed(() => props.xAxis !== void 0 ? String(props.xAxis) : void 0);
144
+ defineSlots();
105
145
  </script>
106
146
 
107
147
  <template>
108
- <CartesianFrame :container="VccsAreaChart" :x-axis-key="xAxisKey" v-bind="props">
148
+ <CartesianFrame
149
+ :container="VccsAreaChart"
150
+ :x-axis-key="xAxisKey"
151
+ :container-props="chartContainerProps"
152
+ :percent-axis="stacked === true && percent === true"
153
+ :frame-class="frameClass"
154
+ skeleton-shape="wave"
155
+ v-bind="props"
156
+ >
157
+ <template v-if="$slots.tooltip" #tooltip="scope">
158
+ <slot name="tooltip" v-bind="scope" />
159
+ </template>
109
160
  <!--
110
161
  GradientDefs builds SVG nodes with `h()` so they land in the SVG namespace
111
162
  inside the chart surface. Do not wrap this in vccs `<Customized>`: that
@@ -118,6 +169,12 @@ const xAxisKey = computed(() => props.xAxis !== void 0 ? String(props.xAxis) : v
118
169
  :stops="gradientStops"
119
170
  :scope="gradientScope"
120
171
  />
172
+ <StrokeGradientDefs
173
+ v-if="strokeGradient?.length"
174
+ :series="paintedSeries"
175
+ :stops="strokeGradient"
176
+ :scope="gradientScope"
177
+ />
121
178
  <!-- Same namespace/`Customized` constraints as GradientDefs above. -->
122
179
  <DitherDefs
123
180
  v-if="useDither"
@@ -128,6 +185,13 @@ const xAxisKey = computed(() => props.xAxis !== void 0 ? String(props.xAxis) : v
128
185
  :fade-stops="ditherWashStops"
129
186
  :height="height"
130
187
  />
188
+ <AreaVariantDefs
189
+ v-if="useFillVariant || glow"
190
+ :series="paintedSeries"
191
+ :variant="useFillVariant ? variant : void 0"
192
+ :scope="gradientScope"
193
+ :glow="glow === true"
194
+ />
131
195
  <Area
132
196
  v-for="s in series"
133
197
  :key="s.dataKey"
@@ -136,14 +200,25 @@ const xAxisKey = computed(() => props.xAxis !== void 0 ? String(props.xAxis) : v
136
200
  :y-axis-id="s.yAxisId"
137
201
  :type="curve"
138
202
  :stack-id="stackId"
139
- :stroke="s.color"
203
+ :stroke="strokeFor(s.dataKey, s.color)"
140
204
  :fill="fillFor(s.dataKey, s.color)"
141
- :fill-opacity="useGradientFill || useDither ? 1 : fillOpacity"
205
+ :fill-opacity="useGradientFill || useDither || useFillVariant ? 1 : fillOpacity"
142
206
  :stroke-width="lineWidth ?? 2"
143
207
  :stroke-dasharray="dashArray"
144
- :dot="s.dot"
208
+ :filter="glowFor(s.dataKey)"
209
+ :dot="showDots || s.dot"
145
210
  :hide="s.hidden"
146
211
  :is-animation-active="duration !== void 0 && duration !== 0"
147
- />
212
+ >
213
+ <template v-if="showDots" #dot="dotProps">
214
+ <ChartDot
215
+ :cx="dotProps.cx"
216
+ :cy="dotProps.cy"
217
+ :color="s.color"
218
+ :variant="dotVariant"
219
+ :size="dotSize ?? 3"
220
+ />
221
+ </template>
222
+ </Area>
148
223
  </CartesianFrame>
149
224
  </template>
@@ -5,7 +5,11 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
5
5
  } ? P : {});
6
6
  expose: (exposed: {}) => void;
7
7
  attrs: any;
8
- slots: {};
8
+ slots: {
9
+ tooltip?: (props: {
10
+ values: T | undefined;
11
+ }) => unknown;
12
+ };
9
13
  emit: {};
10
14
  }>) => import("vue").VNode & {
11
15
  __ctx?: Awaited<typeof __VLS_setup>;
@@ -5,7 +5,11 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
5
5
  } ? P : {});
6
6
  expose: (exposed: {}) => void;
7
7
  attrs: any;
8
- slots: {};
8
+ slots: {
9
+ tooltip?: (props: {
10
+ values: T | undefined;
11
+ }) => unknown;
12
+ };
9
13
  emit: {};
10
14
  }>) => import("vue").VNode & {
11
15
  __ctx?: Awaited<typeof __VLS_setup>;
@@ -1,8 +1,10 @@
1
1
  <script setup>
2
- import { computed } from "vue";
2
+ import { computed, ref, useId } from "vue";
3
3
  import { Bar, BarChart as VccsBarChart, LabelList, Rectangle } from "vccs";
4
4
  import CartesianFrame from "./internal/CartesianFrame.vue";
5
5
  import CubeBarShape from "./internal/CubeBarShape.vue";
6
+ import VariantBarShape from "./internal/VariantBarShape.vue";
7
+ import BarVariantDefs from "./internal/BarVariantDefs";
6
8
  import {
7
9
  categoriesToSeries,
8
10
  PRIMARY_Y_AXIS_ID
@@ -13,10 +15,12 @@ import {
13
15
  DEFAULT_CUBE_RADIUS,
14
16
  DEFAULT_CUBE_SIZE
15
17
  } from "../utils/cubes";
18
+ import { PATTERNED_BAR_VARIANTS, variantId } from "../utils/variants";
16
19
  const props = defineProps({
17
20
  yAxis: { type: Array, required: true },
18
21
  xAxis: { type: null, required: false },
19
22
  stacked: { type: Boolean, required: false },
23
+ percent: { type: Boolean, required: false },
20
24
  orientation: { type: String, required: false },
21
25
  radius: { type: Number, required: false },
22
26
  barGap: { type: [Number, String], required: false },
@@ -31,6 +35,10 @@ const props = defineProps({
31
35
  cubeMinSize: { type: Number, required: false },
32
36
  cubeMinOpacity: { type: Number, required: false },
33
37
  cubeEmptyColor: { type: String, required: false, default: DEFAULT_CUBE_EMPTY_COLOR },
38
+ glow: { type: Boolean, required: false },
39
+ bufferBar: { type: Boolean, required: false },
40
+ hoverHighlight: { type: Boolean, required: false },
41
+ maxHighlight: { type: Boolean, required: false },
34
42
  stackAndGrouped: { type: Boolean, required: false },
35
43
  stackedGroupedSpacing: { type: Number, required: false },
36
44
  data: { type: Array, required: true },
@@ -69,9 +77,39 @@ const props = defineProps({
69
77
  xExplicitTicks: { type: Array, required: false },
70
78
  yExplicitTicks: { type: Array, required: false },
71
79
  crosshairConfig: { type: Object, required: false },
72
- theme: { type: Object, required: false }
80
+ theme: { type: Object, required: false },
81
+ backgroundPattern: { type: String, required: false },
82
+ legendVariant: { type: String, required: false },
83
+ tooltipVariant: { type: String, required: false },
84
+ tooltipRoundness: { type: String, required: false },
85
+ loading: { type: Boolean, required: false },
86
+ loadingLabel: { type: String, required: false }
73
87
  });
88
+ const variantScope = useId();
74
89
  const isCubes = computed(() => props.variant === "cubes");
90
+ const isPatterned = computed(() => PATTERNED_BAR_VARIANTS.includes(props.variant));
91
+ const isStripped = computed(() => props.variant === "stripped");
92
+ const usesVariantShape = computed(
93
+ () => isStripped.value || props.bufferBar === true || props.glow === true
94
+ );
95
+ const hoveredIndex = ref(null);
96
+ const lastIndex = computed(() => props.data.length - 1);
97
+ const maxIndex = computed(() => {
98
+ if (!props.maxHighlight) return null;
99
+ let best = -1;
100
+ let bestTotal = Number.NEGATIVE_INFINITY;
101
+ props.data.forEach((row, index) => {
102
+ const total = series.value.reduce((sum, s) => {
103
+ const value = row[s.dataKey];
104
+ return sum + (typeof value === "number" ? value : 0);
105
+ }, 0);
106
+ if (total > bestTotal) {
107
+ bestTotal = total;
108
+ best = index;
109
+ }
110
+ });
111
+ return best >= 0 ? best : null;
112
+ });
75
113
  const valueAccessor = computed(() => {
76
114
  const fn = props.valueLabel?.label;
77
115
  if (!fn) return void 0;
@@ -98,6 +136,40 @@ const series = computed(
98
136
  };
99
137
  })
100
138
  );
139
+ const paintedSeries = computed(
140
+ () => series.value.filter((s) => typeof s.color === "string").map((s) => ({ dataKey: s.dataKey, color: s.color }))
141
+ );
142
+ const legendColors = computed(
143
+ () => Object.fromEntries(
144
+ series.value.filter((s) => s.color).map((s) => [s.name, s.color])
145
+ )
146
+ );
147
+ function fillFor(dataKey, color) {
148
+ if (!isPatterned.value || color === void 0) return color;
149
+ return `url(#${variantId(props.variant, dataKey, variantScope)})`;
150
+ }
151
+ function bufferFillFor(dataKey) {
152
+ return `url(#${variantId("buffer", dataKey, variantScope)})`;
153
+ }
154
+ function glowFor(dataKey) {
155
+ return props.glow ? `url(#${variantId("glow", dataKey, variantScope)})` : void 0;
156
+ }
157
+ const DIMMED_OPACITY = 0.3;
158
+ function opacityFor(index) {
159
+ if (props.hoverHighlight && hoveredIndex.value !== null) {
160
+ return index === hoveredIndex.value ? 1 : DIMMED_OPACITY;
161
+ }
162
+ if (maxIndex.value !== null) {
163
+ return index === maxIndex.value ? 1 : DIMMED_OPACITY;
164
+ }
165
+ return 1;
166
+ }
167
+ function onBarEnter(index) {
168
+ if (props.hoverHighlight) hoveredIndex.value = index ?? null;
169
+ }
170
+ function onBarLeave() {
171
+ if (props.hoverHighlight) hoveredIndex.value = null;
172
+ }
101
173
  const stackIdFor = (yAxisId) => props.stacked ? `stack-${yAxisId}` : void 0;
102
174
  const xAxisKey = computed(() => props.xAxis !== void 0 ? String(props.xAxis) : void 0);
103
175
  const chartContainerProps = computed(() => {
@@ -105,18 +177,23 @@ const chartContainerProps = computed(() => {
105
177
  const barCategoryGap = props.barCategoryGap ?? props.groupPadding;
106
178
  return {
107
179
  ...barGap !== void 0 ? { barGap } : {},
108
- ...barCategoryGap !== void 0 ? { barCategoryGap } : {}
180
+ ...barCategoryGap !== void 0 ? { barCategoryGap } : {},
181
+ // Normalising only means something once the series are summed into a stack.
182
+ ...props.stacked && props.percent ? { stackOffset: "expand" } : {}
109
183
  };
110
184
  });
111
185
  function barRadius(index) {
112
186
  const r = props.radius ?? 2;
187
+ const horizontal = props.orientation === "horizontal";
188
+ if (isStripped.value && !props.stacked) {
189
+ return horizontal ? [0, r, r, 0] : [r, r, 0, 0];
190
+ }
113
191
  if (!props.stacked) return r;
114
192
  const isLast = index === series.value.length - 1;
115
- if (props.orientation === "horizontal") {
116
- return isLast ? [0, r, r, 0] : 0;
117
- }
193
+ if (horizontal) return isLast ? [0, r, r, 0] : 0;
118
194
  return isLast ? [r, r, 0, 0] : 0;
119
195
  }
196
+ defineSlots();
120
197
  </script>
121
198
 
122
199
  <template>
@@ -124,8 +201,25 @@ function barRadius(index) {
124
201
  :container="VccsBarChart"
125
202
  :x-axis-key="xAxisKey"
126
203
  :container-props="chartContainerProps"
204
+ :percent-axis="stacked === true && percent === true"
205
+ :legend-colors="legendColors"
127
206
  v-bind="props"
128
207
  >
208
+ <!--
209
+ Same namespace/`Customized` constraints as GradientDefs: these are built
210
+ with `h()` so they land in the SVG namespace and `url(#…)` resolves.
211
+ -->
212
+ <BarVariantDefs
213
+ v-if="isPatterned || glow || bufferBar"
214
+ :series="paintedSeries"
215
+ :variant="variant"
216
+ :scope="variantScope"
217
+ :glow="glow === true"
218
+ :buffer="bufferBar === true"
219
+ />
220
+ <template v-if="$slots.tooltip" #tooltip="scope">
221
+ <slot name="tooltip" v-bind="scope" />
222
+ </template>
129
223
  <Bar
130
224
  v-for="(s, i) in series"
131
225
  :key="s.dataKey"
@@ -133,7 +227,7 @@ function barRadius(index) {
133
227
  :name="s.name"
134
228
  :y-axis-id="s.yAxisId"
135
229
  :stack-id="stackIdFor(s.yAxisId)"
136
- :fill="s.color"
230
+ :fill="fillFor(s.dataKey, s.color)"
137
231
  :radius="isCubes ? 0 : barRadius(i)"
138
232
  :hide="s.hidden"
139
233
  :is-animation-active="duration !== void 0 && duration !== 0"
@@ -159,7 +253,30 @@ function barRadius(index) {
159
253
  :empty-color="cubeEmptyColor"
160
254
  :include-empty="!stacked || i === 0"
161
255
  />
162
- <Rectangle v-else v-bind="shapeProps" />
256
+ <VariantBarShape
257
+ v-else-if="usesVariantShape"
258
+ :x="shapeProps.x"
259
+ :y="shapeProps.y"
260
+ :width="shapeProps.width"
261
+ :height="shapeProps.height"
262
+ :radius="barRadius(i)"
263
+ :fill="shapeProps.fill ?? s.color"
264
+ :color="s.color"
265
+ :capped="isStripped"
266
+ :is-buffer="bufferBar === true && shapeProps.index === lastIndex"
267
+ :buffer-fill="bufferFillFor(s.dataKey)"
268
+ :filter="glowFor(s.dataKey)"
269
+ :opacity="opacityFor(shapeProps.index)"
270
+ @mouseenter="onBarEnter(shapeProps.index)"
271
+ @mouseleave="onBarLeave"
272
+ />
273
+ <Rectangle
274
+ v-else
275
+ v-bind="shapeProps"
276
+ :opacity="opacityFor(shapeProps.index)"
277
+ @mouseenter="onBarEnter(shapeProps.index)"
278
+ @mouseleave="onBarLeave"
279
+ />
163
280
  </template>
164
281
  <LabelList
165
282
  v-if="valueLabel && !isCubes"
@@ -5,7 +5,11 @@ declare const __VLS_export: <T>(__VLS_props: NonNullable<Awaited<typeof __VLS_se
5
5
  } ? P : {});
6
6
  expose: (exposed: {}) => void;
7
7
  attrs: any;
8
- slots: {};
8
+ slots: {
9
+ tooltip?: (props: {
10
+ values: T | undefined;
11
+ }) => unknown;
12
+ };
9
13
  emit: {};
10
14
  }>) => import("vue").VNode & {
11
15
  __ctx?: Awaited<typeof __VLS_setup>;