@kylincloud/flamegraph 0.35.19 → 0.35.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kylincloud/flamegraph",
3
- "version": "0.35.19",
3
+ "version": "0.35.21",
4
4
  "description": "KylinCloud flamegraph renderer (Pyroscope-based)",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.node.cjs.js",
@@ -71,7 +71,7 @@ export const DiffLegendPaletteDropdown = (
71
71
  >
72
72
  {/* 触发按钮:当前色带预览 + 下拉箭头 */}
73
73
  <DiffLegend palette={palette} showMode="small" />
74
- <span className={styles.dropdownArrow}>▼</span>
74
+ <span className={styles.dropdownArrow}></span>
75
75
  </MenuButton>
76
76
  }
77
77
  onItemClick={(e) => {
@@ -9,7 +9,6 @@
9
9
  }
10
10
 
11
11
  .search {
12
- // 默认样式:白色背景,适用于 light 和 kylin 模式
13
12
  background: var(--ps-immutable-white);
14
13
  transition:
15
14
  background-color 0.1s ease-out,
@@ -23,16 +22,15 @@
23
22
  height: 37px;
24
23
  width: 100%;
25
24
 
26
- // 2)文本颜色改成“偏灰”,不要纯黑
27
- // 这里用一个接近 antd 的值:rgba(0, 0, 0, 0.65)
28
- color: rgba(0, 0, 0, 0.65);
25
+ /* 2)文本颜色改成“偏灰”,不要纯黑 */
26
+ color: rgba(0, 0, 0, 0.85);
29
27
 
30
- // 3)placeholder 再淡一点,类似 antd 的 placeholder
28
+ /* 3)placeholder 再淡一点,类似 antd 的 placeholder */
31
29
  &::placeholder {
32
30
  color: rgba(0, 0, 0, 0.25);
33
31
  }
34
32
 
35
- // 适配 light 和 kylin 模式
33
+ /* 适配 light 和 kylin 模式 */
36
34
  &.light,
37
35
  &.kylin {
38
36
  background: var(--ps-immutable-white);
@@ -40,7 +38,7 @@
40
38
  border-color: var(--ps-ui-border);
41
39
  }
42
40
 
43
- // 适配 dark 模式
41
+ /* 适配 dark 模式 */
44
42
  @media (prefers-color-scheme: dark) {
45
43
 
46
44
  &,
@@ -55,22 +53,30 @@
55
53
  }
56
54
  }
57
55
 
58
- // 聚焦样式
56
+ /* 聚焦时的绿色框样式 */
57
+ &:focus-visible {
58
+ background: var(--ps-immutable-white);
59
+ border-color: rgb(93, 151, 111);
60
+ box-shadow: 0 0 0 3px rgba(93, 151, 111, 0.4); /* 更强的阴影效果 */
61
+ outline: none; /* 确保没有其他 outline 样式 */
62
+ }
63
+
64
+ /* light 和 kylin 模式下的聚焦样式 */
59
65
  &.light:focus,
60
66
  &.kylin:focus {
61
67
  background: var(--ps-immutable-white);
62
68
  border-color: rgb(93, 151, 111);
63
- box-shadow: 0 0 0 2px rgba(93, 151, 111, 0.2);
64
- outline: none;
69
+ box-shadow: 0 0 0 2px rgba(93, 151, 111, 0.2); /* 较弱的阴影效果 */
70
+ outline: none; /* 确保没有其他 outline 样式 */
65
71
  }
66
72
 
67
- // dark 模式下的聚焦样式
73
+ /* dark 模式下的聚焦样式 */
68
74
  @media (prefers-color-scheme: dark) {
69
75
  &.dark:focus {
70
76
  background: var(--ps-immutable-dark-background);
71
- border-color: rgb(93, 151, 111);
72
- box-shadow: 0 0 0 2px rgba(93, 151, 111, 0.2);
73
- outline: none;
77
+ border-color: rgb(48, 48, 48); /* 使用更深的边框颜色 */
78
+ box-shadow: 0 0 0 2px rgba(48, 48, 48, 0.6); /* 更深的阴影效果 */
79
+ outline: none; /* 确保没有其他 outline 样式 */
74
80
  }
75
81
  }
76
82
  }
@@ -7,7 +7,7 @@
7
7
  color: var(--ps-tooltip-text);
8
8
  font-size: 12px;
9
9
  visibility: hidden;
10
- z-index: 2;
10
+ z-index: 5;
11
11
  pointer-events: none;
12
12
 
13
13
  &.flamegraphDiffTooltip {
@@ -7,6 +7,7 @@ import React, {
7
7
  useState,
8
8
  useRef,
9
9
  useCallback,
10
+ useLayoutEffect,
10
11
  Dispatch,
11
12
  SetStateAction,
12
13
  } from 'react';
@@ -210,6 +211,52 @@ function getDiffColorByText(
210
211
  return undefined;
211
212
  }
212
213
 
214
+ /**
215
+ * Tooltip 位置计算:默认右下;若越界则翻到左/上;最终 clamp 到视口内。
216
+ * 注意:Tooltip 使用 position: fixed,因此用 innerWidth/innerHeight 做视口碰撞检测最直接。
217
+ */
218
+ const TOOLTIP_GAP_X = 12;
219
+ const TOOLTIP_GAP_Y = 20;
220
+ const TOOLTIP_PAD = 8;
221
+
222
+ function clamp(v: number, min: number, max: number) {
223
+ if (max < min) return min;
224
+ return Math.max(min, Math.min(max, v));
225
+ }
226
+
227
+ function computeSafeTooltipPos(
228
+ x: number,
229
+ y: number,
230
+ tipW: number,
231
+ tipH: number
232
+ ) {
233
+ const vw = window.innerWidth;
234
+ const vh = window.innerHeight;
235
+
236
+ const w = Math.max(0, tipW || 0);
237
+ const h = Math.max(0, tipH || 0);
238
+
239
+ // 默认:右下
240
+ let left = x + TOOLTIP_GAP_X;
241
+ let top = y + TOOLTIP_GAP_Y;
242
+
243
+ // 右侧溢出:翻到左边
244
+ if (left + w + TOOLTIP_PAD > vw) {
245
+ left = x - w - TOOLTIP_GAP_X;
246
+ }
247
+
248
+ // 底部溢出:翻到上边
249
+ if (top + h + TOOLTIP_PAD > vh) {
250
+ top = y - h - TOOLTIP_GAP_Y;
251
+ }
252
+
253
+ // 最终夹取到视口内
254
+ left = clamp(left, TOOLTIP_PAD, vw - w - TOOLTIP_PAD);
255
+ top = clamp(top, TOOLTIP_PAD, vh - h - TOOLTIP_PAD);
256
+
257
+ return { left, top };
258
+ }
259
+
213
260
  export function Tooltip({
214
261
  shouldShowFooter = true,
215
262
  shouldShowTitle = true,
@@ -219,6 +266,8 @@ export function Tooltip({
219
266
  palette,
220
267
  }: TooltipProps) {
221
268
  const tooltipRef = useRef<HTMLDivElement>(null);
269
+ const lastPosRef = useRef<{ x: number; y: number } | null>(null);
270
+
222
271
  const [content, setContent] = React.useState({
223
272
  title: {
224
273
  text: '',
@@ -245,13 +294,17 @@ export function Tooltip({
245
294
  throw new Error('Missing tooltipElement');
246
295
  }
247
296
 
248
- const left = Math.min(
249
- e.clientX + 12,
250
- window.innerWidth - tooltipRef.current.clientWidth - 20
251
- );
252
- const top = e.clientY + 20;
297
+ // 记录最后鼠标位置(给 useLayoutEffect 二次校正用)
298
+ lastPosRef.current = { x: e.clientX, y: e.clientY };
253
299
 
300
+ // 先更新内容(tooltip 高度可能因此变化)
254
301
  setTooltipContent(setContent, onMouseOut, e);
302
+
303
+ // 用当前已渲染的尺寸先算一次位置(内容变化后的真实尺寸会在 useLayoutEffect 再校正)
304
+ const w = tooltipRef.current.clientWidth || 0;
305
+ const h = tooltipRef.current.clientHeight || 0;
306
+
307
+ const { left, top } = computeSafeTooltipPos(e.clientX, e.clientY, w, h);
255
308
  setStyle({ top, left, visibility: 'visible' });
256
309
  },
257
310
  [setTooltipContent]
@@ -278,6 +331,24 @@ export function Tooltip({
278
331
  };
279
332
  }, [dataSourceRef.current, memoizedOnMouseMove]);
280
333
 
334
+ // 内容变化后用真实 DOM 尺寸做二次校正,避免“首次显示尺寸尚未更新导致仍越界”
335
+ useLayoutEffect(() => {
336
+ if (!tooltipRef.current) return;
337
+ if (!lastPosRef.current) return;
338
+ if (content.tooltipData.length === 0) return;
339
+
340
+ const { x, y } = lastPosRef.current;
341
+ const rect = tooltipRef.current.getBoundingClientRect();
342
+ const { left, top } = computeSafeTooltipPos(x, y, rect.width, rect.height);
343
+
344
+ setStyle((prev) => {
345
+ if (prev && prev.left === left && prev.top === top && prev.visibility === 'visible') {
346
+ return prev;
347
+ }
348
+ return { ...(prev || {}), left, top, visibility: 'visible' };
349
+ });
350
+ }, [content.tooltipData.length, content.title.text]);
351
+
281
352
  return (
282
353
  <div
283
354
  data-testid="tooltip"
@@ -460,12 +531,10 @@ function TooltipTable({
460
531
  <tr>
461
532
  <td />
462
533
  <td>
463
- {i18n.self} (
464
- {i18n.tooltipUnitTitles[baselineData.units].total})
534
+ {i18n.self} ({i18n.tooltipUnitTitles[baselineData.units].total})
465
535
  </td>
466
536
  <td>
467
- {i18n.total} (
468
- {i18n.tooltipUnitTitles[baselineData.units].total})
537
+ {i18n.total} ({i18n.tooltipUnitTitles[baselineData.units].total})
469
538
  </td>
470
539
  </tr>
471
540
  </thead>