@classic-homes/charts-core 0.1.1

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.
@@ -0,0 +1,277 @@
1
+ import { colors, semanticColors, fontFamily, borderRadius } from '@classic-homes/theme-tokens';
2
+
3
+ // src/theme/generator.ts
4
+ function generateLightTheme() {
5
+ const chartColors = [
6
+ colors.teal[500],
7
+ // chart.1
8
+ colors.navy[700],
9
+ // chart.2
10
+ colors.plum[700],
11
+ // chart.3
12
+ colors.forest[500],
13
+ // chart.4
14
+ colors.sky[600],
15
+ // chart.5
16
+ // Extended palette for >5 series
17
+ colors.stone[600],
18
+ colors.lavender[700],
19
+ colors.deepTeal[600],
20
+ colors.sage[600],
21
+ colors.red[600]
22
+ ];
23
+ return {
24
+ color: chartColors,
25
+ backgroundColor: "transparent",
26
+ textStyle: {
27
+ fontFamily: fontFamily.sans.join(", "),
28
+ color: semanticColors.light.foreground
29
+ },
30
+ title: {
31
+ textStyle: {
32
+ color: semanticColors.light.foreground,
33
+ fontWeight: 600,
34
+ fontSize: 16
35
+ },
36
+ subtextStyle: {
37
+ color: semanticColors.light.mutedForeground,
38
+ fontSize: 14
39
+ }
40
+ },
41
+ legend: {
42
+ textStyle: {
43
+ color: semanticColors.light.foreground
44
+ }
45
+ },
46
+ tooltip: {
47
+ backgroundColor: semanticColors.light.popover,
48
+ borderColor: semanticColors.light.border,
49
+ borderWidth: 1,
50
+ borderRadius: parseInt(borderRadius.md) || 6,
51
+ textStyle: {
52
+ color: semanticColors.light.popoverForeground
53
+ },
54
+ extraCssText: "box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);"
55
+ },
56
+ xAxis: {
57
+ axisLine: {
58
+ show: true,
59
+ lineStyle: {
60
+ color: colors.gray[300]
61
+ }
62
+ },
63
+ axisTick: {
64
+ show: true,
65
+ lineStyle: {
66
+ color: colors.gray[300]
67
+ }
68
+ },
69
+ axisLabel: {
70
+ color: semanticColors.light.mutedForeground
71
+ },
72
+ splitLine: {
73
+ show: true,
74
+ lineStyle: {
75
+ color: colors.gray[200],
76
+ type: "dashed"
77
+ }
78
+ }
79
+ },
80
+ yAxis: {
81
+ axisLine: {
82
+ show: false,
83
+ lineStyle: {
84
+ color: colors.gray[300]
85
+ }
86
+ },
87
+ axisTick: {
88
+ show: false,
89
+ lineStyle: {
90
+ color: colors.gray[300]
91
+ }
92
+ },
93
+ axisLabel: {
94
+ color: semanticColors.light.mutedForeground
95
+ },
96
+ splitLine: {
97
+ show: true,
98
+ lineStyle: {
99
+ color: colors.gray[200],
100
+ type: "dashed"
101
+ }
102
+ }
103
+ },
104
+ line: {
105
+ smooth: false,
106
+ symbol: "circle",
107
+ symbolSize: 4
108
+ },
109
+ bar: {
110
+ barMaxWidth: 50,
111
+ itemStyle: {
112
+ borderRadius: [4, 4, 0, 0]
113
+ }
114
+ },
115
+ pie: {
116
+ itemStyle: {
117
+ borderColor: semanticColors.light.card,
118
+ borderWidth: 2
119
+ }
120
+ },
121
+ scatter: {
122
+ symbolSize: 10
123
+ },
124
+ gauge: {
125
+ axisLine: {
126
+ lineStyle: {
127
+ color: [
128
+ [0.3, colors.teal[400]],
129
+ [0.7, colors.teal[500]],
130
+ [1, colors.teal[600]]
131
+ ]
132
+ }
133
+ }
134
+ }
135
+ };
136
+ }
137
+ function generateDarkTheme() {
138
+ const chartColors = [
139
+ colors.teal[400],
140
+ // chart.1
141
+ colors.navy[400],
142
+ // chart.2
143
+ colors.plum[400],
144
+ // chart.3
145
+ colors.forest[400],
146
+ // chart.4
147
+ colors.sky[400],
148
+ // chart.5
149
+ // Extended palette for >5 series
150
+ colors.stone[400],
151
+ colors.lavender[400],
152
+ colors.deepTeal[400],
153
+ colors.sage[400],
154
+ colors.red[400]
155
+ ];
156
+ return {
157
+ color: chartColors,
158
+ backgroundColor: "transparent",
159
+ textStyle: {
160
+ fontFamily: fontFamily.sans.join(", "),
161
+ color: semanticColors.dark.foreground
162
+ },
163
+ title: {
164
+ textStyle: {
165
+ color: semanticColors.dark.foreground,
166
+ fontWeight: 600,
167
+ fontSize: 16
168
+ },
169
+ subtextStyle: {
170
+ color: semanticColors.dark.mutedForeground,
171
+ fontSize: 14
172
+ }
173
+ },
174
+ legend: {
175
+ textStyle: {
176
+ color: semanticColors.dark.foreground
177
+ }
178
+ },
179
+ tooltip: {
180
+ backgroundColor: semanticColors.dark.popover,
181
+ borderColor: semanticColors.dark.border,
182
+ borderWidth: 1,
183
+ borderRadius: parseInt(borderRadius.md) || 6,
184
+ textStyle: {
185
+ color: semanticColors.dark.popoverForeground
186
+ },
187
+ extraCssText: "box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.3);"
188
+ },
189
+ xAxis: {
190
+ axisLine: {
191
+ show: true,
192
+ lineStyle: {
193
+ color: colors.gray[600]
194
+ }
195
+ },
196
+ axisTick: {
197
+ show: true,
198
+ lineStyle: {
199
+ color: colors.gray[600]
200
+ }
201
+ },
202
+ axisLabel: {
203
+ color: semanticColors.dark.mutedForeground
204
+ },
205
+ splitLine: {
206
+ show: true,
207
+ lineStyle: {
208
+ color: colors.gray[700],
209
+ type: "dashed"
210
+ }
211
+ }
212
+ },
213
+ yAxis: {
214
+ axisLine: {
215
+ show: false,
216
+ lineStyle: {
217
+ color: colors.gray[600]
218
+ }
219
+ },
220
+ axisTick: {
221
+ show: false,
222
+ lineStyle: {
223
+ color: colors.gray[600]
224
+ }
225
+ },
226
+ axisLabel: {
227
+ color: semanticColors.dark.mutedForeground
228
+ },
229
+ splitLine: {
230
+ show: true,
231
+ lineStyle: {
232
+ color: colors.gray[700],
233
+ type: "dashed"
234
+ }
235
+ }
236
+ },
237
+ line: {
238
+ smooth: false,
239
+ symbol: "circle",
240
+ symbolSize: 4
241
+ },
242
+ bar: {
243
+ barMaxWidth: 50,
244
+ itemStyle: {
245
+ borderRadius: [4, 4, 0, 0]
246
+ }
247
+ },
248
+ pie: {
249
+ itemStyle: {
250
+ borderColor: semanticColors.dark.card,
251
+ borderWidth: 2
252
+ }
253
+ },
254
+ scatter: {
255
+ symbolSize: 10
256
+ },
257
+ gauge: {
258
+ axisLine: {
259
+ lineStyle: {
260
+ color: [
261
+ [0.3, colors.teal[500]],
262
+ [0.7, colors.teal[400]],
263
+ [1, colors.teal[300]]
264
+ ]
265
+ }
266
+ }
267
+ }
268
+ };
269
+ }
270
+ var lightTheme = generateLightTheme();
271
+ var darkTheme = generateDarkTheme();
272
+
273
+ // src/theme/index.ts
274
+ var THEME_LIGHT = "classic-light";
275
+ var THEME_DARK = "classic-dark";
276
+
277
+ export { THEME_DARK, THEME_LIGHT, darkTheme, generateDarkTheme, generateLightTheme, lightTheme };
package/dist/index.cjs ADDED
@@ -0,0 +1,425 @@
1
+ 'use strict';
2
+
3
+ var themeTokens = require('@classic-homes/theme-tokens');
4
+
5
+ // src/theme/generator.ts
6
+ function generateLightTheme() {
7
+ const chartColors = [
8
+ themeTokens.colors.teal[500],
9
+ // chart.1
10
+ themeTokens.colors.navy[700],
11
+ // chart.2
12
+ themeTokens.colors.plum[700],
13
+ // chart.3
14
+ themeTokens.colors.forest[500],
15
+ // chart.4
16
+ themeTokens.colors.sky[600],
17
+ // chart.5
18
+ // Extended palette for >5 series
19
+ themeTokens.colors.stone[600],
20
+ themeTokens.colors.lavender[700],
21
+ themeTokens.colors.deepTeal[600],
22
+ themeTokens.colors.sage[600],
23
+ themeTokens.colors.red[600]
24
+ ];
25
+ return {
26
+ color: chartColors,
27
+ backgroundColor: "transparent",
28
+ textStyle: {
29
+ fontFamily: themeTokens.fontFamily.sans.join(", "),
30
+ color: themeTokens.semanticColors.light.foreground
31
+ },
32
+ title: {
33
+ textStyle: {
34
+ color: themeTokens.semanticColors.light.foreground,
35
+ fontWeight: 600,
36
+ fontSize: 16
37
+ },
38
+ subtextStyle: {
39
+ color: themeTokens.semanticColors.light.mutedForeground,
40
+ fontSize: 14
41
+ }
42
+ },
43
+ legend: {
44
+ textStyle: {
45
+ color: themeTokens.semanticColors.light.foreground
46
+ }
47
+ },
48
+ tooltip: {
49
+ backgroundColor: themeTokens.semanticColors.light.popover,
50
+ borderColor: themeTokens.semanticColors.light.border,
51
+ borderWidth: 1,
52
+ borderRadius: parseInt(themeTokens.borderRadius.md) || 6,
53
+ textStyle: {
54
+ color: themeTokens.semanticColors.light.popoverForeground
55
+ },
56
+ extraCssText: "box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);"
57
+ },
58
+ xAxis: {
59
+ axisLine: {
60
+ show: true,
61
+ lineStyle: {
62
+ color: themeTokens.colors.gray[300]
63
+ }
64
+ },
65
+ axisTick: {
66
+ show: true,
67
+ lineStyle: {
68
+ color: themeTokens.colors.gray[300]
69
+ }
70
+ },
71
+ axisLabel: {
72
+ color: themeTokens.semanticColors.light.mutedForeground
73
+ },
74
+ splitLine: {
75
+ show: true,
76
+ lineStyle: {
77
+ color: themeTokens.colors.gray[200],
78
+ type: "dashed"
79
+ }
80
+ }
81
+ },
82
+ yAxis: {
83
+ axisLine: {
84
+ show: false,
85
+ lineStyle: {
86
+ color: themeTokens.colors.gray[300]
87
+ }
88
+ },
89
+ axisTick: {
90
+ show: false,
91
+ lineStyle: {
92
+ color: themeTokens.colors.gray[300]
93
+ }
94
+ },
95
+ axisLabel: {
96
+ color: themeTokens.semanticColors.light.mutedForeground
97
+ },
98
+ splitLine: {
99
+ show: true,
100
+ lineStyle: {
101
+ color: themeTokens.colors.gray[200],
102
+ type: "dashed"
103
+ }
104
+ }
105
+ },
106
+ line: {
107
+ smooth: false,
108
+ symbol: "circle",
109
+ symbolSize: 4
110
+ },
111
+ bar: {
112
+ barMaxWidth: 50,
113
+ itemStyle: {
114
+ borderRadius: [4, 4, 0, 0]
115
+ }
116
+ },
117
+ pie: {
118
+ itemStyle: {
119
+ borderColor: themeTokens.semanticColors.light.card,
120
+ borderWidth: 2
121
+ }
122
+ },
123
+ scatter: {
124
+ symbolSize: 10
125
+ },
126
+ gauge: {
127
+ axisLine: {
128
+ lineStyle: {
129
+ color: [
130
+ [0.3, themeTokens.colors.teal[400]],
131
+ [0.7, themeTokens.colors.teal[500]],
132
+ [1, themeTokens.colors.teal[600]]
133
+ ]
134
+ }
135
+ }
136
+ }
137
+ };
138
+ }
139
+ function generateDarkTheme() {
140
+ const chartColors = [
141
+ themeTokens.colors.teal[400],
142
+ // chart.1
143
+ themeTokens.colors.navy[400],
144
+ // chart.2
145
+ themeTokens.colors.plum[400],
146
+ // chart.3
147
+ themeTokens.colors.forest[400],
148
+ // chart.4
149
+ themeTokens.colors.sky[400],
150
+ // chart.5
151
+ // Extended palette for >5 series
152
+ themeTokens.colors.stone[400],
153
+ themeTokens.colors.lavender[400],
154
+ themeTokens.colors.deepTeal[400],
155
+ themeTokens.colors.sage[400],
156
+ themeTokens.colors.red[400]
157
+ ];
158
+ return {
159
+ color: chartColors,
160
+ backgroundColor: "transparent",
161
+ textStyle: {
162
+ fontFamily: themeTokens.fontFamily.sans.join(", "),
163
+ color: themeTokens.semanticColors.dark.foreground
164
+ },
165
+ title: {
166
+ textStyle: {
167
+ color: themeTokens.semanticColors.dark.foreground,
168
+ fontWeight: 600,
169
+ fontSize: 16
170
+ },
171
+ subtextStyle: {
172
+ color: themeTokens.semanticColors.dark.mutedForeground,
173
+ fontSize: 14
174
+ }
175
+ },
176
+ legend: {
177
+ textStyle: {
178
+ color: themeTokens.semanticColors.dark.foreground
179
+ }
180
+ },
181
+ tooltip: {
182
+ backgroundColor: themeTokens.semanticColors.dark.popover,
183
+ borderColor: themeTokens.semanticColors.dark.border,
184
+ borderWidth: 1,
185
+ borderRadius: parseInt(themeTokens.borderRadius.md) || 6,
186
+ textStyle: {
187
+ color: themeTokens.semanticColors.dark.popoverForeground
188
+ },
189
+ extraCssText: "box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.3);"
190
+ },
191
+ xAxis: {
192
+ axisLine: {
193
+ show: true,
194
+ lineStyle: {
195
+ color: themeTokens.colors.gray[600]
196
+ }
197
+ },
198
+ axisTick: {
199
+ show: true,
200
+ lineStyle: {
201
+ color: themeTokens.colors.gray[600]
202
+ }
203
+ },
204
+ axisLabel: {
205
+ color: themeTokens.semanticColors.dark.mutedForeground
206
+ },
207
+ splitLine: {
208
+ show: true,
209
+ lineStyle: {
210
+ color: themeTokens.colors.gray[700],
211
+ type: "dashed"
212
+ }
213
+ }
214
+ },
215
+ yAxis: {
216
+ axisLine: {
217
+ show: false,
218
+ lineStyle: {
219
+ color: themeTokens.colors.gray[600]
220
+ }
221
+ },
222
+ axisTick: {
223
+ show: false,
224
+ lineStyle: {
225
+ color: themeTokens.colors.gray[600]
226
+ }
227
+ },
228
+ axisLabel: {
229
+ color: themeTokens.semanticColors.dark.mutedForeground
230
+ },
231
+ splitLine: {
232
+ show: true,
233
+ lineStyle: {
234
+ color: themeTokens.colors.gray[700],
235
+ type: "dashed"
236
+ }
237
+ }
238
+ },
239
+ line: {
240
+ smooth: false,
241
+ symbol: "circle",
242
+ symbolSize: 4
243
+ },
244
+ bar: {
245
+ barMaxWidth: 50,
246
+ itemStyle: {
247
+ borderRadius: [4, 4, 0, 0]
248
+ }
249
+ },
250
+ pie: {
251
+ itemStyle: {
252
+ borderColor: themeTokens.semanticColors.dark.card,
253
+ borderWidth: 2
254
+ }
255
+ },
256
+ scatter: {
257
+ symbolSize: 10
258
+ },
259
+ gauge: {
260
+ axisLine: {
261
+ lineStyle: {
262
+ color: [
263
+ [0.3, themeTokens.colors.teal[500]],
264
+ [0.7, themeTokens.colors.teal[400]],
265
+ [1, themeTokens.colors.teal[300]]
266
+ ]
267
+ }
268
+ }
269
+ }
270
+ };
271
+ }
272
+ var lightTheme = generateLightTheme();
273
+ var darkTheme = generateDarkTheme();
274
+
275
+ // src/theme/index.ts
276
+ var THEME_LIGHT = "classic-light";
277
+ var THEME_DARK = "classic-dark";
278
+
279
+ // src/utils/format.ts
280
+ function formatNumber(value, options) {
281
+ return new Intl.NumberFormat("en-US", options).format(value);
282
+ }
283
+ function formatCurrency(value, currency = "USD", locale = "en-US") {
284
+ return new Intl.NumberFormat(locale, {
285
+ style: "currency",
286
+ currency
287
+ }).format(value);
288
+ }
289
+ function formatPercent(value, decimals = 1, locale = "en-US") {
290
+ return new Intl.NumberFormat(locale, {
291
+ style: "percent",
292
+ minimumFractionDigits: decimals,
293
+ maximumFractionDigits: decimals
294
+ }).format(value);
295
+ }
296
+ function formatDate(date, options, locale = "en-US") {
297
+ const d = typeof date === "string" ? new Date(date) : date;
298
+ return new Intl.DateTimeFormat(locale, options).format(d);
299
+ }
300
+ function abbreviateNumber(value, decimals = 1) {
301
+ const suffixes = ["", "K", "M", "B", "T"];
302
+ let suffixIndex = 0;
303
+ let abbreviated = value;
304
+ while (Math.abs(abbreviated) >= 1e3 && suffixIndex < suffixes.length - 1) {
305
+ abbreviated /= 1e3;
306
+ suffixIndex++;
307
+ }
308
+ return abbreviated.toFixed(decimals).replace(/\.0+$/, "") + suffixes[suffixIndex];
309
+ }
310
+ function createTooltipFormatter(options = {}) {
311
+ const { showSeriesName = true, valueFormatter = formatNumber } = options;
312
+ return (params) => {
313
+ if (!Array.isArray(params)) {
314
+ params = [
315
+ params
316
+ ];
317
+ }
318
+ return params.map((param) => {
319
+ const value = Array.isArray(param.value) ? param.value[1] : param.value;
320
+ const formatted = valueFormatter(value);
321
+ const percent = param.percent ? ` (${param.percent.toFixed(1)}%)` : "";
322
+ if (showSeriesName && param.seriesName) {
323
+ return `${param.seriesName}: ${formatted}${percent}`;
324
+ }
325
+ return `${param.name}: ${formatted}${percent}`;
326
+ }).join("<br/>");
327
+ };
328
+ }
329
+
330
+ // src/utils/accessibility.ts
331
+ function generateLineChartDescription(title, data) {
332
+ const seriesCount = data.series.length;
333
+ const categoryCount = data.categories.length;
334
+ const seriesNames = data.series.map((s) => s.name).join(", ");
335
+ let description = `${title}. Line chart with ${categoryCount} data points`;
336
+ if (seriesCount > 1) {
337
+ description += ` across ${seriesCount} series: ${seriesNames}`;
338
+ }
339
+ data.series.forEach((series) => {
340
+ if (series.data.length >= 2) {
341
+ const first = series.data[0];
342
+ const last = series.data[series.data.length - 1];
343
+ const trend = last > first ? "increasing" : last < first ? "decreasing" : "stable";
344
+ description += `. ${series.name} shows ${trend} trend from ${first} to ${last}`;
345
+ }
346
+ });
347
+ return description;
348
+ }
349
+ function generateBarChartDescription(title, data) {
350
+ const categoryCount = data.categories.length;
351
+ const seriesCount = data.series.length;
352
+ let description = `${title}. Bar chart with ${categoryCount} categories`;
353
+ if (seriesCount > 1) {
354
+ description += ` and ${seriesCount} series`;
355
+ }
356
+ let maxValue = -Infinity;
357
+ let maxCategory = "";
358
+ let minValue = Infinity;
359
+ let minCategory = "";
360
+ data.series.forEach((series) => {
361
+ series.data.forEach((value, index) => {
362
+ if (value > maxValue) {
363
+ maxValue = value;
364
+ maxCategory = data.categories[index];
365
+ }
366
+ if (value < minValue) {
367
+ minValue = value;
368
+ minCategory = data.categories[index];
369
+ }
370
+ });
371
+ });
372
+ description += `. Highest value is ${maxValue} for ${maxCategory}. Lowest value is ${minValue} for ${minCategory}`;
373
+ return description;
374
+ }
375
+ function generatePieChartDescription(title, data, isDonut = false) {
376
+ const total = data.reduce((sum, slice) => sum + slice.value, 0);
377
+ const chartType = isDonut ? "Donut" : "Pie";
378
+ let description = `${title}. ${chartType} chart with ${data.length} segments`;
379
+ const sorted = [...data].sort((a, b) => b.value - a.value);
380
+ const topSegments = sorted.slice(0, 3);
381
+ const percentages = topSegments.map((segment) => {
382
+ const percent = (segment.value / total * 100).toFixed(1);
383
+ return `${segment.name} at ${percent}%`;
384
+ });
385
+ description += `. Top segments: ${percentages.join(", ")}`;
386
+ return description;
387
+ }
388
+ function generateScatterChartDescription(title, data) {
389
+ const totalPoints = data.series.reduce((sum, s) => sum + s.data.length, 0);
390
+ const seriesCount = data.series.length;
391
+ let description = `${title}. Scatter plot with ${totalPoints} data points`;
392
+ if (seriesCount > 1) {
393
+ const seriesNames = data.series.map((s) => s.name).join(", ");
394
+ description += ` across ${seriesCount} series: ${seriesNames}`;
395
+ }
396
+ return description;
397
+ }
398
+ function generateDataTable(headers, rows) {
399
+ const headerRow = headers.map((h) => `<th scope="col">${h}</th>`).join("");
400
+ const bodyRows = rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join("")}</tr>`).join("");
401
+ return `
402
+ <table class="sr-only">
403
+ <thead><tr>${headerRow}</tr></thead>
404
+ <tbody>${bodyRows}</tbody>
405
+ </table>
406
+ `;
407
+ }
408
+
409
+ exports.THEME_DARK = THEME_DARK;
410
+ exports.THEME_LIGHT = THEME_LIGHT;
411
+ exports.abbreviateNumber = abbreviateNumber;
412
+ exports.createTooltipFormatter = createTooltipFormatter;
413
+ exports.darkTheme = darkTheme;
414
+ exports.formatCurrency = formatCurrency;
415
+ exports.formatDate = formatDate;
416
+ exports.formatNumber = formatNumber;
417
+ exports.formatPercent = formatPercent;
418
+ exports.generateBarChartDescription = generateBarChartDescription;
419
+ exports.generateDarkTheme = generateDarkTheme;
420
+ exports.generateDataTable = generateDataTable;
421
+ exports.generateLightTheme = generateLightTheme;
422
+ exports.generateLineChartDescription = generateLineChartDescription;
423
+ exports.generatePieChartDescription = generatePieChartDescription;
424
+ exports.generateScatterChartDescription = generateScatterChartDescription;
425
+ exports.lightTheme = lightTheme;