vccs 1.0.0-beta.2 → 1.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
@@ -76,6 +76,17 @@ export default defineConfig({
76
76
  })
77
77
  ```
78
78
 
79
+ ## Use vccs with an AI agent
80
+
81
+ ```sh
82
+ npx skills add unovue/vue-charts # add -g to install for every project
83
+ ```
84
+
85
+ Then just ask for the chart — you run nothing yourself. Claude loads the skill when the request
86
+ matches it, or you can invoke it explicitly with `/vccs-usage`:
87
+
88
+ > add a card with weekly user retention by signup month
89
+
79
90
  ## Typed rows
80
91
 
81
92
  `defineChartComponents` binds your row type to the components you pick. A wrong `data-key` is
@@ -55,8 +55,10 @@ var BrushView = /* @__PURE__ */ defineComponent({
55
55
  const startIndex = computed(() => view.range?.startIndex ?? 0);
56
56
  const endIndex = computed(() => view.range?.endIndex ?? Math.max(0, (chartData.value?.length ?? 0) - 1));
57
57
  const calculatedY = computed(() => (y.value ?? 0) + (props.dy ?? 0));
58
+ let proposed;
58
59
  function onChange(nextState) {
59
60
  if (sameRange(nextState, view.range)) return;
61
+ proposed = nextState;
60
62
  emit("update:range", nextState);
61
63
  emit("change", nextState);
62
64
  nextTick(restoreControlledPositions);
@@ -68,6 +70,8 @@ var BrushView = /* @__PURE__ */ defineComponent({
68
70
  });
69
71
  function restoreControlledPositions() {
70
72
  if (!view.controlled()) return;
73
+ if (sameRange(view.range, proposed ?? null)) return;
74
+ proposed = void 0;
71
75
  brushState.value.startX = brushState.value.scale?.(startIndex.value);
72
76
  brushState.value.endX = brushState.value.scale?.(endIndex.value);
73
77
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vccs",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.2",
4
+ "version": "1.0.0",
5
5
  "description": "Composable charting components for Vue 3 — an unofficial port of Recharts",
6
6
  "author": "rick-hup",
7
7
  "license": "MIT",
@@ -51,11 +51,15 @@
51
51
  ]
52
52
  }
53
53
  },
54
+ "bin": {
55
+ "vccs-usage": "./usage/vccs-usage.mjs"
56
+ },
54
57
  "files": [
55
58
  "./LICENSE",
56
59
  "./README.md",
57
60
  "./dist/**/*.d.ts",
58
- "./dist/**/*.mjs"
61
+ "./dist/**/*.mjs",
62
+ "./usage"
59
63
  ],
60
64
  "peerDependencies": {
61
65
  "@nuxt/kit": "^4.0.0",
@@ -0,0 +1,235 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "guides": [
4
+ {
5
+ "id": "installation",
6
+ "title": "Installation and registration",
7
+ "description": "Install vccs in Vite or Nuxt 4, use explicit imports, auto-imports, or the Nuxt module.",
8
+ "category": "core",
9
+ "path": "guides/core/installation.md",
10
+ "components": [],
11
+ "useCases": ["Set up a new Vue or Nuxt chart", "Configure VccsResolver or vccs/nuxt"],
12
+ "keywords": ["install", "setup", "vite", "nuxt", "resolver", "auto-import", "安装", "自动导入"]
13
+ },
14
+ {
15
+ "id": "vue-api",
16
+ "title": "Vue API rules",
17
+ "description": "Use slots, events, Vue models, responsive sizing, data keys, and CSS theme variables correctly.",
18
+ "category": "core",
19
+ "path": "guides/core/vue-api.md",
20
+ "components": ["Tooltip", "Brush", "Legend"],
21
+ "useCases": ["Customize chart content", "Control active state", "Fix a Recharts-to-Vue API mismatch"],
22
+ "keywords": ["slots", "events", "v-model", "active-index", "brush", "tooltip", "responsive", "theme", "插槽", "事件", "主题"]
23
+ },
24
+ {
25
+ "id": "typed-rows",
26
+ "title": "Typed chart rows",
27
+ "description": "Make data-key and tooltip payload types follow the application's row type.",
28
+ "category": "core",
29
+ "path": "guides/core/typed-rows.md",
30
+ "components": [],
31
+ "useCases": ["Reject wrong data keys at compile time", "Type tooltip payloads"],
32
+ "keywords": ["typescript", "types", "generic", "defineChartComponents", "row", "类型", "类型安全"]
33
+ },
34
+ {
35
+ "id": "ssr-testing",
36
+ "title": "SSR and deterministic testing",
37
+ "description": "Render charts on the server and disable motion for stable SSR and geometry assertions.",
38
+ "category": "core",
39
+ "path": "guides/core/ssr-testing.md",
40
+ "components": [],
41
+ "useCases": ["Render charts in Nuxt SSR", "Write deterministic chart tests"],
42
+ "keywords": ["ssr", "server", "hydration", "test", "animation", "服务端渲染", "测试"]
43
+ },
44
+ {
45
+ "id": "area-chart",
46
+ "title": "AreaChart",
47
+ "description": "Show a filled trend, accumulated magnitude, or stacked total over an ordered axis.",
48
+ "category": "chart",
49
+ "path": "guides/charts/area-chart.md",
50
+ "components": ["AreaChart", "Area"],
51
+ "useCases": ["Show a filled trend over time", "Show stacked totals over an ordered axis", "用面积展示趋势或堆积总量"],
52
+ "keywords": ["area", "filled line", "stacked area", "trend", "time series", "面积图", "趋势", "堆积"]
53
+ },
54
+ {
55
+ "id": "bar-chart",
56
+ "title": "BarChart",
57
+ "description": "Compare categories with vertical or horizontal bars, including stacked and negative values.",
58
+ "category": "chart",
59
+ "path": "guides/charts/bar-chart.md",
60
+ "components": ["BarChart", "Bar"],
61
+ "useCases": ["Compare values across categories", "Rank categories or show a stacked composition", "用柱状图或条形图比较分类"],
62
+ "keywords": ["bar", "column", "comparison", "ranking", "stacked", "柱状图", "条形图", "对比", "排名"]
63
+ },
64
+ {
65
+ "id": "line-chart",
66
+ "title": "LineChart",
67
+ "description": "Show one or more trends over an ordered numeric or categorical axis.",
68
+ "category": "chart",
69
+ "path": "guides/charts/line-chart.md",
70
+ "components": ["LineChart", "Line"],
71
+ "useCases": ["Show a time series", "Compare trends across series", "用折线展示趋势"],
72
+ "keywords": ["line", "trend", "time series", "spark alternative", "折线图", "趋势", "时间序列"]
73
+ },
74
+ {
75
+ "id": "scatter-chart",
76
+ "title": "ScatterChart",
77
+ "description": "Show relationships between numeric variables with points or bubbles.",
78
+ "category": "chart",
79
+ "path": "guides/charts/scatter-chart.md",
80
+ "components": ["ScatterChart", "Scatter", "ZAxis"],
81
+ "useCases": ["Show correlation or distribution", "Encode a third numeric value as bubble size", "用散点展示相关性或分布"],
82
+ "keywords": ["scatter", "correlation", "distribution", "bubble", "散点图", "气泡图", "相关性"]
83
+ },
84
+ {
85
+ "id": "composed-chart",
86
+ "title": "ComposedChart",
87
+ "description": "Combine Bar, Line, Area, and Scatter series on shared Cartesian axes.",
88
+ "category": "chart",
89
+ "path": "guides/charts/composed-chart.md",
90
+ "components": ["ComposedChart", "Bar", "Line", "Area", "Scatter"],
91
+ "useCases": ["Compare actual bars with a target line", "Mix series types on one chart", "在同一坐标系混合柱状和折线"],
92
+ "keywords": ["composed", "mixed", "combo", "bar and line", "组合图", "混合图"]
93
+ },
94
+ {
95
+ "id": "funnel-chart",
96
+ "title": "FunnelChart",
97
+ "description": "Show values and drop-off across ordered conversion stages.",
98
+ "category": "chart",
99
+ "path": "guides/charts/funnel-chart.md",
100
+ "components": ["FunnelChart", "Funnel"],
101
+ "useCases": ["Show conversion across stages", "Expose drop-off in a process", "展示阶段转化和流失"],
102
+ "keywords": ["funnel", "conversion", "drop-off", "stages", "漏斗图", "转化率"]
103
+ },
104
+ {
105
+ "id": "pie-chart",
106
+ "title": "PieChart",
107
+ "description": "Show a small number of part-to-whole proportions as a pie or donut.",
108
+ "category": "chart",
109
+ "path": "guides/charts/pie-chart.md",
110
+ "components": ["PieChart", "Pie", "Cell"],
111
+ "useCases": ["Show proportions of a total", "Build a donut chart", "展示少量分类的占比"],
112
+ "keywords": ["pie", "donut", "proportion", "part-to-whole", "饼图", "环形图", "占比"]
113
+ },
114
+ {
115
+ "id": "radar-chart",
116
+ "title": "RadarChart",
117
+ "description": "Compare multivariate profiles across a shared set of dimensions.",
118
+ "category": "chart",
119
+ "path": "guides/charts/radar-chart.md",
120
+ "components": ["RadarChart", "Radar", "PolarAngleAxis", "PolarGrid"],
121
+ "useCases": ["Compare scores across dimensions", "Show a multivariate profile", "比较多维评分"],
122
+ "keywords": ["radar", "spider", "multivariate", "profile", "雷达图", "多维"]
123
+ },
124
+ {
125
+ "id": "radial-bar-chart",
126
+ "title": "RadialBarChart",
127
+ "description": "Show progress or category values as concentric or stacked radial bars.",
128
+ "category": "chart",
129
+ "path": "guides/charts/radial-bar-chart.md",
130
+ "components": ["RadialBarChart", "RadialBar"],
131
+ "useCases": ["Show progress toward a goal", "Compare values on polar tracks", "展示环形进度或径向分类值"],
132
+ "keywords": ["radial bar", "progress", "gauge", "polar bar", "径向条形图", "进度", "仪表盘"]
133
+ },
134
+ {
135
+ "id": "bar-list",
136
+ "title": "BarList",
137
+ "description": "Render a lightweight plain-HTML ranked list with inline value bars.",
138
+ "category": "chart",
139
+ "path": "guides/charts/bar-list.md",
140
+ "components": ["BarList"],
141
+ "useCases": ["Build a compact ranking list", "Show labeled values without SVG axes", "用 HTML 列表展示排行"],
142
+ "keywords": ["bar list", "ranking", "html", "leaderboard", "条形列表", "排行榜"]
143
+ },
144
+ {
145
+ "id": "sparkline",
146
+ "title": "Sparkline",
147
+ "description": "Place a tiny inline trend in a table, KPI tile, or dense dashboard row.",
148
+ "category": "chart",
149
+ "path": "guides/charts/sparkline.md",
150
+ "components": ["Sparkline"],
151
+ "useCases": ["Show a compact trend without axes", "Add a trend to a KPI or table row", "在指标卡或表格中展示迷你趋势"],
152
+ "keywords": ["sparkline", "mini line", "kpi", "inline trend", "火花线", "迷你趋势"]
153
+ },
154
+ {
155
+ "id": "tracker",
156
+ "title": "Tracker",
157
+ "description": "Show a compact sequence of discrete activity or status cells.",
158
+ "category": "chart",
159
+ "path": "guides/charts/tracker.md",
160
+ "components": ["Tracker"],
161
+ "useCases": ["Show service or activity status over a sequence", "Render compact status cells", "展示一组状态或活动点"],
162
+ "keywords": ["tracker", "status", "activity", "cells", "状态", "活动点", "追踪"]
163
+ },
164
+ {
165
+ "id": "heatmap",
166
+ "title": "Heatmap",
167
+ "description": "Show magnitude or density across two categorical dimensions.",
168
+ "category": "chart",
169
+ "path": "guides/charts/heatmap.md",
170
+ "components": ["Heatmap"],
171
+ "useCases": ["Show a matrix of values", "Find concentration across two categories", "展示两个分类维度的密度或强度"],
172
+ "keywords": ["heatmap", "matrix", "density", "intensity", "热力图", "矩阵", "密度"]
173
+ },
174
+ {
175
+ "id": "calendar-heatmap",
176
+ "title": "CalendarHeatmap",
177
+ "description": "Show daily activity or intensity on a calendar.",
178
+ "category": "chart",
179
+ "path": "guides/charts/calendar-heatmap.md",
180
+ "components": ["CalendarHeatmap"],
181
+ "useCases": ["Show daily activity over weeks or months", "Build a contribution calendar", "展示每日活动或贡献日历"],
182
+ "keywords": ["calendar heatmap", "daily", "contribution", "activity calendar", "日历热力图", "贡献图"]
183
+ },
184
+ {
185
+ "id": "cohort-chart",
186
+ "title": "CohortChart",
187
+ "description": "Show retention or another metric by cohort and elapsed period.",
188
+ "category": "chart",
189
+ "path": "guides/charts/cohort-chart.md",
190
+ "components": ["CohortChart"],
191
+ "useCases": ["Analyze retention by signup cohort", "Compare behavior across elapsed periods", "分析分群留存"],
192
+ "keywords": ["cohort", "retention", "signup", "period", "队列图", "留存", "分群"]
193
+ },
194
+ {
195
+ "id": "journey-sankey",
196
+ "title": "JourneySankey",
197
+ "description": "Show how entities move through ordered journey steps and where they drop off.",
198
+ "category": "chart",
199
+ "path": "guides/charts/journey-sankey.md",
200
+ "components": ["JourneySankey"],
201
+ "useCases": ["Visualize a user journey", "Compare paths through ordered steps", "展示用户旅程和路径流失"],
202
+ "keywords": ["journey", "path", "conversion", "sankey", "用户旅程", "路径", "桑基图"]
203
+ },
204
+ {
205
+ "id": "sankey",
206
+ "title": "Sankey",
207
+ "description": "Show weighted flows between arbitrary source and target nodes.",
208
+ "category": "chart",
209
+ "path": "guides/charts/sankey.md",
210
+ "components": ["Sankey"],
211
+ "useCases": ["Show transfers or flows between nodes", "Visualize weighted relationships in a network", "展示节点之间的加权流动"],
212
+ "keywords": ["sankey", "flow", "nodes", "links", "桑基图", "流量", "流向"]
213
+ },
214
+ {
215
+ "id": "treemap",
216
+ "title": "Treemap",
217
+ "description": "Show hierarchical part-to-whole values as nested rectangles.",
218
+ "category": "chart",
219
+ "path": "guides/charts/treemap.md",
220
+ "components": ["Treemap"],
221
+ "useCases": ["Show hierarchy and magnitude together", "Compare branches of a whole", "用嵌套矩形展示层级和占比"],
222
+ "keywords": ["treemap", "hierarchy", "nested rectangles", "矩形树图", "层级", "占比"]
223
+ },
224
+ {
225
+ "id": "sunburst-chart",
226
+ "title": "SunburstChart",
227
+ "description": "Show hierarchical part-to-whole values as concentric radial rings.",
228
+ "category": "chart",
229
+ "path": "guides/charts/sunburst-chart.md",
230
+ "components": ["SunburstChart"],
231
+ "useCases": ["Show hierarchy as radial rings", "Explore nested proportions", "用同心环展示层级和占比"],
232
+ "keywords": ["sunburst", "hierarchy", "radial rings", "旭日图", "层级", "环形"]
233
+ }
234
+ ]
235
+ }
@@ -0,0 +1,56 @@
1
+ # AreaChart
2
+
3
+ Use `AreaChart` for a filled trend or a stacked total over an ordered axis. Use `LineChart` when the fill would overemphasize magnitude; use `BarChart` for discrete category comparisons.
4
+
5
+ ## Data shape
6
+
7
+ - `data` is an array of flat rows on the chart root.
8
+ - `XAxis data-key` names the ordered category or time value.
9
+ - Each `Area data-key` selects one numeric series from the same row.
10
+ - Use one `Area` per series and set `name` when the legend or tooltip needs a different label.
11
+
12
+ ## Minimal example
13
+
14
+ ```vue
15
+ <script setup lang="ts">
16
+ import { Area, AreaChart, CartesianGrid, Tooltip, XAxis, YAxis } from 'vccs'
17
+
18
+ const data = [
19
+ { month: 'Jan', visitors: 186 },
20
+ { month: 'Feb', visitors: 305 },
21
+ { month: 'Mar', visitors: 237 },
22
+ ]
23
+ </script>
24
+
25
+ <template>
26
+ <AreaChart
27
+ :data="data"
28
+ :height="300"
29
+ >
30
+ <CartesianGrid />
31
+ <XAxis data-key="month" />
32
+ <YAxis />
33
+ <Tooltip :cursor="false" />
34
+ <Area
35
+ type="monotone"
36
+ data-key="visitors"
37
+ stroke="#f97316"
38
+ fill="#f97316"
39
+ :fill-opacity="0.3"
40
+ />
41
+ </AreaChart>
42
+ </template>
43
+ ```
44
+
45
+ Animation is enabled by default; retrieve `ssr-testing` before taking screenshots or asserting exact geometry.
46
+
47
+ ## Chart-specific rules
48
+
49
+ - Keep all series on the shared root `data` array; do not put a separate array on each `Area`.
50
+ - Give areas the same `stack-id` to stack them; omit it when the areas should remain independent.
51
+ - Use `connect-nulls` only when a gap should be bridged; otherwise missing values stay visible as gaps.
52
+ - Retrieve `composed-chart` when bars, lines, or scatter points must share the same axes.
53
+
54
+ ## Related guides
55
+
56
+ `installation`, `vue-api`, `typed-rows`, `ssr-testing`, `line-chart`, `bar-chart`, `composed-chart`.
@@ -0,0 +1,60 @@
1
+ # BarChart
2
+
3
+ Use `BarChart` to compare or rank values across categories. Use `BarList` for a compact HTML ranking without axes; use `LineChart` when the main point is a continuous trend.
4
+
5
+ ## Data shape
6
+
7
+ - `data` is an array of flat rows on the chart root.
8
+ - `XAxis data-key` names the category for vertical bars.
9
+ - Each `Bar data-key` selects one numeric series from the same row.
10
+ - Use one `Bar` per series and set `name` when the legend or tooltip needs a different label.
11
+
12
+ ## Minimal example
13
+
14
+ ```vue
15
+ <script setup lang="ts">
16
+ import { Bar, BarChart, CartesianGrid, Legend, Tooltip, XAxis, YAxis } from 'vccs'
17
+
18
+ const data = [
19
+ { month: 'Jan', desktop: 186, mobile: 80 },
20
+ { month: 'Feb', desktop: 305, mobile: 120 },
21
+ { month: 'Mar', desktop: 237, mobile: 160 },
22
+ ]
23
+ </script>
24
+
25
+ <template>
26
+ <BarChart
27
+ :data="data"
28
+ :height="300"
29
+ >
30
+ <CartesianGrid />
31
+ <XAxis data-key="month" />
32
+ <YAxis />
33
+ <Tooltip :cursor="false" />
34
+ <Legend />
35
+ <Bar
36
+ data-key="desktop"
37
+ name="Desktop"
38
+ fill="#f97316"
39
+ />
40
+ <Bar
41
+ data-key="mobile"
42
+ name="Mobile"
43
+ fill="#14b8a6"
44
+ />
45
+ </BarChart>
46
+ </template>
47
+ ```
48
+
49
+ Animation is enabled by default; retrieve `ssr-testing` before taking screenshots or asserting exact geometry.
50
+
51
+ ## Chart-specific rules
52
+
53
+ - Keep grouped or stacked series on the shared root `data` array, with one `Bar` per numeric field.
54
+ - Give bars the same `stack-id` to stack them; for stacks containing negative values, set `stack-offset="sign"` on `BarChart`.
55
+ - Use `layout="vertical"` for horizontal bars, with a numeric `XAxis` and a categorical `YAxis` carrying the category `data-key`.
56
+ - Use `bar-size` for a fixed bar width or `max-bar-size` for an upper limit.
57
+
58
+ ## Related guides
59
+
60
+ `installation`, `vue-api`, `typed-rows`, `ssr-testing`, `bar-list`, `line-chart`, `composed-chart`.
@@ -0,0 +1,46 @@
1
+ # BarList
2
+
3
+ Use `BarList` for a compact ranked list with labels and inline magnitude bars. It is plain HTML, not an SVG chart; use `BarChart` when you need axes, stacked values, or multiple series.
4
+
5
+ ## Data shape
6
+
7
+ - `data` contains one row per item.
8
+ - `name-key` selects the label and row identity; it defaults to `name`.
9
+ - `data-key` selects the numeric value; it defaults to `value`.
10
+ - Add `href-key` when a row field should turn its label into a link.
11
+ - Bar length is the value divided by the largest value, not the share of the total.
12
+
13
+ ## Minimal example
14
+
15
+ ```vue
16
+ <script setup lang="ts">
17
+ import { BarList } from 'vccs'
18
+
19
+ const data = [
20
+ { name: '/', value: 1240, url: '/' },
21
+ { name: '/pricing', value: 820, url: '/pricing' },
22
+ { name: '/docs', value: 610, url: '/docs' },
23
+ { name: '/blog', value: 330, url: '/blog' },
24
+ ]
25
+ </script>
26
+
27
+ <template>
28
+ <BarList
29
+ :data="data"
30
+ href-key="url"
31
+ color="#f97316"
32
+ />
33
+ </template>
34
+ ```
35
+
36
+ ## Chart-specific rules
37
+
38
+ - Rows sort by descending value by default; use `sort="none"` to preserve input order.
39
+ - Keep `name-key` stable across updates so a row keeps its identity when its rank changes.
40
+ - Use `value-formatter` for display text and `locale` for the default number format.
41
+ - Customize labels or values with the `#name` and `#value` slots, not function-valued render props.
42
+ - Adjust the HTML rows with `row-height` and `gap`; do not add Cartesian axes or series children.
43
+
44
+ ## Related guides
45
+
46
+ `installation`, `vue-api`, `typed-rows`, `ssr-testing`, `bar-chart`, `tracker`.
@@ -0,0 +1,55 @@
1
+ # CalendarHeatmap
2
+
3
+ Use `CalendarHeatmap` for daily activity arranged into weekdays and weeks, such as contributions or practice minutes. Use `Heatmap` for arbitrary categories and `Sparkline` when only the overall trend matters.
4
+
5
+ ## Data shape
6
+
7
+ - `data` is a flat array of daily rows.
8
+ - `date-key` defaults to `date` and accepts a valid `YYYY-MM-DD` string or a `Date` object.
9
+ - `data-key` defaults to `value` and selects the numeric intensity.
10
+ - Rows for the same day are summed; invalid dates are skipped.
11
+ - Days without a source row are empty cells; do not pad the range with zero rows.
12
+ - Set `start` and `end` for an explicit range. Otherwise the range ends on the latest data date and covers about 52 weeks.
13
+
14
+ ## Minimal example
15
+
16
+ ```vue
17
+ <script setup lang="ts">
18
+ import { CalendarHeatmap, Tooltip } from 'vccs'
19
+
20
+ const data = [
21
+ { date: '2025-01-02', value: 3 },
22
+ { date: '2025-01-04', value: 5 },
23
+ { date: '2025-01-07', value: 2 },
24
+ { date: '2025-01-10', value: 8 },
25
+ { date: '2025-01-13', value: 4 },
26
+ { date: '2025-01-16', value: 1 },
27
+ { date: '2025-01-20', value: 9 },
28
+ { date: '2025-01-24', value: 6 },
29
+ ]
30
+ </script>
31
+
32
+ <template>
33
+ <CalendarHeatmap
34
+ :data="data"
35
+ start="2025-01-01"
36
+ end="2025-01-31"
37
+ :week-start="1"
38
+ color="#14b8a6"
39
+ >
40
+ <Tooltip :cursor="false" />
41
+ </CalendarHeatmap>
42
+ </template>
43
+ ```
44
+
45
+ ## Chart-specific rules
46
+
47
+ - Prefer `YYYY-MM-DD` strings for unambiguous calendar days; a `Date` uses its local calendar date.
48
+ - Explicit `start` and `end` keep a fixed example or server-rendered range independent of the current day.
49
+ - `colors` is the complete scale from empty to full, so include the empty color as its first entry.
50
+ - Use `:week-start="0"` for Sunday or `:week-start="1"` for Monday; `max` controls the value at full intensity.
51
+ - Tooltip and cell-event payloads are `CalendarDay` objects with `date`, `value`, `level`, and source `rows`.
52
+
53
+ ## Related guides
54
+
55
+ `installation`, `vue-api`, `typed-rows`, `ssr-testing`, `heatmap`, `tracker`, `sparkline`.
@@ -0,0 +1,47 @@
1
+ # CohortChart
2
+
3
+ Use `CohortChart` for retention or another count by acquisition cohort and elapsed period. Use `Heatmap` for an arbitrary matrix and `LineChart` for one overall trend without cohort breakdown.
4
+
5
+ ## Data shape
6
+
7
+ - `data` contains one row per cohort, ordered oldest first.
8
+ - `cohort-key` selects the cohort name and defaults to `cohort`.
9
+ - `values-key` selects a numeric array and defaults to `values`.
10
+ - `values[0]` is the initial cohort size; `values[n]` is the count still active at period `n`.
11
+ - Supply raw counts even in the default percentage mode. Omit periods a cohort has not reached instead of padding them with zero.
12
+
13
+ ## Minimal example
14
+
15
+ ```vue
16
+ <script setup lang="ts">
17
+ import { CohortChart, Tooltip } from 'vccs'
18
+
19
+ const data = [
20
+ { cohort: 'Jan', values: [1200, 610, 480, 410] },
21
+ { cohort: 'Feb', values: [940, 470, 370] },
22
+ { cohort: 'Mar', values: [1180, 650] },
23
+ { cohort: 'Apr', values: [860] },
24
+ ]
25
+ </script>
26
+
27
+ <template>
28
+ <CohortChart
29
+ :data="data"
30
+ color="#f97316"
31
+ >
32
+ <Tooltip :cursor="false" />
33
+ </CohortChart>
34
+ </template>
35
+ ```
36
+
37
+ ## Chart-specific rules
38
+
39
+ - The default `mode="percent"` calculates each cell from the raw count divided by `values[0]`; use `mode="count"` for raw counts.
40
+ - Keep `values[0]` positive. A non-positive or invalid initial size cannot produce percentage cells.
41
+ - Different cohorts may have different array lengths; shorter arrays leave unelapsed periods blank and form the expected triangle.
42
+ - Use `period-formatter` for column headings. `value-formatter` receives the calculated percentage or the raw count according to `mode`.
43
+ - Tooltip and cell-event payloads include the cohort source `row`, contributing `rows`, and elapsed `period`.
44
+
45
+ ## Related guides
46
+
47
+ `installation`, `vue-api`, `typed-rows`, `ssr-testing`, `heatmap`, `line-chart`.
@@ -0,0 +1,70 @@
1
+ # ComposedChart
2
+
3
+ Use `ComposedChart` when different series need different marks on shared Cartesian axes. Use a specific chart root when every series has the same mark; do not combine incomparable units on one value axis.
4
+
5
+ ## Data shape
6
+
7
+ - `data` is an array of flat rows on the chart root.
8
+ - `XAxis data-key` names the shared ordered category or time value.
9
+ - Each `Area`, `Bar`, or `Line` uses `data-key` to select a numeric field from the same row.
10
+ - Set `name` on each series when the legend or tooltip needs a label different from the key.
11
+
12
+ ## Minimal example
13
+
14
+ ```vue
15
+ <script setup lang="ts">
16
+ import { Area, Bar, CartesianGrid, ComposedChart, Legend, Line, Tooltip, XAxis, YAxis } from 'vccs'
17
+
18
+ const data = [
19
+ { month: 'Jan', desktop: 186, mobile: 80, total: 266 },
20
+ { month: 'Feb', desktop: 305, mobile: 120, total: 425 },
21
+ { month: 'Mar', desktop: 237, mobile: 160, total: 397 },
22
+ ]
23
+ </script>
24
+
25
+ <template>
26
+ <ComposedChart
27
+ :data="data"
28
+ :height="300"
29
+ >
30
+ <CartesianGrid />
31
+ <XAxis data-key="month" />
32
+ <YAxis />
33
+ <Tooltip :cursor="false" />
34
+ <Legend />
35
+ <Area
36
+ type="monotone"
37
+ data-key="total"
38
+ name="Total"
39
+ stroke="#f97316"
40
+ fill="#f97316"
41
+ :fill-opacity="0.3"
42
+ />
43
+ <Bar
44
+ data-key="desktop"
45
+ name="Desktop"
46
+ fill="#14b8a6"
47
+ :bar-size="20"
48
+ />
49
+ <Line
50
+ type="monotone"
51
+ data-key="mobile"
52
+ name="Mobile"
53
+ stroke="#f59e0b"
54
+ />
55
+ </ComposedChart>
56
+ </template>
57
+ ```
58
+
59
+ Animation is enabled by default; retrieve `ssr-testing` before taking screenshots or asserting exact geometry.
60
+
61
+ ## Chart-specific rules
62
+
63
+ - Combine `Area`, `Bar`, `Line`, and `Scatter` children; retrieve their chart guides for series-specific props.
64
+ - Keep `Area`, `Bar`, and `Line` series on the shared root `data` array; retrieve `scatter-chart` for scatter data and numeric axes.
65
+ - Series paint in template order, so a later series can cover an earlier one.
66
+ - The tooltip follows the category axis; add `Legend` when multiple series need visible labels.
67
+
68
+ ## Related guides
69
+
70
+ `installation`, `vue-api`, `typed-rows`, `ssr-testing`, `area-chart`, `bar-chart`, `line-chart`, `scatter-chart`.