one-design-next 0.0.71 → 0.0.73

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.
@@ -17,17 +17,23 @@ var ELLIPSIS = '…';
17
17
 
18
18
  /** 可用宽度变化小于该值时跳过重算(与二分容差同量级) */
19
19
  var FIT_WIDTH_EPS = 0.5;
20
+ /**
21
+ * 可用宽度低于该阈值时视为测量不可靠(布局未完成 / 被瞬时压扁)。
22
+ * 此时保留上一帧可读结果或原文,避免把标题裁成单独的「…」。
23
+ */
24
+ var FIT_MIN_RELIABLE_WIDTH = 24;
20
25
 
21
26
  /**
22
27
  * 有 trailing(客服 icon / status / 时间)时,用 DOM 实测把标题裁到可用宽度。
23
28
  * 解决 CSS text-overflow 按字符边界截断后,省略号右侧留白把 trailing 顶开的问题。
24
29
  *
25
- * 性能:只监听整行(btn)宽度;RO 回调经 rAF 合并(每行每帧最多 fit 一次);
26
- * 缓存 maxWidth / trailingWidth / 裁切结果,宽度几乎不变或结果不变则跳过更新。
30
+ * 性能:RO 监听行 / label / trailing(active 时时间让位不改变行宽,必须听内部);
31
+ * 回调经 rAF 合并;缓存 maxWidth / trailingWidth / 裁切结果。
27
32
  */
28
33
  function useFittedTitle(title, enabled, labelRef, titleRef, /** 右对齐区(状态 / 时间),量宽预留 */
29
34
  trailingRef, /** 紧跟标题的类型 icon,量宽预留 */
30
- typeIconRef) {
35
+ typeIconRef, /** active 时时间让位 / 字重变化,需强制重测 */
36
+ layoutKey) {
31
37
  var _useState = useState(title),
32
38
  _useState2 = _slicedToArray(_useState, 2),
33
39
  fitted = _useState2[0],
@@ -41,11 +47,14 @@ typeIconRef) {
41
47
  var label = labelRef.current;
42
48
  var titleEl = titleRef.current;
43
49
  if (!label || !titleEl) return;
50
+
51
+ // 标题变更时先回到原文,避免沿用上一会话裁成的「…」
52
+ setFitted(title);
44
53
  var cancelled = false;
45
54
  var rafId = 0;
46
55
  var lastMaxWidth = Number.NaN;
47
56
  var lastTrailingWidth = Number.NaN;
48
- var lastFitted = '';
57
+ var lastFitted = title;
49
58
  var probe = document.createElement('span');
50
59
  probe.setAttribute('aria-hidden', 'true');
51
60
  probe.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none;white-space:nowrap;left:-9999px;top:0;';
@@ -80,13 +89,24 @@ typeIconRef) {
80
89
  if (Number.isFinite(lastMaxWidth) && Math.abs(maxWidth - lastMaxWidth) < FIT_WIDTH_EPS && Math.abs(trailingWidth - lastTrailingWidth) < FIT_WIDTH_EPS) {
81
90
  return;
82
91
  }
92
+
93
+ // 布局未就绪时不要写成单独的「…」,否则行宽不变时 RO 不触发会永久卡住
94
+ if (maxWidth < FIT_MIN_RELIABLE_WIDTH) {
95
+ lastMaxWidth = Number.NaN;
96
+ lastTrailingWidth = Number.NaN;
97
+ if (lastFitted !== title) {
98
+ lastFitted = title;
99
+ setFitted(title);
100
+ }
101
+ return;
102
+ }
83
103
  lastMaxWidth = maxWidth;
84
104
  lastTrailingWidth = trailingWidth;
85
105
  var next = title;
86
106
  if (measure(title) > maxWidth + FIT_WIDTH_EPS) {
87
107
  var lo = 0;
88
108
  var hi = title.length;
89
- next = ELLIPSIS;
109
+ next = title;
90
110
  while (lo <= hi) {
91
111
  var mid = lo + hi >> 1;
92
112
  var candidate = "".concat(title.slice(0, mid)).concat(ELLIPSIS);
@@ -97,6 +117,11 @@ typeIconRef) {
97
117
  hi = mid - 1;
98
118
  }
99
119
  }
120
+ // 极端窄宽仍放不下「字+…」时交给 CSS ellipsis,保留原文
121
+ if (next === ELLIPSIS || next === title && measure(title) > maxWidth + FIT_WIDTH_EPS) {
122
+ var withEllipsis = "".concat(title.slice(0, 1)).concat(ELLIPSIS);
123
+ next = measure(withEllipsis) <= maxWidth + FIT_WIDTH_EPS ? withEllipsis : title;
124
+ }
100
125
  }
101
126
  if (next === lastFitted) return;
102
127
  lastFitted = next;
@@ -121,13 +146,18 @@ typeIconRef) {
121
146
  var row = (_label$closest = label.closest('[data-odn-chat-item-btn]')) !== null && _label$closest !== void 0 ? _label$closest : label;
122
147
  var ro = new ResizeObserver(scheduleFit);
123
148
  ro.observe(row);
149
+ ro.observe(label);
150
+ var trailing = trailingRef.current;
151
+ if (trailing) ro.observe(trailing);
152
+ var typeIcon = typeIconRef.current;
153
+ if (typeIcon) ro.observe(typeIcon);
124
154
  return function () {
125
155
  cancelled = true;
126
156
  if (rafId) window.cancelAnimationFrame(rafId);
127
157
  ro.disconnect();
128
158
  probe.remove();
129
159
  };
130
- }, [title, enabled, labelRef, titleRef, trailingRef, typeIconRef]);
160
+ }, [title, enabled, layoutKey, labelRef, titleRef, trailingRef, typeIconRef]);
131
161
  return enabled ? fitted : title;
132
162
  }
133
163
  function ChatItemStatus(_ref) {
@@ -248,7 +278,8 @@ export function ChatItem(_ref2) {
248
278
  var showTime = Boolean(timeLabel);
249
279
  var showTrailing = showStatus || showTime;
250
280
  var fitTitle = showTypeIcon || showTrailing;
251
- var displayTitle = useFittedTitle(title, fitTitle, labelRef, titleRef, trailingRef, typeIconRef);
281
+ var displayTitle = useFittedTitle(title, fitTitle, labelRef, titleRef, trailingRef, typeIconRef, // active / 菜单开合都会改时间让位与字重,行宽可能不变
282
+ "".concat(active ? 1 : 0, ":").concat(menuOpen ? 1 : 0));
252
283
  useEffect(function () {
253
284
  if (!renaming) setDraft(title);
254
285
  }, [title, renaming]);
@@ -300,6 +331,7 @@ export function ChatItem(_ref2) {
300
331
  }] : []));
301
332
  return /*#__PURE__*/React.createElement(HoverFill, {
302
333
  "data-odn-chat-item": true,
334
+ "data-odn-chat-item-id": id,
303
335
  "data-odn-chat-item-pinned": pinned || undefined,
304
336
  bgClassName: "odn-chat-item-btn-bg",
305
337
  disabled: active || renaming
@@ -228,6 +228,12 @@ export interface ComposerProps {
228
228
  * @default image/*,.pdf,...,.7z
229
229
  */
230
230
  accept?: string;
231
+ /**
232
+ * 自定义"格式不支持"提示文案。接收被拒绝的文件扩展名(不含前导点,已大写),
233
+ * 返回用于 Message.warning 的字符串。
234
+ * @default (ext) => `不支持「${ext}」格式`
235
+ */
236
+ fileRejectMessage?: (ext: string) => string;
231
237
  /**
232
238
  * 参数面板内容渲染。提供后 invocation chip 可点击打开面板;
233
239
  * `SkillItem.initialState='pending'` 插入后会自动打开。
@@ -137,6 +137,7 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
137
137
  maxTotalSize = _ref.maxTotalSize,
138
138
  _ref$accept = _ref.accept,
139
139
  accept = _ref$accept === void 0 ? DEFAULT_ACCEPT : _ref$accept,
140
+ fileRejectMessage = _ref.fileRejectMessage,
140
141
  renderParamPanel = _ref.renderParamPanel,
141
142
  onToolClick = _ref.onToolClick,
142
143
  className = _ref.className,
@@ -500,7 +501,8 @@ export var Composer = /*#__PURE__*/forwardRef(function Composer(_ref, ref) {
500
501
  _iterator.f();
501
502
  }
502
503
  if (unsupportedExt) {
503
- Message.warning("\u4E0D\u652F\u6301\u300C".concat(unsupportedExt.replace(/^\./, '').toUpperCase(), "\u300D\u683C\u5F0F"));
504
+ var _ext = unsupportedExt.replace(/^\./, '').toUpperCase();
505
+ Message.warning(fileRejectMessage ? fileRejectMessage(_ext) : "\u4E0D\u652F\u6301\u300C".concat(_ext, "\u300D\u683C\u5F0F"));
504
506
  }
505
507
  if (oversizedName) {
506
508
  Message.warning("\u300C".concat(oversizedName, "\u300D\u8D85\u8FC7 ").concat(formatSizeMb(maxFileSize), "\uFF0C\u8BF7\u538B\u7F29\u540E\u91CD\u8BD5"));
@@ -4,7 +4,7 @@ html {
4
4
  --odn-dialog-footer-padding: 24px;
5
5
  --odn-dialog-footer-gap: 12px;
6
6
  --odn-dialog-footer-justify: flex-end;
7
- --odn-dialog-overlay-background: rgba(0, 0, 0, 0.45);
7
+ --odn-dialog-overlay-background: rgba(0, 0, 0, 0.2);
8
8
  --odn-dialog-border-radius: 10px;
9
9
  --odn-dialog-close-top: 16px;
10
10
  --odn-dialog-close-right: 16px;
@@ -1,6 +1,7 @@
1
1
  @charset "UTF-8";
2
2
  html {
3
3
  --odn-drawer-overlay-background: rgba(0, 0, 0, 0.45);
4
+ --odn-drawer-shadow: var(--odn-shadow-2);
4
5
  --odn-drawer-header-padding-inline: 20px;
5
6
  --odn-drawer-header-height: 64px;
6
7
  --odn-drawer-header-border: 1px solid var(--odn-color-black-4);
@@ -79,6 +80,7 @@ html {
79
80
  display: flex;
80
81
  flex-direction: column;
81
82
  background-color: #fff;
83
+ box-shadow: var(--odn-drawer-shadow);
82
84
  pointer-events: initial;
83
85
  overflow: auto;
84
86
  }
@@ -886,10 +886,13 @@ var Dropdown = function Dropdown(props) {
886
886
  }))));
887
887
  }
888
888
 
889
- // click 模式的默认渲染
889
+ // click 模式:与 hover 一致使用 modal={false}。
890
+ // 默认 modal 会铺内部 backdrop,挂在 Drawer/Dialog 内时菜单项看起来可点但点不中
891
+ //(ChatItem 修改名称 / 置顶 / 删除即踩中此问题)。
890
892
  return /*#__PURE__*/React.createElement(DropdownMenu, {
891
893
  open: disabled ? false : finalOpen,
892
- onOpenChange: handleOpenChange
894
+ onOpenChange: handleOpenChange,
895
+ modal: false
893
896
  }, /*#__PURE__*/React.createElement(DropdownMenuTrigger, {
894
897
  asChild: true,
895
898
  disabled: disabled
@@ -4250,6 +4250,10 @@ export declare const svgData: {
4250
4250
  readonly viewBox: "0 0 24 24";
4251
4251
  readonly content: "<g fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M3 7V5a2 2 0 0 1 2-2h2\"></path><path d=\"M17 3h2a2 2 0 0 1 2 2v2\"></path><path d=\"M21 17v2a2 2 0 0 1-2 2h-2\"></path><path d=\"M7 21H5a2 2 0 0 1-2-2v-2\"></path></g>";
4252
4252
  };
4253
+ readonly 'menu-line': {
4254
+ readonly viewBox: "0 0 24 24";
4255
+ readonly content: "<g fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M4 5h16\"></path><path d=\"M4 12h16\"></path><path d=\"M4 19h16\"></path></g>";
4256
+ };
4253
4257
  readonly 'search-line': {
4254
4258
  readonly viewBox: "0 0 24 24";
4255
4259
  readonly content: "<g fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"11\" cy=\"11\" r=\"8\"></circle><path d=\"m21 21-4.3-4.3\"></path></g>";