one-design-next 0.0.76 → 0.0.78

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.
@@ -1,4 +1,6 @@
1
1
  import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
2
+ import { resolveMentionCategoryIcon } from "../_genui-inline-ref";
3
+ import Icon from "../icon";
2
4
  import Popover from "../popover";
3
5
  import "./style";
4
6
  function formatPayloadSummary(payload) {
@@ -6,7 +8,7 @@ function formatPayloadSummary(payload) {
6
8
  var entries = Object.entries(payload).filter(function (_ref) {
7
9
  var _ref2 = _slicedToArray(_ref, 2),
8
10
  v = _ref2[1];
9
- return v != null && v !== '';
11
+ return v !== null && v !== undefined && v !== '';
10
12
  });
11
13
  if (entries.length === 0) return null;
12
14
  return entries.map(function (_ref3) {
@@ -16,16 +18,50 @@ function formatPayloadSummary(payload) {
16
18
  return "".concat(k, ": ").concat(String(v));
17
19
  }).join(' · ');
18
20
  }
19
- export function Mention(_ref5) {
21
+ function MentionPopoverTitle(_ref5) {
22
+ var label = _ref5.label,
23
+ icon = _ref5.icon;
24
+ return /*#__PURE__*/React.createElement("div", {
25
+ "data-odn-mention-popover-title": true
26
+ }, /*#__PURE__*/React.createElement("span", {
27
+ "data-odn-mention-popover-at": true,
28
+ "aria-hidden": true
29
+ }, "@"), icon ? /*#__PURE__*/React.createElement("span", {
30
+ "data-odn-mention-icon": true
31
+ }, /*#__PURE__*/React.createElement(Icon, {
32
+ name: icon,
33
+ size: 12
34
+ })) : null, label);
35
+ }
36
+ function MentionHoverPopup(_ref6) {
37
+ var label = _ref6.label,
38
+ icon = _ref6.icon,
39
+ summary = _ref6.summary;
40
+ return /*#__PURE__*/React.createElement("div", {
41
+ "data-odn-mention-popover-inner": true
42
+ }, /*#__PURE__*/React.createElement(MentionPopoverTitle, {
43
+ label: label,
44
+ icon: icon
45
+ }), summary ? /*#__PURE__*/React.createElement("div", {
46
+ "data-odn-mention-popover-summary": true
47
+ }, summary) : /*#__PURE__*/React.createElement("div", {
48
+ "data-odn-mention-popover-empty": true
49
+ }, "\u672A\u586B\u53C2\u6570"));
50
+ }
51
+ export function Mention(_ref7) {
20
52
  var _data$state;
21
- var data = _ref5.data,
22
- _ref5$interactive = _ref5.interactive,
23
- interactive = _ref5$interactive === void 0 ? false : _ref5$interactive,
24
- _ref5$active = _ref5.active,
25
- active = _ref5$active === void 0 ? false : _ref5$active,
26
- onClick = _ref5.onClick;
53
+ var data = _ref7.data,
54
+ _ref7$interactive = _ref7.interactive,
55
+ interactive = _ref7$interactive === void 0 ? false : _ref7$interactive,
56
+ _ref7$active = _ref7.active,
57
+ active = _ref7$active === void 0 ? false : _ref7$active,
58
+ onClick = _ref7.onClick;
27
59
  var clickable = interactive && !!onClick;
28
60
  var state = active ? 'active' : (_data$state = data.state) !== null && _data$state !== void 0 ? _data$state : 'complete';
61
+ var categoryIcon = resolveMentionCategoryIcon(data.kind, data.icon);
62
+ var summary = formatPayloadSummary(data.payload);
63
+ var hasHoverPopup = !interactive && (!!summary || data.state === 'pending');
64
+ var hoverable = clickable || hasHoverPopup;
29
65
  var handleClick = clickable ? function (e) {
30
66
  e.preventDefault();
31
67
  e.stopPropagation();
@@ -39,17 +75,21 @@ export function Mention(_ref5) {
39
75
  "data-odn-mention": true,
40
76
  "data-state": state,
41
77
  "data-clickable": clickable || undefined,
78
+ "data-hoverable": hoverable || undefined,
42
79
  onClick: handleClick,
43
80
  onMouseDown: handleMouseDown
44
81
  }, /*#__PURE__*/React.createElement("span", {
45
82
  "data-odn-mention-at": true,
46
83
  "aria-hidden": true
47
- }, "@"), /*#__PURE__*/React.createElement("span", {
84
+ }, "@"), categoryIcon ? /*#__PURE__*/React.createElement("span", {
85
+ "data-odn-mention-icon": true
86
+ }, /*#__PURE__*/React.createElement(Icon, {
87
+ name: categoryIcon,
88
+ size: 14
89
+ })) : null, /*#__PURE__*/React.createElement("span", {
48
90
  "data-odn-mention-label": true
49
91
  }, data.label));
50
- if (interactive) return core;
51
- var summary = formatPayloadSummary(data.payload);
52
- if (!summary && data.state !== 'pending') return core;
92
+ if (!hasHoverPopup) return core;
53
93
  return /*#__PURE__*/React.createElement(Popover, {
54
94
  trigger: "hover",
55
95
  placement: "top",
@@ -59,30 +99,9 @@ export function Mention(_ref5) {
59
99
  mouseLeaveDelay: 0.1,
60
100
  popup: /*#__PURE__*/React.createElement(MentionHoverPopup, {
61
101
  label: data.label,
102
+ icon: categoryIcon,
62
103
  summary: summary
63
104
  })
64
105
  }, core);
65
106
  }
66
- function MentionHoverPopup(_ref6) {
67
- var label = _ref6.label,
68
- summary = _ref6.summary;
69
- return /*#__PURE__*/React.createElement("div", {
70
- "data-odn-mention-popover-inner": true
71
- }, /*#__PURE__*/React.createElement(MentionPopoverTitle, {
72
- label: label
73
- }), summary ? /*#__PURE__*/React.createElement("div", {
74
- "data-odn-mention-popover-summary": true
75
- }, summary) : /*#__PURE__*/React.createElement("div", {
76
- "data-odn-mention-popover-empty": true
77
- }, "\u672A\u586B\u53C2\u6570"));
78
- }
79
- function MentionPopoverTitle(_ref7) {
80
- var label = _ref7.label;
81
- return /*#__PURE__*/React.createElement("div", {
82
- "data-odn-mention-popover-title": true
83
- }, /*#__PURE__*/React.createElement("span", {
84
- "data-odn-mention-popover-at": true,
85
- "aria-hidden": true
86
- }, "@"), label);
87
- }
88
107
  export default Mention;
@@ -1,15 +1,33 @@
1
+ @charset "UTF-8";
2
+ /* Invocation / Mention 完成后 chip 共用皮:默认无底 + 品牌色字 + 品类 icon
3
+ *
4
+ * 必须是 inline,不能是 inline-flex / inline-block。
5
+ * 蓝字要和旁边正文走同一条基线、同一套行高;做成独立盒子后,
6
+ * 内部文字基线永远对不齐(1em 盒子贴基线时,字在盒子里还会再上浮一截)。
7
+ */
1
8
  [data-odn-mention] {
2
- display: inline-flex;
3
- align-items: center;
9
+ display: inline;
10
+ vertical-align: baseline;
4
11
  white-space: nowrap;
5
12
  word-break: keep-all;
6
13
  overflow-wrap: normal;
7
14
  margin: 0;
8
- padding: 0;
9
- border-radius: 0;
10
- background: transparent;
15
+ padding: 0 4px;
16
+ border-radius: 4px;
17
+ --odn-inline-ref-bg: transparent;
18
+ --odn-inline-ref-bg-hover: color-mix(
19
+ in srgb,
20
+ var(--odn-color-brand-6) 12%,
21
+ transparent
22
+ );
23
+ --odn-inline-ref-bg-active: color-mix(
24
+ in srgb,
25
+ var(--odn-color-brand-6) 16%,
26
+ transparent
27
+ );
28
+ background: var(--odn-inline-ref-bg);
11
29
  color: var(--odn-color-brand-7, var(--odn-color-brand-6));
12
- font-weight: 500;
30
+ font-weight: 400;
13
31
  font-size: 14px;
14
32
  line-height: 24px;
15
33
  cursor: default;
@@ -20,10 +38,11 @@
20
38
  [data-odn-mention][data-state=pending] {
21
39
  color: color-mix(in srgb, var(--odn-color-brand-7, var(--odn-color-brand-6)) 60%, transparent);
22
40
  }
23
- [data-odn-mention][data-state=active], [data-odn-mention]:hover {
24
- background: color-mix(in srgb, var(--odn-color-brand-6) 12%, transparent);
41
+ [data-odn-mention][data-hoverable]:hover {
42
+ background: var(--odn-inline-ref-bg-hover);
25
43
  }
26
44
  [data-odn-mention][data-state=active] {
45
+ background: var(--odn-inline-ref-bg-active);
27
46
  border-bottom: none;
28
47
  }
29
48
  [data-odn-mention][data-clickable] {
@@ -32,12 +51,29 @@
32
51
 
33
52
  [data-odn-mention-at] {
34
53
  opacity: 0.7;
54
+ margin-inline-end: 2px;
35
55
  }
36
56
 
37
57
  [data-odn-mention][data-state=pending] [data-odn-mention-at] {
38
58
  opacity: 1;
39
59
  }
40
60
 
61
+ [data-odn-mention-icon] {
62
+ display: inline-block;
63
+ width: 1em;
64
+ height: 1em;
65
+ margin-inline-end: 2px;
66
+ /* 1em SVG 贴基线会整块落在字的上方,下移与汉字视觉中心对齐 */
67
+ vertical-align: -0.15em;
68
+ line-height: 0;
69
+ color: inherit;
70
+ }
71
+ [data-odn-mention-icon] :where(svg) {
72
+ display: block;
73
+ width: 100%;
74
+ height: 100%;
75
+ }
76
+
41
77
  [data-odn-mention-popover-inner] {
42
78
  display: flex;
43
79
  flex-direction: column;
@@ -47,8 +83,8 @@
47
83
  [data-odn-mention-popover-title] {
48
84
  display: inline-flex;
49
85
  align-items: center;
50
- gap: 1px;
51
- font-weight: 500;
86
+ gap: 2px;
87
+ font-weight: 400;
52
88
  color: var(--odn-color-brand-7, var(--odn-color-brand-6));
53
89
  }
54
90
 
@@ -62,8 +98,8 @@
62
98
  align-self: flex-start;
63
99
  padding: 2px 6px;
64
100
  border-radius: 4px;
65
- background: color-mix(in srgb, var(--odn-color-brand-6) 10%, transparent);
66
- color: var(--odn-color-brand-7, var(--odn-color-brand-6));
101
+ background: var(--odn-color-black-4);
102
+ color: var(--odn-color-solid-black-10);
67
103
  font-size: 12px;
68
104
  line-height: 1.4;
69
105
  }
@@ -1,7 +1,10 @@
1
1
  /// <reference types="react" />
2
2
  import type { PreviewTab } from '../_genui-types';
3
+ import { type ArtifactFileIconType } from '../artifact';
3
4
  import './style';
4
5
  export interface PreviewPanelActionTooltips {
6
+ /** "分享"按钮的 tooltip 文案 */
7
+ share?: React.ReactNode;
5
8
  /** "在浏览器打开"按钮的 tooltip 文案 */
6
9
  openInBrowser?: React.ReactNode;
7
10
  /** "下载"按钮的 tooltip 文案 */
@@ -13,12 +16,29 @@ export interface PreviewPanelActionTooltips {
13
16
  /** "收起预览"按钮的 tooltip 文案 */
14
17
  closeAll?: React.ReactNode;
15
18
  }
19
+ /** Header menuIcon 展开列表中的产物项(通常来自当前对话)。 */
20
+ export interface PreviewPanelArtifact {
21
+ id: string;
22
+ title: string;
23
+ fileType?: ArtifactFileIconType;
24
+ status?: 'Generating' | 'Done' | (string & NonNullable<unknown>);
25
+ }
16
26
  export interface PreviewPanelProps {
17
27
  tabs: PreviewTab[];
18
28
  activeTabId?: string | null;
19
29
  onTabChange?: (id: string) => void;
20
30
  onTabClose?: (id: string) => void;
21
31
  onCloseAll?: () => void;
32
+ /**
33
+ * 当前对话的全部产物。传入后 menuIcon 列表以 Artifact Small 呈现;
34
+ * 未传时回退为当前已打开的 `tabs`(向后兼容)。
35
+ */
36
+ artifacts?: PreviewPanelArtifact[];
37
+ /**
38
+ * 点击产物列表项。调用方按 `getArtifactAction(fileType)`:
39
+ * 可预览 → 打开 / 切换预览;不可预览 → 下载。
40
+ */
41
+ onArtifactOpen?: (artifact: PreviewPanelArtifact) => void;
22
42
  /**
23
43
  * 下载当前激活标签。传入时在 header 右侧渲染下载按钮,点击时回调会收到当前激活 tab;
24
44
  * 未传则不渲染下载按钮(向后兼容)。
@@ -28,6 +48,11 @@ export interface PreviewPanelProps {
28
48
  * 在浏览器中打开当前激活标签。未传时使用默认实现(Blob URL + window.open)。
29
49
  */
30
50
  onOpenInBrowser?: (tab: PreviewTab) => void;
51
+ /**
52
+ * 分享当前激活标签(产物)。未传时默认复制带 `preview` 查询参数的当前页链接,
53
+ * 并 toast「已复制产物链接」。
54
+ */
55
+ onShare?: (tab: PreviewTab) => void;
31
56
  /**
32
57
  * 是否全屏。配合 `onFullscreenChange` 使用;传入回调时 header 渲染全屏/取消全屏按钮。
33
58
  */
@@ -54,7 +79,7 @@ export interface PreviewPanelProps {
54
79
  */
55
80
  actionTooltips?: PreviewPanelActionTooltips;
56
81
  }
57
- export declare function PreviewPanel({ tabs, activeTabId, onTabChange, onTabClose, onCloseAll, onDownload, onOpenInBrowser, fullscreen, onFullscreenChange, open, emptyTitle, emptyDescription, widthMode, actionTooltips, }: PreviewPanelProps): import("react").JSX.Element;
82
+ export declare function PreviewPanel({ tabs, activeTabId, onTabChange, onTabClose, onCloseAll, artifacts, onArtifactOpen, onDownload, onOpenInBrowser, onShare, fullscreen, onFullscreenChange, open, emptyTitle, emptyDescription, widthMode, actionTooltips, }: PreviewPanelProps): import("react").JSX.Element;
58
83
  export declare namespace PreviewPanel {
59
84
  var displayName: string;
60
85
  }
@@ -3,8 +3,10 @@ import _extends from "@babel/runtime/helpers/esm/extends";
3
3
  import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
4
4
  var _excluded = ["tooltip"];
5
5
  import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
6
+ import Artifact, { ARTIFACT_DEDICATED_FILE_ICON_TYPES, ArtifactFileIcon, getArtifactAction } from "../artifact";
6
7
  import Button from "../button";
7
8
  import Icon from "../icon";
9
+ import { Message } from "../message";
8
10
  import { OdnOverlayVerticalScrollbar, useOverlayScrollbarReveal } from "../overlay-vertical-scrollbar";
9
11
  import Popover from "../popover";
10
12
  import StreamText from "../stream-text";
@@ -12,6 +14,45 @@ import Tooltip from "../tooltip";
12
14
  import { CsvPreviewTable } from "./CsvPreviewTable";
13
15
  import { isCsvTab, parseCsv } from "./parseCsv";
14
16
  import "./style";
17
+
18
+ /** Header menuIcon 展开列表中的产物项(通常来自当前对话)。 */
19
+
20
+ function inferArtifactFileType(title) {
21
+ var _title$split$pop;
22
+ var ext = title.includes('.') ? (_title$split$pop = title.split('.').pop()) === null || _title$split$pop === void 0 ? void 0 : _title$split$pop.toLowerCase() : undefined;
23
+ if (ext && ARTIFACT_DEDICATED_FILE_ICON_TYPES.includes(ext)) {
24
+ return ext;
25
+ }
26
+ return 'file';
27
+ }
28
+
29
+ /** 与 Artifact Small 相同的主名中间省略(保留后四位 + 扩展名)。 */
30
+ var TAB_TITLE_NAME_TAIL_KEEP = 4;
31
+ function splitTabTitleParts(title) {
32
+ var lastDot = title.lastIndexOf('.');
33
+ var name = title;
34
+ var extension = null;
35
+ if (lastDot > 0 && lastDot < title.length - 1) {
36
+ var ext = title.slice(lastDot);
37
+ if (ext.length <= 6) {
38
+ name = title.slice(0, lastDot);
39
+ extension = ext;
40
+ }
41
+ }
42
+ if (name.length <= TAB_TITLE_NAME_TAIL_KEEP) {
43
+ return {
44
+ head: name,
45
+ tail: null,
46
+ extension: extension
47
+ };
48
+ }
49
+ return {
50
+ head: name.slice(0, -TAB_TITLE_NAME_TAIL_KEEP),
51
+ tail: name.slice(-TAB_TITLE_NAME_TAIL_KEEP),
52
+ extension: extension
53
+ };
54
+ }
55
+
15
56
  /** 内部辅助:有 tooltip 文案时包裹 Tooltip,否则仅渲染按钮 */
16
57
  function ActionButton(_ref) {
17
58
  var tooltip = _ref.tooltip,
@@ -35,8 +76,11 @@ export function PreviewPanel(_ref2) {
35
76
  onTabChange = _ref2.onTabChange,
36
77
  onTabClose = _ref2.onTabClose,
37
78
  onCloseAll = _ref2.onCloseAll,
79
+ artifacts = _ref2.artifacts,
80
+ onArtifactOpen = _ref2.onArtifactOpen,
38
81
  onDownload = _ref2.onDownload,
39
82
  onOpenInBrowser = _ref2.onOpenInBrowser,
83
+ onShare = _ref2.onShare,
40
84
  _ref2$fullscreen = _ref2.fullscreen,
41
85
  fullscreen = _ref2$fullscreen === void 0 ? false : _ref2$fullscreen,
42
86
  onFullscreenChange = _ref2.onFullscreenChange,
@@ -53,6 +97,17 @@ export function PreviewPanel(_ref2) {
53
97
  })) !== null && _tabs$find !== void 0 ? _tabs$find : tabs[0]) !== null && _ref3 !== void 0 ? _ref3 : null;
54
98
  var isOpen = open !== null && open !== void 0 ? open : tabs.length > 0;
55
99
  var isEmpty = tabs.length === 0;
100
+ var menuArtifacts = useMemo(function () {
101
+ if (artifacts && artifacts.length > 0) return artifacts;
102
+ return tabs.map(function (tab) {
103
+ return {
104
+ id: tab.id,
105
+ title: tab.name,
106
+ fileType: inferArtifactFileType(tab.name)
107
+ };
108
+ });
109
+ }, [artifacts, tabs]);
110
+ var showArtifactsMenu = menuArtifacts.length > 0;
56
111
  var previewScrollRef = useRef(null);
57
112
  var tabsScrollRef = useRef(null);
58
113
  var _useState = useState({
@@ -147,6 +202,34 @@ export function PreviewPanel(_ref2) {
147
202
  return URL.revokeObjectURL(url);
148
203
  }, 60000);
149
204
  };
205
+ var handleShare = function handleShare() {
206
+ var _navigator$clipboard;
207
+ if (!activeTab) return;
208
+ if (onShare) {
209
+ onShare(activeTab);
210
+ return;
211
+ }
212
+ var shareUrl = new URL(window.location.href);
213
+ shareUrl.searchParams.set('preview', activeTab.id);
214
+ var text = shareUrl.toString();
215
+ var onOk = function onOk() {
216
+ return Message.success({
217
+ content: '已复制产物链接',
218
+ duration: 1.5
219
+ });
220
+ };
221
+ var onFail = function onFail() {
222
+ return Message.info({
223
+ content: '复制失败,请手动分享产物链接',
224
+ duration: 2
225
+ });
226
+ };
227
+ if ((_navigator$clipboard = navigator.clipboard) !== null && _navigator$clipboard !== void 0 && _navigator$clipboard.writeText) {
228
+ navigator.clipboard.writeText(text).then(onOk).catch(onFail);
229
+ } else {
230
+ onFail();
231
+ }
232
+ };
150
233
  return /*#__PURE__*/React.createElement("div", {
151
234
  "data-odn-preview-panel": true,
152
235
  "data-odn-preview-panel-open": isOpen || undefined,
@@ -157,7 +240,7 @@ export function PreviewPanel(_ref2) {
157
240
  "data-odn-preview-panel-header": true
158
241
  }, /*#__PURE__*/React.createElement("div", {
159
242
  "data-odn-preview-panel-tabs-rail": true
160
- }, !isEmpty && /*#__PURE__*/React.createElement(Popover, {
243
+ }, showArtifactsMenu && /*#__PURE__*/React.createElement(Popover, {
161
244
  trigger: "hover",
162
245
  placement: "bottomLeft",
163
246
  arrowed: false,
@@ -165,33 +248,37 @@ export function PreviewPanel(_ref2) {
165
248
  mouseLeaveDelay: 0.15,
166
249
  zIndex: 1100,
167
250
  popupStyle: {
168
- padding: 4,
169
- minWidth: 200,
251
+ padding: 8,
252
+ minWidth: 220,
170
253
  maxWidth: 320
171
254
  },
172
255
  popup: /*#__PURE__*/React.createElement("div", {
173
256
  "data-odn-preview-panel-tabs-menu": true,
174
257
  role: "listbox",
175
258
  "aria-label": "\u5168\u90E8\u4EA7\u7269"
176
- }, tabs.map(function (tab) {
177
- var isActive = tab.id === (activeTab === null || activeTab === void 0 ? void 0 : activeTab.id);
178
- return /*#__PURE__*/React.createElement("button", {
179
- key: tab.id,
180
- type: "button",
259
+ }, menuArtifacts.map(function (item) {
260
+ var _item$fileType;
261
+ var isActive = item.id === (activeTab === null || activeTab === void 0 ? void 0 : activeTab.id);
262
+ return /*#__PURE__*/React.createElement("div", {
263
+ key: item.id,
181
264
  role: "option",
182
265
  "aria-selected": isActive,
183
266
  "data-odn-preview-panel-tabs-menu-item": true,
184
- "data-odn-preview-panel-tabs-menu-item-active": isActive || undefined,
185
- onClick: function onClick() {
186
- return onTabChange === null || onTabChange === void 0 ? void 0 : onTabChange(tab.id);
187
- }
188
- }, /*#__PURE__*/React.createElement(Icon, {
189
- name: "file-text",
190
- size: 14,
191
- "data-odn-preview-panel-tabs-menu-item-icon": true
192
- }), /*#__PURE__*/React.createElement("span", {
193
- "data-odn-preview-panel-tabs-menu-item-name": true
194
- }, tab.name));
267
+ "data-odn-preview-panel-tabs-menu-item-active": isActive || undefined
268
+ }, /*#__PURE__*/React.createElement(Artifact, {
269
+ size: "small",
270
+ title: item.title,
271
+ actionKind: getArtifactAction((_item$fileType = item.fileType) !== null && _item$fileType !== void 0 ? _item$fileType : 'file').kind,
272
+ fileType: item.fileType,
273
+ status: item.status,
274
+ onOpen: onArtifactOpen || onTabChange ? function () {
275
+ if (onArtifactOpen) {
276
+ onArtifactOpen(item);
277
+ return;
278
+ }
279
+ onTabChange === null || onTabChange === void 0 || onTabChange(item.id);
280
+ } : undefined
281
+ }));
195
282
  }))
196
283
  }, /*#__PURE__*/React.createElement(Button, {
197
284
  light: true,
@@ -216,12 +303,21 @@ export function PreviewPanel(_ref2) {
216
303
  role: "tablist",
217
304
  "aria-label": "\u9884\u89C8\u6807\u7B7E"
218
305
  }, tabs.map(function (tab) {
306
+ var _artifacts$find$fileT, _artifacts$find;
219
307
  var isActive = tab.id === (activeTab === null || activeTab === void 0 ? void 0 : activeTab.id);
308
+ var fileType = (_artifacts$find$fileT = artifacts === null || artifacts === void 0 || (_artifacts$find = artifacts.find(function (item) {
309
+ return item.id === tab.id;
310
+ })) === null || _artifacts$find === void 0 ? void 0 : _artifacts$find.fileType) !== null && _artifacts$find$fileT !== void 0 ? _artifacts$find$fileT : inferArtifactFileType(tab.name);
311
+ var _splitTabTitleParts = splitTabTitleParts(tab.name),
312
+ titleHead = _splitTabTitleParts.head,
313
+ titleTail = _splitTabTitleParts.tail,
314
+ titleExtension = _splitTabTitleParts.extension;
220
315
  return /*#__PURE__*/React.createElement("div", {
221
316
  key: tab.id,
222
317
  role: "tab",
223
318
  tabIndex: isActive ? 0 : -1,
224
319
  "aria-selected": isActive,
320
+ title: tab.name,
225
321
  onClick: function onClick() {
226
322
  return onTabChange === null || onTabChange === void 0 ? void 0 : onTabChange(tab.id);
227
323
  },
@@ -233,13 +329,21 @@ export function PreviewPanel(_ref2) {
233
329
  },
234
330
  "data-odn-preview-panel-tab": true,
235
331
  "data-odn-preview-panel-tab-active": isActive || undefined
236
- }, /*#__PURE__*/React.createElement(Icon, {
237
- name: "file-text",
238
- size: 14,
239
- "data-odn-preview-panel-tab-icon": true
240
- }), /*#__PURE__*/React.createElement("span", {
332
+ }, /*#__PURE__*/React.createElement("span", {
333
+ "data-odn-preview-panel-tab-icon": true,
334
+ "aria-hidden": true
335
+ }, /*#__PURE__*/React.createElement(ArtifactFileIcon, {
336
+ type: fileType,
337
+ size: "small"
338
+ })), /*#__PURE__*/React.createElement("span", {
241
339
  "data-odn-preview-panel-tab-name": true
242
- }, tab.name), /*#__PURE__*/React.createElement("button", {
340
+ }, /*#__PURE__*/React.createElement("span", {
341
+ "data-odn-preview-panel-tab-name-head": true
342
+ }, titleHead), titleTail ? /*#__PURE__*/React.createElement("span", {
343
+ "data-odn-preview-panel-tab-name-tail": true
344
+ }, titleTail) : null, titleExtension ? /*#__PURE__*/React.createElement("span", {
345
+ "data-odn-preview-panel-tab-name-ext": true
346
+ }, titleExtension) : null), /*#__PURE__*/React.createElement("button", {
243
347
  type: "button",
244
348
  onClick: function onClick(e) {
245
349
  e.stopPropagation();
@@ -252,7 +356,7 @@ export function PreviewPanel(_ref2) {
252
356
  "aria-label": "\u5173\u95ED\u6807\u7B7E"
253
357
  }, /*#__PURE__*/React.createElement(Icon, {
254
358
  name: "x",
255
- size: 12
359
+ size: 16
256
360
  })));
257
361
  })), showTabScrollButtons && /*#__PURE__*/React.createElement(Button, {
258
362
  light: true,
@@ -267,17 +371,35 @@ export function PreviewPanel(_ref2) {
267
371
  "aria-label": "\u5411\u53F3\u67E5\u770B\u6807\u7B7E"
268
372
  })), /*#__PURE__*/React.createElement("div", {
269
373
  "data-odn-preview-panel-actions": true
270
- }, /*#__PURE__*/React.createElement("div", {
374
+ }, /*#__PURE__*/React.createElement(Tooltip.Group, {
375
+ as: "div",
376
+ placement: "bottom",
271
377
  "data-odn-preview-panel-action-group": true
272
- }, /*#__PURE__*/React.createElement(ActionButton, {
273
- tooltip: actionTooltips === null || actionTooltips === void 0 ? void 0 : actionTooltips.openInBrowser,
378
+ }, /*#__PURE__*/React.createElement(Tooltip, {
379
+ popup: actionTooltips === null || actionTooltips === void 0 ? void 0 : actionTooltips.share
380
+ }, /*#__PURE__*/React.createElement(Button, {
381
+ light: true,
382
+ size: "medium",
383
+ icon: "share-2",
384
+ onClick: handleShare,
385
+ disabled: !activeTab,
386
+ "data-odn-preview-panel-share": true,
387
+ "aria-label": "\u5206\u4EAB\u4EA7\u7269"
388
+ })), /*#__PURE__*/React.createElement(Tooltip, {
389
+ popup: actionTooltips === null || actionTooltips === void 0 ? void 0 : actionTooltips.openInBrowser
390
+ }, /*#__PURE__*/React.createElement(Button, {
391
+ light: true,
392
+ size: "medium",
274
393
  icon: "arrow-up-right",
275
394
  onClick: handleOpenInBrowser,
276
395
  disabled: !activeTab,
277
396
  "data-odn-preview-panel-open-browser": true,
278
397
  "aria-label": "\u5728\u6D4F\u89C8\u5668\u6253\u5F00"
279
- }), onDownload ? /*#__PURE__*/React.createElement(ActionButton, {
280
- tooltip: actionTooltips === null || actionTooltips === void 0 ? void 0 : actionTooltips.download,
398
+ })), onDownload ? /*#__PURE__*/React.createElement(Tooltip, {
399
+ popup: actionTooltips === null || actionTooltips === void 0 ? void 0 : actionTooltips.download
400
+ }, /*#__PURE__*/React.createElement(Button, {
401
+ light: true,
402
+ size: "medium",
281
403
  icon: "download-2",
282
404
  onClick: function onClick() {
283
405
  return activeTab && onDownload(activeTab);
@@ -285,7 +407,7 @@ export function PreviewPanel(_ref2) {
285
407
  disabled: !activeTab,
286
408
  "data-odn-preview-panel-download": true,
287
409
  "aria-label": "\u4E0B\u8F7D"
288
- }) : null), onFullscreenChange || onCloseAll ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
410
+ })) : null), onFullscreenChange || onCloseAll ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("span", {
289
411
  "data-odn-preview-panel-action-divider": true,
290
412
  "aria-hidden": true
291
413
  }), /*#__PURE__*/React.createElement("div", {