fix(chart): align ECharts components with theme tokens and load the full ECharts ESM bundle

This commit is contained in:
2026-04-04 11:25:19 +00:00
parent ff32470d8a
commit 3505c390d8
8 changed files with 69 additions and 42 deletions

View File

@@ -1,5 +1,12 @@
# Changelog # Changelog
## 2026-04-04 - 3.55.4 - fix(chart)
align ECharts components with theme tokens and load the full ECharts ESM bundle
- replace hardcoded chart colors with centralized themeDefaults-based ECharts theme helpers across bar, donut, gauge, and radar components
- improve donut label styling to use theme-aware text colors
- switch CDN loading to the pre-built echarts.esm.min.js bundle so all chart types and components are available
## 2026-04-04 - 3.55.3 - fix(theme) ## 2026-04-04 - 3.55.3 - fix(theme)
align component styles with shared theme CSS variables align component styles with shared theme CSS variables

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@design.estate/dees-catalog', name: '@design.estate/dees-catalog',
version: '3.55.3', version: '3.55.4',
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.' description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
} }

View File

@@ -8,7 +8,7 @@ import { DeesChartEchartsBase } from '../dees-chart-echarts-base.js';
import { demoFunc } from './demo.js'; import { demoFunc } from './demo.js';
import { barStyles } from './styles.js'; import { barStyles } from './styles.js';
import { renderChartBar } from './template.js'; import { renderChartBar } from './template.js';
import { getEchartsSeriesColors } from '../dees-chart-echarts-theme.js'; import { getEchartsSeriesColors, getThemeColors } from '../dees-chart-echarts-theme.js';
export interface IBarSeriesItem { export interface IBarSeriesItem {
name: string; name: string;
@@ -66,25 +66,25 @@ export class DeesChartBar extends DeesChartEchartsBase {
} }
protected buildOption(): Record<string, any> { protected buildOption(): Record<string, any> {
const colors = getThemeColors(this.goBright);
const seriesColors = getEchartsSeriesColors(this.goBright); const seriesColors = getEchartsSeriesColors(this.goBright);
const isDark = !this.goBright;
const formatter = this.valueFormatter; const formatter = this.valueFormatter;
const categoryAxis: Record<string, any> = { const categoryAxis: Record<string, any> = {
type: 'category', type: 'category',
data: this.categories, data: this.categories,
axisLine: { lineStyle: { color: isDark ? 'hsl(0 0% 20%)' : 'hsl(0 0% 85%)' } }, axisLine: { lineStyle: { color: colors.borderStrong } },
axisLabel: { color: isDark ? 'hsl(0 0% 63.9%)' : 'hsl(0 0% 40%)' }, axisLabel: { color: colors.textMuted },
}; };
const valueAxis: Record<string, any> = { const valueAxis: Record<string, any> = {
type: 'value', type: 'value',
axisLine: { show: false }, axisLine: { show: false },
axisLabel: { axisLabel: {
color: isDark ? 'hsl(0 0% 63.9%)' : 'hsl(0 0% 40%)', color: colors.textMuted,
formatter: (val: number) => formatter(val), formatter: (val: number) => formatter(val),
}, },
splitLine: { lineStyle: { color: isDark ? 'hsl(0 0% 14%)' : 'hsl(0 0% 92%)' } }, splitLine: { lineStyle: { color: colors.borderSubtle } },
}; };
const seriesData = this.series.map((s, index) => ({ const seriesData = this.series.map((s, index) => ({

View File

@@ -8,7 +8,7 @@ import { DeesChartEchartsBase } from '../dees-chart-echarts-base.js';
import { demoFunc } from './demo.js'; import { demoFunc } from './demo.js';
import { donutStyles } from './styles.js'; import { donutStyles } from './styles.js';
import { renderChartDonut } from './template.js'; import { renderChartDonut } from './template.js';
import { getEchartsSeriesColors } from '../dees-chart-echarts-theme.js'; import { getEchartsSeriesColors, getThemeColors } from '../dees-chart-echarts-theme.js';
export interface IDonutDataItem { export interface IDonutDataItem {
name: string; name: string;
@@ -62,6 +62,7 @@ export class DeesChartDonut extends DeesChartEchartsBase {
} }
protected buildOption(): Record<string, any> { protected buildOption(): Record<string, any> {
const colors = getThemeColors(this.goBright);
const seriesColors = getEchartsSeriesColors(this.goBright); const seriesColors = getEchartsSeriesColors(this.goBright);
const data = this.data.map((item, index) => ({ const data = this.data.map((item, index) => ({
name: item.name, name: item.name,
@@ -108,6 +109,8 @@ export class DeesChartDonut extends DeesChartEchartsBase {
show: true, show: true,
formatter: '{b}: {d}%', formatter: '{b}: {d}%',
fontSize: 11, fontSize: 11,
color: colors.textSecondary,
textBorderColor: 'transparent',
} }
: { show: false }, : { show: false },
emphasis: { emphasis: {

View File

@@ -1,24 +1,33 @@
/** /**
* Shared theme utilities for ECharts-based chart components. * Shared theme utilities for ECharts-based chart components.
* Provides color palettes and option fragments that match the dees-catalog design tokens. * Uses the centralized themeDefaults tokens so chart colors stay in sync
* with the rest of the dees-catalog design system.
*
* ECharts renders on <canvas> and cannot read CSS custom properties,
* so we reference the TypeScript source-of-truth (themeDefaults) directly.
*/ */
import { themeDefaults } from '../00theme.js';
const light = themeDefaults.colors.light;
const dark = themeDefaults.colors.dark;
const SERIES_COLORS = { const SERIES_COLORS = {
dark: [ dark: [
'hsl(217.2 91.2% 59.8%)', // blue dark.accentPrimary, // blue
'hsl(173.4 80.4% 40%)', // teal 'hsl(173.4 80.4% 40%)', // teal (no token yet)
'hsl(280.3 87.4% 66.7%)', // purple 'hsl(280.3 87.4% 66.7%)', // purple (no token yet)
'hsl(24.6 95% 53.1%)', // orange dark.accentWarning, // orange/amber
'hsl(142 76% 36%)', // green dark.accentSuccess, // green
'hsl(346 77% 49%)', // rose dark.accentError, // rose/red
], ],
light: [ light: [
'hsl(222.2 47.4% 51.2%)', light.accentPrimary,
'hsl(142.1 76.2% 36.3%)', 'hsl(142.1 76.2% 36.3%)', // teal (no token yet)
'hsl(280.3 47.7% 50.2%)', 'hsl(280.3 47.7% 50.2%)', // purple (no token yet)
'hsl(20.5 90.2% 48.2%)', light.accentWarning,
'hsl(160 60% 45%)', light.accentSuccess,
'hsl(340 65% 47%)', light.accentError,
], ],
}; };
@@ -27,29 +36,37 @@ export function getEchartsSeriesColors(goBright: boolean): string[] {
} }
export function getEchartsThemeOptions(goBright: boolean): Record<string, any> { export function getEchartsThemeOptions(goBright: boolean): Record<string, any> {
const isDark = !goBright; const colors = goBright ? light : dark;
return { return {
backgroundColor: 'transparent', backgroundColor: 'transparent',
textStyle: { textStyle: {
color: isDark ? 'hsl(0 0% 63.9%)' : 'hsl(0 0% 20%)', color: colors.textSecondary,
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif',
fontSize: 12, fontSize: 12,
}, },
color: goBright ? SERIES_COLORS.light : SERIES_COLORS.dark, color: goBright ? SERIES_COLORS.light : SERIES_COLORS.dark,
tooltip: { tooltip: {
backgroundColor: isDark ? 'hsl(0 0% 9%)' : 'hsl(0 0% 100%)', backgroundColor: colors.bgPrimary,
borderColor: isDark ? 'hsl(0 0% 14.9%)' : 'hsl(0 0% 89.8%)', borderColor: colors.borderDefault,
textStyle: { textStyle: {
color: isDark ? 'hsl(0 0% 95%)' : 'hsl(0 0% 9%)', color: colors.textPrimary,
fontSize: 12, fontSize: 12,
}, },
confine: true, confine: true,
}, },
legend: { legend: {
textStyle: { textStyle: {
color: isDark ? 'hsl(0 0% 63.9%)' : 'hsl(0 0% 20%)', color: colors.textSecondary,
fontSize: 12, fontSize: 12,
}, },
}, },
}; };
} }
/**
* Helper to get the resolved theme colors object for use in buildOption().
* Components can use this instead of hardcoding dark/light color values.
*/
export function getThemeColors(goBright: boolean) {
return goBright ? light : dark;
}

View File

@@ -8,7 +8,7 @@ import { DeesChartEchartsBase } from '../dees-chart-echarts-base.js';
import { demoFunc } from './demo.js'; import { demoFunc } from './demo.js';
import { gaugeStyles } from './styles.js'; import { gaugeStyles } from './styles.js';
import { renderChartGauge } from './template.js'; import { renderChartGauge } from './template.js';
import { getEchartsSeriesColors } from '../dees-chart-echarts-theme.js'; import { getEchartsSeriesColors, getThemeColors } from '../dees-chart-echarts-theme.js';
export interface IGaugeThreshold { export interface IGaugeThreshold {
value: number; value: number;
@@ -66,7 +66,7 @@ export class DeesChartGauge extends DeesChartEchartsBase {
} }
protected buildOption(): Record<string, any> { protected buildOption(): Record<string, any> {
const isDark = !this.goBright; const colors = getThemeColors(this.goBright);
const seriesColors = getEchartsSeriesColors(this.goBright); const seriesColors = getEchartsSeriesColors(this.goBright);
const primaryColor = seriesColors[0]; const primaryColor = seriesColors[0];
@@ -119,7 +119,7 @@ export class DeesChartGauge extends DeesChartEchartsBase {
distance: -20, distance: -20,
length: 6, length: 6,
lineStyle: { lineStyle: {
color: isDark ? 'hsl(0 0% 30%)' : 'hsl(0 0% 75%)', color: colors.borderStrong,
width: 1, width: 1,
}, },
}, },
@@ -128,14 +128,14 @@ export class DeesChartGauge extends DeesChartEchartsBase {
distance: -24, distance: -24,
length: 10, length: 10,
lineStyle: { lineStyle: {
color: isDark ? 'hsl(0 0% 40%)' : 'hsl(0 0% 60%)', color: colors.textMuted,
width: 2, width: 2,
}, },
}, },
axisLabel: { axisLabel: {
show: this.showTicks, show: this.showTicks,
distance: 30, distance: 30,
color: isDark ? 'hsl(0 0% 50%)' : 'hsl(0 0% 45%)', color: colors.textMuted,
fontSize: 11, fontSize: 11,
}, },
detail: { detail: {
@@ -143,7 +143,7 @@ export class DeesChartGauge extends DeesChartEchartsBase {
fontSize: 28, fontSize: 28,
fontWeight: 600, fontWeight: 600,
offsetCenter: [0, '65%'], offsetCenter: [0, '65%'],
color: isDark ? 'hsl(0 0% 90%)' : 'hsl(0 0% 15%)', color: colors.textPrimary,
formatter: `{value}${this.unit}`, formatter: `{value}${this.unit}`,
}, },
title: { title: {

View File

@@ -8,7 +8,7 @@ import { DeesChartEchartsBase } from '../dees-chart-echarts-base.js';
import { demoFunc } from './demo.js'; import { demoFunc } from './demo.js';
import { radarStyles } from './styles.js'; import { radarStyles } from './styles.js';
import { renderChartRadar } from './template.js'; import { renderChartRadar } from './template.js';
import { getEchartsSeriesColors } from '../dees-chart-echarts-theme.js'; import { getEchartsSeriesColors, getThemeColors } from '../dees-chart-echarts-theme.js';
export interface IRadarIndicator { export interface IRadarIndicator {
name: string; name: string;
@@ -64,7 +64,7 @@ export class DeesChartRadar extends DeesChartEchartsBase {
} }
protected buildOption(): Record<string, any> { protected buildOption(): Record<string, any> {
const isDark = !this.goBright; const colors = getThemeColors(this.goBright);
const seriesColors = getEchartsSeriesColors(this.goBright); const seriesColors = getEchartsSeriesColors(this.goBright);
const seriesData = this.series.map((s, index) => { const seriesData = this.series.map((s, index) => {
@@ -95,24 +95,22 @@ export class DeesChartRadar extends DeesChartEchartsBase {
shape: 'polygon', shape: 'polygon',
splitNumber: 4, splitNumber: 4,
axisName: { axisName: {
color: isDark ? 'hsl(0 0% 63.9%)' : 'hsl(0 0% 35%)', color: colors.textSecondary,
fontSize: 11, fontSize: 11,
}, },
splitArea: { splitArea: {
areaStyle: { areaStyle: {
color: isDark color: [colors.bgTertiary, colors.bgSecondary],
? ['hsl(0 0% 7%)', 'hsl(0 0% 9%)']
: ['hsl(0 0% 97%)', 'hsl(0 0% 95%)'],
}, },
}, },
splitLine: { splitLine: {
lineStyle: { lineStyle: {
color: isDark ? 'hsl(0 0% 16%)' : 'hsl(0 0% 88%)', color: colors.borderDefault,
}, },
}, },
axisLine: { axisLine: {
lineStyle: { lineStyle: {
color: isDark ? 'hsl(0 0% 16%)' : 'hsl(0 0% 88%)', color: colors.borderDefault,
}, },
}, },
}, },

View File

@@ -334,7 +334,9 @@ body > div[style*="top: -50000px"][style*="width: 50000px"] {
} }
this.echartsLoadingPromise = (async () => { this.echartsLoadingPromise = (async () => {
const url = `${CDN_BASE}/echarts@${CDN_VERSIONS.echarts}/+esm`; // Use the pre-built ESM bundle which includes all chart types and components.
// The +esm wrapper only exports the core without auto-registered chart types.
const url = `${CDN_BASE}/echarts@${CDN_VERSIONS.echarts}/dist/echarts.esm.min.js`;
const module = await import(/* @vite-ignore */ url); const module = await import(/* @vite-ignore */ url);
this.echartsLib = { this.echartsLib = {