one-design-next 0.0.67 → 0.0.68
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/dist/chat-item/index.js +53 -29
- package/package.json +1 -1
package/dist/chat-item/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
2
2
|
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
|
|
3
|
-
import {
|
|
4
|
-
import HoverFill from "../hover-fill";
|
|
5
|
-
import Icon from "../icon";
|
|
3
|
+
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
6
4
|
import Dialog from "../dialog";
|
|
7
5
|
import Dropdown from "../dropdown";
|
|
6
|
+
import HoverFill from "../hover-fill";
|
|
7
|
+
import Icon from "../icon";
|
|
8
8
|
import { formatRelativeTime } from "./relative-time";
|
|
9
9
|
import "./style";
|
|
10
10
|
var STATUS_ARIA_LABEL = {
|
|
@@ -15,9 +15,15 @@ var STATUS_ARIA_LABEL = {
|
|
|
15
15
|
};
|
|
16
16
|
var ELLIPSIS = '…';
|
|
17
17
|
|
|
18
|
+
/** 可用宽度变化小于该值时跳过重算(与二分容差同量级) */
|
|
19
|
+
var FIT_WIDTH_EPS = 0.5;
|
|
20
|
+
|
|
18
21
|
/**
|
|
19
22
|
* 有 trailing(客服 icon / status / 时间)时,用 DOM 实测把标题裁到可用宽度。
|
|
20
23
|
* 解决 CSS text-overflow 按字符边界截断后,省略号右侧留白把 trailing 顶开的问题。
|
|
24
|
+
*
|
|
25
|
+
* 性能:只监听整行(btn)宽度;RO 回调经 rAF 合并(每行每帧最多 fit 一次);
|
|
26
|
+
* 缓存 maxWidth / trailingWidth / 裁切结果,宽度几乎不变或结果不变则跳过更新。
|
|
21
27
|
*/
|
|
22
28
|
function useFittedTitle(title, enabled, labelRef, titleRef, /** 右对齐区(状态 / 时间),量宽预留 */
|
|
23
29
|
trailingRef, /** 紧跟标题的类型 icon,量宽预留 */
|
|
@@ -27,7 +33,7 @@ typeIconRef) {
|
|
|
27
33
|
fitted = _useState2[0],
|
|
28
34
|
setFitted = _useState2[1];
|
|
29
35
|
useLayoutEffect(function () {
|
|
30
|
-
var _document$fonts;
|
|
36
|
+
var _document$fonts, _label$closest;
|
|
31
37
|
if (!enabled) {
|
|
32
38
|
setFitted(title);
|
|
33
39
|
return;
|
|
@@ -36,6 +42,10 @@ typeIconRef) {
|
|
|
36
42
|
var titleEl = titleRef.current;
|
|
37
43
|
if (!label || !titleEl) return;
|
|
38
44
|
var cancelled = false;
|
|
45
|
+
var rafId = 0;
|
|
46
|
+
var lastMaxWidth = Number.NaN;
|
|
47
|
+
var lastTrailingWidth = Number.NaN;
|
|
48
|
+
var lastFitted = '';
|
|
39
49
|
var probe = document.createElement('span');
|
|
40
50
|
probe.setAttribute('aria-hidden', 'true');
|
|
41
51
|
probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none;white-space:nowrap;left:-9999px;top:0;';
|
|
@@ -67,39 +77,53 @@ typeIconRef) {
|
|
|
67
77
|
// 标题两侧可能各有一段 gap:title↔type、type/title↔trailing
|
|
68
78
|
var gapCount = (typeWidth > 0 ? 1 : 0) + (trailingWidth > 0 ? 1 : 0);
|
|
69
79
|
var maxWidth = Math.max(0, label.getBoundingClientRect().width - trailingWidth - typeWidth - gap * gapCount);
|
|
70
|
-
if (
|
|
71
|
-
setFitted(title);
|
|
80
|
+
if (Number.isFinite(lastMaxWidth) && Math.abs(maxWidth - lastMaxWidth) < FIT_WIDTH_EPS && Math.abs(trailingWidth - lastTrailingWidth) < FIT_WIDTH_EPS) {
|
|
72
81
|
return;
|
|
73
82
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
var
|
|
77
|
-
|
|
78
|
-
var
|
|
79
|
-
var
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
lastMaxWidth = maxWidth;
|
|
84
|
+
lastTrailingWidth = trailingWidth;
|
|
85
|
+
var next = title;
|
|
86
|
+
if (measure(title) > maxWidth + FIT_WIDTH_EPS) {
|
|
87
|
+
var lo = 0;
|
|
88
|
+
var hi = title.length;
|
|
89
|
+
next = ELLIPSIS;
|
|
90
|
+
while (lo <= hi) {
|
|
91
|
+
var mid = lo + hi >> 1;
|
|
92
|
+
var candidate = "".concat(title.slice(0, mid)).concat(ELLIPSIS);
|
|
93
|
+
if (measure(candidate) <= maxWidth + FIT_WIDTH_EPS) {
|
|
94
|
+
next = candidate;
|
|
95
|
+
lo = mid + 1;
|
|
96
|
+
} else {
|
|
97
|
+
hi = mid - 1;
|
|
98
|
+
}
|
|
85
99
|
}
|
|
86
100
|
}
|
|
87
|
-
|
|
101
|
+
if (next === lastFitted) return;
|
|
102
|
+
lastFitted = next;
|
|
103
|
+
setFitted(next);
|
|
104
|
+
};
|
|
105
|
+
var scheduleFit = function scheduleFit() {
|
|
106
|
+
if (cancelled || rafId) return;
|
|
107
|
+
rafId = window.requestAnimationFrame(function () {
|
|
108
|
+
rafId = 0;
|
|
109
|
+
fit();
|
|
110
|
+
});
|
|
88
111
|
};
|
|
112
|
+
|
|
113
|
+
// 首屏同步裁切,避免首帧闪全标题;后续宽度变化走 rAF 合并
|
|
89
114
|
fit();
|
|
90
115
|
void ((_document$fonts = document.fonts) === null || _document$fonts === void 0 ? void 0 : _document$fonts.ready.then(function () {
|
|
91
|
-
if (
|
|
116
|
+
if (cancelled) return;
|
|
117
|
+
// 字体就绪后字形宽度可能变,需绕过 maxWidth 缓存强制重测
|
|
118
|
+
lastMaxWidth = Number.NaN;
|
|
119
|
+
scheduleFit();
|
|
92
120
|
}));
|
|
93
|
-
var
|
|
94
|
-
ro
|
|
95
|
-
|
|
96
|
-
if (trailing) ro.observe(trailing);
|
|
97
|
-
var typeIcon = typeIconRef.current;
|
|
98
|
-
if (typeIcon) ro.observe(typeIcon);
|
|
99
|
-
var btn = label.closest('[data-odn-chat-item-btn]');
|
|
100
|
-
if (btn) ro.observe(btn);
|
|
121
|
+
var row = (_label$closest = label.closest('[data-odn-chat-item-btn]')) !== null && _label$closest !== void 0 ? _label$closest : label;
|
|
122
|
+
var ro = new ResizeObserver(scheduleFit);
|
|
123
|
+
ro.observe(row);
|
|
101
124
|
return function () {
|
|
102
125
|
cancelled = true;
|
|
126
|
+
if (rafId) window.cancelAnimationFrame(rafId);
|
|
103
127
|
ro.disconnect();
|
|
104
128
|
probe.remove();
|
|
105
129
|
};
|
|
@@ -219,7 +243,7 @@ export function ChatItem(_ref2) {
|
|
|
219
243
|
var showStatus = Boolean(status && (!active || status === 'generating' || status === 'waiting'));
|
|
220
244
|
var showTypeIcon = type === 'human';
|
|
221
245
|
var timeLabel = useMemo(function () {
|
|
222
|
-
return time
|
|
246
|
+
return time === null || time === undefined ? '' : formatRelativeTime(time, now);
|
|
223
247
|
}, [time, now]);
|
|
224
248
|
var showTime = Boolean(timeLabel);
|
|
225
249
|
var showTrailing = showStatus || showTime;
|
|
@@ -240,7 +264,7 @@ export function ChatItem(_ref2) {
|
|
|
240
264
|
|
|
241
265
|
// 相对时间每分钟刷新一次(有 time 时)
|
|
242
266
|
useEffect(function () {
|
|
243
|
-
if (time
|
|
267
|
+
if (time === null || time === undefined) return;
|
|
244
268
|
var id = window.setInterval(function () {
|
|
245
269
|
return setNow(Date.now());
|
|
246
270
|
}, 60000);
|