Skip to content

Commit ab86a7c

Browse files
committed
fix: preserve tooltip theme visibility overrides
Tooltip theme merging was flattening nested style values and dropping root tooltip config such as mark and dimension visibility. This keeps style fields in spec.style, merges functional tooltip config at the root, and adds a focused regression for theme-driven tooltip visibility. Constraint: Tooltip themes must support both style fields and root spec fields Rejected: Fix only style merging | mark and dimension visibility would still be ignored Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep tooltip theme merge split between style keys and root spec keys Tested: Direct transformer probes for style nesting and mark visibility exclusion Tested: File-level TypeScript diagnostics on changed files Not-tested: Full package compile blocked by pre-existing continuous legend type errors
1 parent c2cfe21 commit ab86a7c

4 files changed

Lines changed: 135 additions & 10 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,4 @@ packages/vchart/__tests__/runtime/node/**.png
135135

136136
*.tsbuildinfo
137137
.github/hooks/copilot-hooks.json
138+
.omx/
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { mergeSpec } from '@visactor/vutils-extension';
2+
import { TooltipSpecTransformer } from '../../../src/component/tooltip/tooltip-transformer';
3+
import { ComponentTypeEnum } from '../../../src/component/interface/type';
4+
import { tooltip as builtInTooltipTheme } from '../../../src/theme/builtin/common/component/tooltip';
5+
6+
describe('tooltip theme transformer', () => {
7+
const createTransformer = (tooltipTheme: Record<string, any>) =>
8+
new TooltipSpecTransformer({
9+
type: ComponentTypeEnum.tooltip,
10+
mode: 'node',
11+
getTheme: (...keys: string[]) => {
12+
if (keys[0] === 'component' && keys[1] === ComponentTypeEnum.tooltip) {
13+
return mergeSpec({}, builtInTooltipTheme, tooltipTheme);
14+
}
15+
return undefined;
16+
}
17+
});
18+
19+
it('supports tooltip theme fields declared under component.tooltip.style', () => {
20+
const transformer = createTransformer({
21+
style: {
22+
panel: {
23+
backgroundColor: '#123456'
24+
},
25+
titleLabel: {
26+
fill: '#abcdef',
27+
fontSize: 18
28+
},
29+
keyLabel: {
30+
fill: '#ff0000'
31+
}
32+
}
33+
});
34+
35+
const { spec } = transformer.transformSpec({}, {});
36+
37+
expect(spec.style.panel.backgroundColor).toBe('#123456');
38+
expect(spec.style.titleLabel.fill).toBe('#abcdef');
39+
expect(spec.style.titleLabel.fontSize).toBe(18);
40+
expect(spec.style.keyLabel.fill).toBe('#ff0000');
41+
expect(spec.style.style).toBeUndefined();
42+
});
43+
44+
it('keeps root tooltip theme fields at root instead of leaking them into style', () => {
45+
const transformer = createTransformer({
46+
offset: {
47+
x: 24,
48+
y: 16
49+
},
50+
trigger: 'click',
51+
transitionDuration: 0,
52+
panel: {
53+
backgroundColor: '#654321'
54+
}
55+
});
56+
57+
const { spec } = transformer.transformSpec({}, {});
58+
59+
expect(spec.offset).toEqual({ x: 24, y: 16 });
60+
expect(spec.trigger).toBe('click');
61+
expect(spec.transitionDuration).toBe(0);
62+
expect(spec.style.panel.backgroundColor).toBe('#654321');
63+
expect(spec.style.offset).toBeUndefined();
64+
expect(spec.style.trigger).toBeUndefined();
65+
expect(spec.style.transitionDuration).toBeUndefined();
66+
});
67+
68+
it('supports active-type visibility declared in tooltip theme', () => {
69+
const transformer = createTransformer({
70+
mark: {
71+
visible: false
72+
},
73+
dimension: {
74+
visible: true
75+
}
76+
});
77+
78+
const { spec } = transformer.transformSpec({}, {});
79+
80+
expect(spec.mark.visible).toBe(false);
81+
expect(spec.dimension.visible).toBe(true);
82+
expect(spec.activeType).not.toContain('mark');
83+
expect(spec.activeType).toContain('dimension');
84+
});
85+
});

packages/vchart/src/component/interface/theme.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { IMarkLineTheme } from '../marker/mark-line/interface';
1111
import type { IMarkPointTheme } from '../marker/mark-point/interface';
1212
import type { IPlayerTheme } from '../player/interface';
1313
import type { ITitleTheme } from '../title/interface';
14-
import type { ITooltipTheme } from '../tooltip/interface';
14+
import type { ITooltipSpec, ITooltipTheme } from '../tooltip/interface';
1515
import type { ComponentTypeEnum } from './type';
1616
import type { ITotalLabelTheme } from '../label/interface';
1717
import type { IPoptipTheme } from '../poptip/interface';
@@ -80,7 +80,28 @@ export interface IComponentTheme {
8080
/**
8181
* tooltip 组件配置
8282
*/
83-
[ComponentTypeEnum.tooltip]?: ITooltipTheme<string | IColorKey>;
83+
[ComponentTypeEnum.tooltip]?: ITooltipTheme<string | IColorKey> &
84+
Partial<
85+
Pick<
86+
ITooltipSpec,
87+
| 'visible'
88+
| 'activeType'
89+
| 'mark'
90+
| 'dimension'
91+
| 'group'
92+
| 'trigger'
93+
| 'triggerOff'
94+
| 'showDelay'
95+
| 'hideTimer'
96+
| 'lockAfterClick'
97+
| 'renderMode'
98+
| 'confine'
99+
| 'className'
100+
| 'parentElement'
101+
| 'enterable'
102+
| 'throttleInterval'
103+
>
104+
>;
84105
/**
85106
* crosshair 配置
86107
*/

packages/vchart/src/component/tooltip/tooltip-transformer.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,42 @@ import { TOOLTIP_EL_CLASS_NAME } from './constant';
66
import { getTooltipActualActiveType } from './utils/common';
77
import { mergeSpec } from '@visactor/vutils-extension';
88

9+
const TOOLTIP_STYLE_THEME_KEYS = [
10+
'panel',
11+
'shape',
12+
'titleLabel',
13+
'keyLabel',
14+
'valueLabel',
15+
'spaceRow',
16+
'maxContentHeight',
17+
'align'
18+
] as const;
19+
920
export class TooltipSpecTransformer extends BaseComponentSpecTransformer<any> {
1021
protected _shouldMergeThemeToSpec() {
1122
return false;
1223
}
1324

1425
protected _initTheme(spec: any, chartSpec: any): { spec: any; theme: any } {
1526
const { spec: newSpec, theme } = super._initTheme(spec, chartSpec);
27+
const themeStyle = mergeSpec(
28+
{},
29+
...TOOLTIP_STYLE_THEME_KEYS.map(key => (theme?.[key] !== undefined ? { [key]: theme[key] } : undefined)),
30+
theme?.style
31+
);
32+
const themeSpec = mergeSpec({}, theme);
33+
34+
TOOLTIP_STYLE_THEME_KEYS.forEach(key => {
35+
delete themeSpec[key];
36+
});
37+
delete themeSpec.style;
1638

17-
// 合并样式和配置
18-
newSpec.style = mergeSpec({}, this._theme, newSpec.style);
19-
newSpec.offset = mergeSpec({}, theme.offset, spec.offset);
20-
newSpec.transitionDuration = spec.transitionDuration ?? theme.transitionDuration;
39+
const mergedSpec = mergeSpec({}, themeSpec, newSpec);
2140

22-
// 合并交互相关配置
23-
newSpec.trigger = spec.trigger ?? theme.trigger;
24-
newSpec.triggerOff = spec.triggerOff ?? theme.triggerOff;
41+
// 合并样式配置
42+
mergedSpec.style = mergeSpec({}, themeStyle, mergedSpec.style);
2543

26-
return { spec: newSpec, theme };
44+
return { spec: mergedSpec, theme };
2745
}
2846

2947
protected _transformSpecAfterMergingTheme(spec: any, chartSpec: any, chartSpecInfo?: IChartSpecInfo) {

0 commit comments

Comments
 (0)