one-design-next 0.0.11 → 0.0.13

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.
Files changed (55) hide show
  1. package/dist/_genui-types.d.ts +45 -10
  2. package/dist/attachments/index.js +67 -10
  3. package/dist/attachments/style/index.css +86 -14
  4. package/dist/collapse/primitive.d.ts +1 -1
  5. package/dist/composer/chip.d.ts +4 -4
  6. package/dist/composer/clipboard.d.ts +12 -0
  7. package/dist/composer/clipboard.js +84 -0
  8. package/dist/composer/editor.d.ts +9 -1
  9. package/dist/composer/editor.js +70 -14
  10. package/dist/composer/hooks/useChipManager.d.ts +6 -1
  11. package/dist/composer/hooks/useChipManager.js +76 -27
  12. package/dist/composer/hooks/useChipSelectionMarker.d.ts +7 -0
  13. package/dist/composer/hooks/useChipSelectionMarker.js +66 -0
  14. package/dist/composer/index.d.ts +58 -1
  15. package/dist/composer/index.js +219 -102
  16. package/dist/composer/inline-ref.d.ts +9 -0
  17. package/dist/composer/inline-ref.js +21 -0
  18. package/dist/composer/send-meta.d.ts +6 -0
  19. package/dist/composer/send-meta.js +67 -0
  20. package/dist/composer/style/index.css +48 -53
  21. package/dist/composer/utils.d.ts +9 -0
  22. package/dist/composer/utils.js +43 -2
  23. package/dist/fab/index.js +3 -16
  24. package/dist/fab/style/index.css +1 -3
  25. package/dist/icon/svg-data.d.ts +4 -0
  26. package/dist/icon/svg-data.js +1 -1
  27. package/dist/icon/types.d.ts +1 -1
  28. package/dist/image/index.d.ts +43 -0
  29. package/dist/image/index.js +51 -0
  30. package/dist/image/style/index.css +59 -0
  31. package/dist/image/style/index.d.ts +2 -0
  32. package/dist/image/style/index.js +2 -0
  33. package/dist/index.d.ts +5 -1
  34. package/dist/index.js +4 -0
  35. package/dist/invocation/index.d.ts +17 -0
  36. package/dist/invocation/index.js +84 -0
  37. package/dist/invocation/style/index.css +58 -0
  38. package/dist/invocation/style/index.d.ts +2 -0
  39. package/dist/invocation/style/index.js +2 -0
  40. package/dist/mention/index.d.ts +17 -0
  41. package/dist/mention/index.js +90 -0
  42. package/dist/mention/style/index.css +58 -0
  43. package/dist/mention/style/index.d.ts +2 -0
  44. package/dist/mention/style/index.js +2 -0
  45. package/dist/message-image/index.d.ts +42 -0
  46. package/dist/message-image/index.js +46 -0
  47. package/dist/message-image/style/index.css +60 -0
  48. package/dist/message-image/style/index.d.ts +2 -0
  49. package/dist/message-image/style/index.js +2 -0
  50. package/dist/preview-panel/index.d.ts +5 -1
  51. package/dist/preview-panel/index.js +27 -2
  52. package/dist/user-bubble/index.d.ts +11 -1
  53. package/dist/user-bubble/index.js +30 -5
  54. package/dist/user-bubble/style/index.css +6 -0
  55. package/package.json +2 -3
@@ -0,0 +1,90 @@
1
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
4
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
5
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
6
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
+ import Popover from "../popover";
8
+ import "./style";
9
+ function formatParamsSummary(params) {
10
+ if (!params) return null;
11
+ var entries = Object.entries(params).filter(function (_ref) {
12
+ var _ref2 = _slicedToArray(_ref, 2),
13
+ v = _ref2[1];
14
+ return v != null && v !== '';
15
+ });
16
+ if (entries.length === 0) return null;
17
+ return entries.map(function (_ref3) {
18
+ var _ref4 = _slicedToArray(_ref3, 2),
19
+ k = _ref4[0],
20
+ v = _ref4[1];
21
+ return "".concat(k, ": ").concat(String(v));
22
+ }).join(' · ');
23
+ }
24
+ export function Mention(_ref5) {
25
+ var data = _ref5.data,
26
+ _ref5$interactive = _ref5.interactive,
27
+ interactive = _ref5$interactive === void 0 ? false : _ref5$interactive,
28
+ _ref5$active = _ref5.active,
29
+ active = _ref5$active === void 0 ? false : _ref5$active,
30
+ onClick = _ref5.onClick;
31
+ var clickable = interactive && !!onClick;
32
+ var state = active ? 'active' : 'complete';
33
+ var handleClick = clickable ? function (e) {
34
+ e.preventDefault();
35
+ e.stopPropagation();
36
+ onClick(e.currentTarget);
37
+ } : undefined;
38
+ var handleMouseDown = clickable ? function (e) {
39
+ e.preventDefault();
40
+ e.stopPropagation();
41
+ } : undefined;
42
+ var core = /*#__PURE__*/React.createElement("span", {
43
+ "data-odn-mention": true,
44
+ "data-state": state,
45
+ "data-clickable": clickable || undefined,
46
+ onClick: handleClick,
47
+ onMouseDown: handleMouseDown
48
+ }, /*#__PURE__*/React.createElement("span", {
49
+ "data-odn-mention-at": true,
50
+ "aria-hidden": true
51
+ }, "@"), /*#__PURE__*/React.createElement("span", {
52
+ "data-odn-mention-label": true
53
+ }, data.label));
54
+ if (interactive) return core;
55
+ var summary = formatParamsSummary(data.params);
56
+ if (!summary) return core;
57
+ return /*#__PURE__*/React.createElement(Popover, {
58
+ trigger: "hover",
59
+ placement: "top",
60
+ arrowed: false,
61
+ offset: 6,
62
+ mouseEnterDelay: 0.15,
63
+ mouseLeaveDelay: 0.1,
64
+ popup: /*#__PURE__*/React.createElement(MentionHoverPopup, {
65
+ label: data.label,
66
+ summary: summary
67
+ })
68
+ }, core);
69
+ }
70
+ function MentionHoverPopup(_ref6) {
71
+ var label = _ref6.label,
72
+ summary = _ref6.summary;
73
+ return /*#__PURE__*/React.createElement("div", {
74
+ "data-odn-mention-popover-inner": true
75
+ }, /*#__PURE__*/React.createElement(MentionPopoverTitle, {
76
+ label: label
77
+ }), /*#__PURE__*/React.createElement("div", {
78
+ "data-odn-mention-popover-summary": true
79
+ }, summary));
80
+ }
81
+ function MentionPopoverTitle(_ref7) {
82
+ var label = _ref7.label;
83
+ return /*#__PURE__*/React.createElement("div", {
84
+ "data-odn-mention-popover-title": true
85
+ }, /*#__PURE__*/React.createElement("span", {
86
+ "data-odn-mention-popover-at": true,
87
+ "aria-hidden": true
88
+ }, "@"), label);
89
+ }
90
+ export default Mention;
@@ -0,0 +1,58 @@
1
+ [data-odn-mention] {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ white-space: nowrap;
5
+ word-break: keep-all;
6
+ overflow-wrap: normal;
7
+ margin: 0;
8
+ padding: 0 4px;
9
+ border-radius: 6px;
10
+ background: transparent;
11
+ color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
12
+ font-weight: 500;
13
+ font-size: inherit;
14
+ line-height: inherit;
15
+ cursor: default;
16
+ user-select: none;
17
+ -webkit-user-select: none;
18
+ transition: background-color 0.15s;
19
+ }
20
+ [data-odn-mention][data-state=active], [data-odn-mention]:hover {
21
+ background: color-mix(in srgb, var(--odn-color-cyan-5) 12%, transparent);
22
+ }
23
+ [data-odn-mention][data-clickable] {
24
+ cursor: pointer;
25
+ }
26
+
27
+ [data-odn-mention-at] {
28
+ opacity: 0.7;
29
+ }
30
+
31
+ [data-odn-mention-popover-inner] {
32
+ display: flex;
33
+ flex-direction: column;
34
+ gap: 6px;
35
+ }
36
+
37
+ [data-odn-mention-popover-title] {
38
+ display: inline-flex;
39
+ align-items: center;
40
+ gap: 1px;
41
+ font-weight: 500;
42
+ color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
43
+ }
44
+
45
+ [data-odn-mention-popover-at] {
46
+ opacity: 0.7;
47
+ }
48
+
49
+ [data-odn-mention-popover-summary] {
50
+ display: inline-block;
51
+ align-self: flex-start;
52
+ padding: 2px 6px;
53
+ border-radius: 4px;
54
+ background: color-mix(in srgb, var(--odn-color-cyan-5) 10%, transparent);
55
+ color: var(--odn-color-cyan-6, var(--odn-color-cyan-5));
56
+ font-size: 12px;
57
+ line-height: 1.4;
58
+ }
@@ -0,0 +1,2 @@
1
+ import '../../style';
2
+ import './index.scss';
@@ -0,0 +1,2 @@
1
+ import "../../style";
2
+ import "./index.css";
@@ -0,0 +1,42 @@
1
+ /// <reference types="react" />
2
+ import './style';
3
+ /**
4
+ * MessageImage 渲染的图片项。
5
+ * 与 `Attachment` 不同:图片消息的「主体」就是图本身,不需要 name / type / size 等
6
+ * 文件元信息——展示文件名只会变成 `/qidian/im/image/3c87...` 这种对用户无意义的服务端路径。
7
+ */
8
+ export interface MessageImageItem {
9
+ url: string;
10
+ alt?: string;
11
+ }
12
+ export interface MessageImageProps {
13
+ /** 待渲染的图片列表。 */
14
+ images: MessageImageItem[];
15
+ /**
16
+ * 点击图片回调,传入图片 index。组件不内置大图查看器,业务方按需对接
17
+ * `PreviewPanel` / 自己实现的 lightbox。
18
+ */
19
+ onPreview?: (index: number) => void;
20
+ /**
21
+ * 删除按钮点击回调,传入图片 index。本期 MessageImage 主要承载消息态展示,
22
+ * 该回调主要为未来扩展(如撤回未发送消息中的图)保留。
23
+ */
24
+ onRemove?: (index: number) => void;
25
+ }
26
+ /**
27
+ * 用户消息中的图片附件渲染组件——`Image` leaf 之上的「消息态」语义包装。
28
+ *
29
+ * 两态:
30
+ * - 单图:数据驱动尺寸,max 280×360 contain,保留原图长宽比
31
+ * - 多图:模板驱动尺寸,每张 88×88 cover,横向 flex + wrap
32
+ * 与单图差异化是为了多图场景下「整齐成组」比「逐张完整」更重要——
33
+ * 业界共识(微信 / iMessage / Telegram 多图均为统一缩略 + 点开看大图)
34
+ *
35
+ * Composer 待发送态等其他场景**不应消费此组件**——那是输入态语义,
36
+ * 应直接用 `Image` leaf + 自己的尺寸 wrap。
37
+ */
38
+ export declare function MessageImage({ images, onPreview, onRemove }: MessageImageProps): import("react").JSX.Element | null;
39
+ export declare namespace MessageImage {
40
+ var displayName: string;
41
+ }
42
+ export default MessageImage;
@@ -0,0 +1,46 @@
1
+ import Image from "../image";
2
+ import "./style";
3
+
4
+ /**
5
+ * MessageImage 渲染的图片项。
6
+ * 与 `Attachment` 不同:图片消息的「主体」就是图本身,不需要 name / type / size 等
7
+ * 文件元信息——展示文件名只会变成 `/qidian/im/image/3c87...` 这种对用户无意义的服务端路径。
8
+ */
9
+
10
+ /**
11
+ * 用户消息中的图片附件渲染组件——`Image` leaf 之上的「消息态」语义包装。
12
+ *
13
+ * 两态:
14
+ * - 单图:数据驱动尺寸,max 280×360 contain,保留原图长宽比
15
+ * - 多图:模板驱动尺寸,每张 88×88 cover,横向 flex + wrap
16
+ * 与单图差异化是为了多图场景下「整齐成组」比「逐张完整」更重要——
17
+ * 业界共识(微信 / iMessage / Telegram 多图均为统一缩略 + 点开看大图)
18
+ *
19
+ * Composer 待发送态等其他场景**不应消费此组件**——那是输入态语义,
20
+ * 应直接用 `Image` leaf + 自己的尺寸 wrap。
21
+ */
22
+ export function MessageImage(_ref) {
23
+ var images = _ref.images,
24
+ onPreview = _ref.onPreview,
25
+ onRemove = _ref.onRemove;
26
+ if (images.length === 0) return null;
27
+ var isMulti = images.length > 1;
28
+ return /*#__PURE__*/React.createElement("div", {
29
+ "data-odn-message-image": true,
30
+ "data-odn-message-image-multi": isMulti || undefined
31
+ }, images.map(function (img, i) {
32
+ return /*#__PURE__*/React.createElement(Image, {
33
+ key: i,
34
+ url: img.url,
35
+ alt: img.alt,
36
+ onPreview: onPreview ? function () {
37
+ return onPreview(i);
38
+ } : undefined,
39
+ onRemove: onRemove ? function () {
40
+ return onRemove(i);
41
+ } : undefined
42
+ });
43
+ }));
44
+ }
45
+ MessageImage.displayName = 'MessageImage';
46
+ export default MessageImage;
@@ -0,0 +1,60 @@
1
+ @charset "UTF-8";
2
+ /* MessageImage 尺寸 token(业务方按需 cascade 覆盖):
3
+ *
4
+ * 单图态(数据驱动尺寸):
5
+ * --odn-message-image-max-width 280:drawer 模式下 UserBubble inner 可用
6
+ * 宽 384px(chat area 560 - px-6×2),280 留 104px 余量;fullscreen
7
+ * 模式 UserBubble inner 576px 完全富余
8
+ * --odn-message-image-max-height 360:长边 × 1.286(≈ 黄金比 1.272),
9
+ * 竖图 9:16 → 203×360、3:4 → 270×360、2:3 → 240×360 都保留竖向张力;
10
+ * 与 iMessage(260×360) / Claude(300×400) 中段对齐
11
+ *
12
+ * 多图态(模板驱动尺寸):
13
+ * --odn-message-image-thumb-size 88:3 张时正好填满 280 包围盒(88×3 +
14
+ * gap 4×2 = 272,留 8 余量),4+ 张自然换行;与 iMessage / Telegram
15
+ * 多图缩略 80–100 区间一致
16
+ * --odn-message-image-thumb-gap 4:图与图之间最小可识别留白
17
+ *
18
+ * 以上都是 8 的整数倍,不破坏栅格。 */
19
+ html {
20
+ --odn-message-image-max-width: 280px;
21
+ --odn-message-image-max-height: 360px;
22
+ --odn-message-image-thumb-size: 88px;
23
+ --odn-message-image-thumb-gap: 4px;
24
+ }
25
+
26
+ /* MessageImage = Image leaf 之上的「消息态」语义包装。
27
+ * - 单图:数据驱动尺寸(max 280×360 contain),保留原图比例
28
+ * - 多图:模板驱动尺寸(88×88 cover,flex wrap),整齐成组
29
+ * - 圆角 scoped 到 MessageImage 内的 Image leaf 容器,不影响其他场景下的
30
+ * Image leaf(Composer 缩略由 Composer 自己加圆角) */
31
+ [data-odn-message-image] {
32
+ display: inline-block;
33
+ max-width: min(100%, var(--odn-message-image-max-width));
34
+ }
35
+ [data-odn-message-image] [data-odn-image] {
36
+ display: block;
37
+ border-radius: 8px;
38
+ overflow: hidden;
39
+ }
40
+ [data-odn-message-image] img {
41
+ max-width: 100%;
42
+ max-height: var(--odn-message-image-max-height);
43
+ object-fit: contain;
44
+ }
45
+
46
+ [data-odn-message-image][data-odn-message-image-multi] {
47
+ display: flex;
48
+ flex-wrap: wrap;
49
+ gap: var(--odn-message-image-thumb-gap);
50
+ }
51
+ [data-odn-message-image][data-odn-message-image-multi] [data-odn-image] {
52
+ width: var(--odn-message-image-thumb-size);
53
+ height: var(--odn-message-image-thumb-size);
54
+ }
55
+ [data-odn-message-image][data-odn-message-image-multi] img {
56
+ width: 100%;
57
+ height: 100%;
58
+ max-height: none;
59
+ object-fit: cover;
60
+ }
@@ -0,0 +1,2 @@
1
+ import '../../style';
2
+ import './index.scss';
@@ -0,0 +1,2 @@
1
+ import "../../style";
2
+ import "./index.css";
@@ -12,6 +12,10 @@ export interface PreviewPanelProps {
12
12
  * 未传则不渲染下载按钮(向后兼容)。
13
13
  */
14
14
  onDownload?: (tab: PreviewTab) => void;
15
+ /**
16
+ * 在浏览器中打开当前激活标签。未传时使用默认实现(Blob URL + window.open)。
17
+ */
18
+ onOpenInBrowser?: (tab: PreviewTab) => void;
15
19
  /**
16
20
  * 是否展开面板。不传时默认按 `tabs.length > 0` 自动推断;
17
21
  * 显式传 `true` 且 tabs 为空时渲染空态("暂无附件"),便于由外部按钮主动打开。
@@ -27,7 +31,7 @@ export interface PreviewPanelProps {
27
31
  */
28
32
  widthMode?: 'half' | 'fill';
29
33
  }
30
- export declare function PreviewPanel({ tabs, activeTabId, onTabChange, onTabClose, onCloseAll, onDownload, open, emptyTitle, emptyDescription, widthMode, }: PreviewPanelProps): import("react").JSX.Element;
34
+ export declare function PreviewPanel({ tabs, activeTabId, onTabChange, onTabClose, onCloseAll, onDownload, onOpenInBrowser, open, emptyTitle, emptyDescription, widthMode, }: PreviewPanelProps): import("react").JSX.Element;
31
35
  export declare namespace PreviewPanel {
32
36
  var displayName: string;
33
37
  }
@@ -11,6 +11,7 @@ export function PreviewPanel(_ref) {
11
11
  onTabClose = _ref.onTabClose,
12
12
  onCloseAll = _ref.onCloseAll,
13
13
  onDownload = _ref.onDownload,
14
+ onOpenInBrowser = _ref.onOpenInBrowser,
14
15
  open = _ref.open,
15
16
  _ref$emptyTitle = _ref.emptyTitle,
16
17
  emptyTitle = _ref$emptyTitle === void 0 ? '暂无附件' : _ref$emptyTitle,
@@ -27,6 +28,21 @@ export function PreviewPanel(_ref) {
27
28
  var _useOverlayScrollbarR = useOverlayScrollbarReveal(),
28
29
  previewScrollbarReveal = _useOverlayScrollbarR.reveal,
29
30
  handlePreviewScroll = _useOverlayScrollbarR.onScroll;
31
+ var handleOpenInBrowser = function handleOpenInBrowser() {
32
+ if (!activeTab) return;
33
+ if (onOpenInBrowser) {
34
+ onOpenInBrowser(activeTab);
35
+ return;
36
+ }
37
+ var blob = new Blob([activeTab.content], {
38
+ type: activeTab.type || 'text/plain'
39
+ });
40
+ var url = URL.createObjectURL(blob);
41
+ window.open(url, '_blank', 'noopener,noreferrer');
42
+ window.setTimeout(function () {
43
+ return URL.revokeObjectURL(url);
44
+ }, 60000);
45
+ };
30
46
  return /*#__PURE__*/React.createElement("div", {
31
47
  "data-odn-preview-panel": true,
32
48
  "data-odn-preview-panel-open": isOpen || undefined,
@@ -79,10 +95,19 @@ export function PreviewPanel(_ref) {
79
95
  })));
80
96
  })), /*#__PURE__*/React.createElement("div", {
81
97
  "data-odn-preview-panel-actions": true
82
- }, onDownload && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
98
+ }, /*#__PURE__*/React.createElement(Button, {
83
99
  light: true,
84
100
  size: "medium",
85
- icon: "bottom",
101
+ icon: "arrow-up-right",
102
+ onClick: handleOpenInBrowser,
103
+ disabled: !activeTab,
104
+ "data-odn-preview-panel-open-browser": true,
105
+ title: "\u5728\u6D4F\u89C8\u5668\u6253\u5F00",
106
+ "aria-label": "\u5728\u6D4F\u89C8\u5668\u6253\u5F00"
107
+ }), onDownload && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Button, {
108
+ light: true,
109
+ size: "medium",
110
+ icon: "download-2",
86
111
  onClick: function onClick() {
87
112
  return activeTab && onDownload(activeTab);
88
113
  },
@@ -1,11 +1,21 @@
1
1
  /// <reference types="react" />
2
+ import { type MessageImageItem } from '../message-image';
2
3
  import type { Attachment, ChatMessage } from '../_genui-types';
3
4
  import './style';
4
5
  export interface UserBubbleProps {
5
6
  message: ChatMessage;
6
7
  onFileClick?: (attachment: Attachment) => void;
8
+ /**
9
+ * 点击图片附件回调,业务方按此对接自己的 lightbox / 大图查看器。
10
+ * @param index 被点击的图片在「当前消息内已分流的图片子集」中的位置(0-based)
11
+ * @param images 当前消息内所有 image attachments(已转成 `MessageImageItem`
12
+ * 的形态,包含 `url` 与 `alt`),方便直接 push 到 lightbox
13
+ * 实现上下张切换
14
+ * 不传 → 图片不可点击预览。
15
+ */
16
+ onImagePreview?: (index: number, images: MessageImageItem[]) => void;
7
17
  }
8
- export declare function UserBubble({ message, onFileClick }: UserBubbleProps): import("react").JSX.Element;
18
+ export declare function UserBubble({ message, onFileClick, onImagePreview }: UserBubbleProps): import("react").JSX.Element;
9
19
  export declare namespace UserBubble {
10
20
  var displayName: string;
11
21
  }
@@ -1,20 +1,45 @@
1
1
  import { Attachments } from "../attachments";
2
+ import MessageImage from "../message-image";
2
3
  import "./style";
3
4
  export function UserBubble(_ref) {
5
+ var _message$attachments;
4
6
  var message = _ref.message,
5
- onFileClick = _ref.onFileClick;
7
+ onFileClick = _ref.onFileClick,
8
+ onImagePreview = _ref.onImagePreview;
6
9
  var hasText = !!message.content;
7
- var hasFiles = message.attachments && message.attachments.length > 0;
10
+ var all = (_message$attachments = message.attachments) !== null && _message$attachments !== void 0 ? _message$attachments : [];
11
+
12
+ /* 图片附件分流到 MessageImage,保持其数据驱动尺寸的渲染语义;
13
+ * 其他附件(文件 / 报告 / chip)继续走 Attachments 的模板槽位渲染。
14
+ * 分流是 UserBubble 内部行为,业务方传入的 message.attachments 形状不变。 */
15
+ var images = all.filter(function (a) {
16
+ return a.type.startsWith('image/') && a.url;
17
+ }).map(function (a) {
18
+ return {
19
+ url: a.url,
20
+ alt: a.name
21
+ };
22
+ });
23
+ var files = all.filter(function (a) {
24
+ return !(a.type.startsWith('image/') && a.url);
25
+ });
8
26
  return /*#__PURE__*/React.createElement("div", {
9
27
  "data-odn-user-bubble": true
10
28
  }, /*#__PURE__*/React.createElement("div", {
11
29
  "data-odn-user-bubble-inner": true
12
- }, hasText && /*#__PURE__*/React.createElement("div", {
30
+ }, images.length > 0 && /*#__PURE__*/React.createElement("div", {
31
+ "data-odn-user-bubble-images": true
32
+ }, /*#__PURE__*/React.createElement(MessageImage, {
33
+ images: images,
34
+ onPreview: onImagePreview ? function (i) {
35
+ return onImagePreview(i, images);
36
+ } : undefined
37
+ })), hasText && /*#__PURE__*/React.createElement("div", {
13
38
  "data-odn-user-bubble-text": true
14
- }, /*#__PURE__*/React.createElement("p", null, message.content)), hasFiles && /*#__PURE__*/React.createElement("div", {
39
+ }, /*#__PURE__*/React.createElement("p", null, message.content)), files.length > 0 && /*#__PURE__*/React.createElement("div", {
15
40
  "data-odn-user-bubble-files": true
16
41
  }, /*#__PURE__*/React.createElement(Attachments, {
17
- attachments: message.attachments,
42
+ attachments: files,
18
43
  onFileClick: onFileClick,
19
44
  compact: hasText
20
45
  }))));
@@ -7,6 +7,7 @@
7
7
  max-width: 75%;
8
8
  display: flex;
9
9
  flex-direction: column;
10
+ align-items: flex-end;
10
11
  gap: 6px;
11
12
  }
12
13
 
@@ -25,6 +26,11 @@
25
26
  margin: 0;
26
27
  }
27
28
 
29
+ [data-odn-user-bubble-images] {
30
+ display: flex;
31
+ justify-content: flex-end;
32
+ }
33
+
28
34
  [data-odn-user-bubble-files] {
29
35
  display: flex;
30
36
  justify-content: flex-end;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "one-design-next",
3
- "version": "0.0.11",
3
+ "version": "0.0.13",
4
4
  "description": "One Design Next from TAD@tencent.com",
5
5
  "module": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -76,7 +76,6 @@
76
76
  "@commitlint/cli": "^17.1.2",
77
77
  "@commitlint/config-conventional": "^17.1.0",
78
78
  "@tailwindcss/postcss": "^4",
79
- "@tencent/tad-universal-od": "^1.141.3",
80
79
  "@tweakpane/core": "^2.0.5",
81
80
  "@types/d3": "^7.4.3",
82
81
  "@types/d3-cloud": "^1.2.9",
@@ -113,7 +112,7 @@
113
112
  "stylelint": "^16.23.1",
114
113
  "stylelint-config-standard-scss": "^15.0.1",
115
114
  "svgo": "latest",
116
- "tailwind-merge": "^3.4.0",
115
+ "tailwind-merge": "^3.6.0",
117
116
  "tailwindcss": "^4",
118
117
  "tweakpane": "latest"
119
118
  },