Skip to content

Commit 8aa4778

Browse files
authored
feat(tooltip): 支持自定义挂载节点 (#1139)
* feat(tooltip): 支持自定义挂载节点 * test: 修复测试 * test: 修改测试断言描述 * test: 修复测试 * test: 修复测试 * fix: 修复未开启tooltip, 还是会渲染 container 节点的问题 * test: 修复测试
1 parent 988d356 commit 8aa4778

File tree

10 files changed

+145
-16
lines changed

10 files changed

+145
-16
lines changed

packages/s2-core/__tests__/spreadsheet/interaction-tooltip-spec.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,19 @@ describe('Interaction Tooltip Tests', () => {
3030
});
3131

3232
test('should display tooltip when data cell clicked', () => {
33-
const showTooltipWithInfoSpy = jest
34-
.spyOn(s2, 'showTooltipWithInfo')
35-
.mockImplementation(() => {});
33+
const isContains = () => {
34+
return s2.tooltip.container?.classList?.contains(
35+
'antv-s2-tooltip-container-show',
36+
);
37+
};
38+
39+
expect(isContains()).toBeFalsy();
3640

3741
s2.emit(S2Event.DATA_CELL_CLICK, {
3842
stopPropagation() {},
3943
} as unknown as GEvent);
4044

41-
expect(showTooltipWithInfoSpy).toHaveBeenCalledTimes(1);
45+
expect(isContains()).toBeTruthy();
4246
expect(s2.tooltip.container.style.display).not.toEqual('none');
4347
expect(s2.tooltip.container.style.visibility).not.toEqual('hidden');
4448
});
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import * as mockDataConfig from 'tests/data/simple-data.json';
2+
import { getContainer } from 'tests/util/helpers';
3+
import { PivotSheet } from '@/sheet-type';
4+
import { S2Options } from '@/common/interface';
5+
6+
const s2Options: S2Options = {
7+
width: 300,
8+
height: 200,
9+
};
10+
11+
const CONTAINER_CLASS_NAME = 'antv-s2-tooltip-container';
12+
13+
describe('Tooltip Tests', () => {
14+
const createS2 = (tooltipOptions: S2Options['tooltip']) => {
15+
return new PivotSheet(getContainer(), mockDataConfig, {
16+
...s2Options,
17+
tooltip: tooltipOptions,
18+
});
19+
};
20+
21+
test('should not render tooltip in default container if disable tooltip', async () => {
22+
const s2 = createS2({ showTooltip: false });
23+
s2.render();
24+
25+
expect(
26+
document.querySelector(`body > .${CONTAINER_CLASS_NAME}`),
27+
).toBeFalsy();
28+
29+
s2.destroy();
30+
});
31+
32+
test('should not render tooltip in default container when hide tooltip if disable tooltip', async () => {
33+
const s2 = createS2({ showTooltip: false });
34+
s2.render();
35+
36+
s2.hideTooltip();
37+
38+
expect(
39+
document.querySelector(`body > .${CONTAINER_CLASS_NAME}`),
40+
).toBeFalsy();
41+
42+
s2.destroy();
43+
});
44+
45+
test('should render tooltip in default container', async () => {
46+
const s2 = createS2({ showTooltip: true });
47+
s2.render();
48+
49+
s2.showTooltip({ position: { x: 0, y: 0 } });
50+
51+
expect(
52+
document.querySelector(`body > div[class^="${CONTAINER_CLASS_NAME}"]`),
53+
).toBeTruthy();
54+
55+
s2.destroy();
56+
});
57+
58+
test('should render tooltip in custom container', async () => {
59+
const container = document.createElement('div');
60+
container.id = 'custom-container';
61+
document.body.appendChild(container);
62+
63+
const s2 = createS2({
64+
showTooltip: true,
65+
getContainer: () => container,
66+
});
67+
68+
s2.render();
69+
70+
s2.showTooltip({ position: { x: 0, y: 0 } });
71+
72+
expect(
73+
document.querySelector(`body > .${CONTAINER_CLASS_NAME}`),
74+
).toBeFalsy();
75+
76+
expect(
77+
document.querySelector(
78+
`#custom-container > div[class^="${CONTAINER_CLASS_NAME}"]`,
79+
),
80+
).toBeTruthy();
81+
82+
s2.destroy();
83+
});
84+
});

packages/s2-core/__tests__/unit/sheet-type/pivot-sheet-spec.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// eslint-disable-next-line max-classes-per-file
2-
import { getContainer, sleep } from 'tests/util/helpers';
2+
import { getContainer } from 'tests/util/helpers';
33
import * as dataCfg from 'tests/data/simple-data.json';
44
import { Canvas, Event as GEvent } from '@antv/g-canvas';
55
import { cloneDeep } from 'lodash';
@@ -181,6 +181,8 @@ describe('PivotSheet Tests', () => {
181181
sheet.showTooltipWithInfo({ clientX: 0, clientY: 0 } as MouseEvent, []);
182182

183183
expect(sheet.tooltip.container.innerHTML).toEqual(tooltipContent);
184+
185+
sheet.destroy();
184186
});
185187

186188
test.each([
@@ -214,6 +216,8 @@ describe('PivotSheet Tests', () => {
214216
sheet.showTooltipWithInfo({ clientX: 0, clientY: 0 } as MouseEvent, []);
215217

216218
expect(sheet.tooltip.container.innerHTML).toEqual(tooltipContent);
219+
220+
sheet.destroy();
217221
},
218222
);
219223

@@ -247,6 +251,8 @@ describe('PivotSheet Tests', () => {
247251
});
248252

249253
expect(sheet.tooltip.container.innerHTML).toEqual(methodTooltipContent);
254+
255+
sheet.destroy();
250256
},
251257
);
252258

@@ -279,6 +285,8 @@ describe('PivotSheet Tests', () => {
279285
expect(
280286
sheet.tooltip.container.contains(defaultTooltipContent),
281287
).toBeFalsy();
288+
289+
sheet.destroy();
282290
},
283291
);
284292

@@ -314,6 +322,8 @@ describe('PivotSheet Tests', () => {
314322
expect(
315323
sheet.tooltip.container.contains(methodTooltipContent),
316324
).toBeTruthy();
325+
326+
sheet.destroy();
317327
},
318328
);
319329

@@ -361,6 +371,8 @@ describe('PivotSheet Tests', () => {
361371
expect(customShow).toHaveBeenCalled();
362372
expect(customHide).toHaveBeenCalled();
363373
expect(customDestroy).toHaveBeenCalled();
374+
375+
sheet.destroy();
364376
});
365377

366378
test('should show invalid custom tooltip warning', () => {
@@ -388,6 +400,8 @@ describe('PivotSheet Tests', () => {
388400
sheet.tooltip as unknown
389401
)?.constructor?.toString()} should be extends from BaseTooltip`,
390402
);
403+
404+
sheet.destroy();
391405
});
392406
});
393407

@@ -741,11 +755,11 @@ describe('PivotSheet Tests', () => {
741755
test('should destroy sheet', () => {
742756
const facetDestroySpy = jest
743757
.spyOn(s2.facet, 'destroy')
744-
.mockImplementation(() => {});
758+
.mockImplementationOnce(() => {});
745759

746760
const hdAdapterDestroySpy = jest
747761
.spyOn(s2.hdAdapter, 'destroy')
748-
.mockImplementation(() => {});
762+
.mockImplementationOnce(() => {});
749763

750764
s2.render(false);
751765

packages/s2-core/__tests__/util/helpers.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,9 @@ export const createMockCellInfo = (
117117
const mockCell = {
118118
...mockCellViewMeta,
119119
getMeta: () => mockCellViewMeta,
120+
update: jest.fn(),
121+
getActualText: jest.fn(),
122+
getFieldValue: jest.fn(),
120123
hideInteractionShape: jest.fn(),
121124
};
122125

packages/s2-core/src/common/interface/tooltip.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ export interface BaseTooltipConfig<T = TooltipContentType> {
154154
readonly operation?: TooltipOperation;
155155
readonly autoAdjustBoundary?: TooltipAutoAdjustBoundary;
156156
readonly renderTooltip?: (spreadsheet: SpreadSheet) => BaseTooltip;
157+
// Custom tooltip mount container
158+
readonly getContainer?: () => HTMLElement;
157159
}
158160

159161
export interface Tooltip<T = TooltipContentType> extends BaseTooltipConfig<T> {

packages/s2-core/src/sheet-type/spread-sheet.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,13 +352,13 @@ export abstract class SpreadSheet extends EE {
352352

353353
public destroy() {
354354
this.emit(S2Event.LAYOUT_DESTROY);
355-
this.facet.destroy();
355+
this.facet?.destroy();
356356
this.hdAdapter?.destroy();
357-
this.interaction.destroy();
358-
this.store.clear();
357+
this.interaction?.destroy();
358+
this.store?.clear();
359359
this.destroyTooltip();
360360
this.clearCanvasEvent();
361-
this.container.destroy();
361+
this.container?.destroy();
362362
}
363363

364364
/**

packages/s2-core/src/ui/tooltip/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ export class BaseTooltip {
7373
}
7474

7575
public hide() {
76+
if (!this.container) {
77+
return;
78+
}
7679
const container = this.getContainer();
7780
setContainerStyle(container, {
7881
style: {
@@ -87,7 +90,7 @@ export class BaseTooltip {
8790
const container = this.getContainer();
8891
if (container) {
8992
this.resetPosition();
90-
container?.remove();
93+
container.remove?.();
9194
}
9295
}
9396

@@ -143,10 +146,13 @@ export class BaseTooltip {
143146
*/
144147
protected getContainer(): HTMLElement {
145148
if (!this.container) {
149+
const rootContainer =
150+
this.spreadsheet.options.tooltip.getContainer?.() || document.body;
151+
146152
const container = document.createElement('div');
147-
document.body.appendChild(container);
153+
rootContainer.appendChild(container);
154+
148155
this.container = container;
149-
return this.container;
150156
}
151157
this.container.className = `${TOOLTIP_PREFIX_CLS}-container`;
152158
return this.container;

packages/s2-react/__tests__/spreadsheet/tooltip-spec.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ function MainLayout() {
4040
describe('SheetComponent Tooltip Tests', () => {
4141
beforeEach(() => {
4242
s2?.destroy();
43-
s2 = null;
4443
});
4544

4645
beforeEach(() => {

s2-site/docs/common/tooltip.zh.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ object **必选**,_default:null_ 功能描述: tooltip 配置
1818
| renderTooltip | 自定义整个 tooltip, 可以继承 BaseTooltip 自己重写一些方法 | [RenderTooltip](#rendertooltip) | - | |
1919
| content | 自定义 tooltip 内容 | `React.ReactNode | Element | string |` 或者 `(cell, defaultTooltipShowOptions) => React.ReactNode | Element | string` | - | |
2020
| autoAdjustBoundary | 当 tooltip 超过边界时自动调整显示位置,container: 图表区域,body: 整个浏览器窗口,设置为 `null` 可关闭此功能 | `container` \| `body` | `body` | |
21+
| getContainer | 自定义 tooltip 挂载容器,| `() => HTMLElement` | `document.body` | |
2122

2223
### BaseTooltipConfig
2324

s2-site/docs/manual/basic/tooltip.zh.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const s2Options = {
5555

5656
### 操作配置项
5757

58-
通过配置 `operation` 字段在 `Tooltip` 上增加操作项
58+
通过配置 `operation` 字段在 `Tooltip` 上增加 [操作项](/zh/docs/api/general/S2Options#tooltipoperation), 支持 [自定义](#自定义-tooltip-操作项).
5959

6060
```ts
6161
const s2Options = {
@@ -271,6 +271,22 @@ const s2Options = {
271271
272272
<playground path='react-component/tooltip/demo/custom-operation.tsx' rid='container-custom-operations' height='300'></playground>
273273
274+
#### 自定义 Tooltip 挂载节点
275+
276+
默认挂载在 `body` 上,可自定义挂载位置
277+
278+
```html
279+
<div class="container" />
280+
```
281+
282+
```ts
283+
const s2Options = {
284+
tooltip: {
285+
getContainer: () => document.querySelector('.container')
286+
}
287+
}
288+
```
289+
274290
#### 自定义 Tooltip 类
275291
276292
继承 `BaseTooltip` 基类,可重写 `显示 (show)`, `隐藏 (hide)`, `销毁 (destroy)` 等方法,结合 `this.spreadsheet` 实例,来实现满足你业务的 `tooltip`

0 commit comments

Comments
 (0)