@ray-js/t-agent-ui-ray 0.0.9 → 0.1.0-beta-2

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.
@@ -46,7 +46,8 @@ export default function ChatContainer(props) {
46
46
  plugins: agent.plugins,
47
47
  pushInputBlocks: agent.pushInputBlocks,
48
48
  emitTileEvent: agent.emitTileEvent,
49
- removeMessage: agent.removeMessage
49
+ removeMessage: agent.removeMessage,
50
+ removeMessageByChannel: agent.removeMessageByChannel
50
51
  };
51
52
  }, [agent]);
52
53
  useEffect(() => {
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import './index.less';
3
+ import { LongPressActionMenuProps } from '../hooks/useLongPress';
4
+ declare const LongPressActionMenu: React.FC<LongPressActionMenuProps>;
5
+ export default LongPressActionMenu;
@@ -0,0 +1,34 @@
1
+ import "core-js/modules/esnext.iterator.constructor.js";
2
+ import "core-js/modules/esnext.iterator.map.js";
3
+ import React from 'react';
4
+ import { View } from '@ray-js/components';
5
+ import './index.less';
6
+ const LongPressActionMenu = _ref => {
7
+ let {
8
+ showActionMenu,
9
+ isClosing,
10
+ menuPosition,
11
+ handleCloseMenu,
12
+ handleMenuItemClick,
13
+ menuItems
14
+ } = _ref;
15
+ if (!showActionMenu) {
16
+ return null;
17
+ }
18
+ return /*#__PURE__*/React.createElement(View, {
19
+ className: "t-agent-action-menu-container ".concat(isClosing ? 't-agent-action-menu-container-closing' : ''),
20
+ onClick: handleCloseMenu
21
+ }, /*#__PURE__*/React.createElement(View, {
22
+ className: "t-agent-action-menu ".concat(isClosing ? 't-agent-action-menu-closing' : ''),
23
+ style: {
24
+ left: "".concat(menuPosition.x, "px"),
25
+ top: "".concat(menuPosition.y, "px")
26
+ },
27
+ onClick: e => e.origin.stopPropagation()
28
+ }, menuItems.map(item => /*#__PURE__*/React.createElement(View, {
29
+ key: item.key,
30
+ className: "t-agent-action-menu-item",
31
+ onClick: () => handleMenuItemClick(item)
32
+ }, item.displayLabel))));
33
+ };
34
+ export default LongPressActionMenu;
@@ -0,0 +1,88 @@
1
+ .t-agent-action-menu-container {
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ // background: rgba(0, 0, 0, 0.5);
8
+ z-index: 1000;
9
+ animation: fade-in 0.2s ease-in-out;
10
+
11
+ &-closing {
12
+ animation: fade-out 0.2s ease-in-out;
13
+ }
14
+
15
+ .t-agent-action-menu {
16
+ position: absolute;
17
+ background-color: #fff;
18
+ border-radius: 8px;
19
+ overflow: hidden;
20
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
21
+ min-width: 150px;
22
+ z-index: 1001;
23
+ animation: scale-in 0.2s ease-in-out;
24
+
25
+ &-closing {
26
+ animation: scale-out 0.2s ease-in-out;
27
+ }
28
+
29
+ &-item {
30
+ padding: 12px 16px;
31
+ font-size: 14px;
32
+ color: #333;
33
+ border-bottom: 1px solid #f0f0f0;
34
+ max-width: 150px;
35
+ overflow: hidden;
36
+ text-overflow: ellipsis;
37
+ white-space: nowrap;
38
+
39
+ &:last-child {
40
+ border-bottom: none;
41
+ }
42
+
43
+ &:active {
44
+ background-color: #f5f5f5;
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ @keyframes fade-in {
51
+ from {
52
+ opacity: 0;
53
+ }
54
+ to {
55
+ opacity: 1;
56
+ }
57
+ }
58
+
59
+ @keyframes fade-out {
60
+ from {
61
+ opacity: 1;
62
+ }
63
+ to {
64
+ opacity: 0;
65
+ }
66
+ }
67
+
68
+ @keyframes scale-in {
69
+ from {
70
+ transform: scale(0.8);
71
+ opacity: 0;
72
+ }
73
+ to {
74
+ transform: scale(1);
75
+ opacity: 1;
76
+ }
77
+ }
78
+
79
+ @keyframes scale-out {
80
+ from {
81
+ transform: scale(1);
82
+ opacity: 1;
83
+ }
84
+ to {
85
+ transform: scale(0.8);
86
+ opacity: 0;
87
+ }
88
+ }
@@ -9,7 +9,7 @@ export declare const MessageContext: import("react").Context<{
9
9
  }>;
10
10
  export declare const RenderContext: import("react").Context<RenderOptions>;
11
11
  export type UIChatSession = Pick<ChatSession, 'get' | 'getData' | 'set' | 'sessionId'>;
12
- export type UIChatAgent = Pick<ChatAgent<UIPlugin & AssistantPlugin>, 'pushInputBlocks' | 'plugins' | 'emitTileEvent' | 'removeMessage'> & {
12
+ export type UIChatAgent = Pick<ChatAgent<UIPlugin & AssistantPlugin>, 'pushInputBlocks' | 'plugins' | 'emitTileEvent' | 'removeMessage' | 'removeMessageByChannel'> & {
13
13
  session: UIChatSession;
14
14
  };
15
15
  export declare const ChatAgentContext: import("react").Context<UIChatAgent>;
@@ -3,3 +3,4 @@ export * from './useAttachmentInput';
3
3
  export * from './useAsrInput';
4
4
  export * from './useSleep';
5
5
  export * from './useIsUnmounted';
6
+ export * from './useLongPress';
@@ -2,4 +2,5 @@ export * from './context';
2
2
  export * from './useAttachmentInput';
3
3
  export * from './useAsrInput';
4
4
  export * from './useSleep';
5
- export * from './useIsUnmounted';
5
+ export * from './useIsUnmounted';
6
+ export * from './useLongPress';
@@ -0,0 +1,38 @@
1
+ import { ChatMessageObject } from '@ray-js/t-agent';
2
+ /**
3
+ * 预定义动作类型
4
+ */
5
+ export type ActionType = 'copy' | 'delete' | 'like' | 'unlike' | 'deleteByChannel';
6
+ export interface ActionMenuItem {
7
+ key: string;
8
+ label: string;
9
+ action: () => void;
10
+ }
11
+ export interface LongPressActionMenuProps {
12
+ showActionMenu: boolean;
13
+ isClosing: boolean;
14
+ menuPosition: {
15
+ x: number;
16
+ y: number;
17
+ };
18
+ handleCloseMenu: () => void;
19
+ handleMenuItemClick: (item: ActionMenuItem) => void;
20
+ menuItems: Array<ActionMenuItem & {
21
+ displayLabel: string;
22
+ }>;
23
+ }
24
+ export interface UseLongPressOptions {
25
+ message?: ChatMessageObject;
26
+ actions?: ActionType | ActionType[];
27
+ getMessageContent?: () => string;
28
+ customActions?: ActionMenuItem[];
29
+ disabled?: boolean;
30
+ }
31
+ export interface LongPressResult {
32
+ longPressProps: LongPressProps;
33
+ menuProps: LongPressActionMenuProps;
34
+ }
35
+ export interface LongPressProps {
36
+ onLongPress: (e: any) => void;
37
+ }
38
+ export declare function useLongPress(options?: UseLongPressOptions): LongPressResult;
@@ -0,0 +1,240 @@
1
+ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
+ import "core-js/modules/esnext.iterator.constructor.js";
3
+ import "core-js/modules/esnext.iterator.for-each.js";
4
+ import "core-js/modules/esnext.iterator.map.js";
5
+ import "core-js/modules/web.dom-collections.iterator.js";
6
+ import { useState, useEffect, useCallback } from 'react';
7
+ import { getSystemInfoSync, setClipboardData, showModal, showToast, vibrateShort } from '@ray-js/ray';
8
+ import logger from '../logger';
9
+ import { useRenderOptions } from './context';
10
+ import { useChatAgent } from '.';
11
+
12
+ /**
13
+ * 预定义动作类型
14
+ */
15
+
16
+ /**
17
+ * 长按状态接口
18
+ */
19
+
20
+ export function useLongPress() {
21
+ let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
22
+ const {
23
+ message,
24
+ actions = ['copy', 'delete'],
25
+ getMessageContent = () => '',
26
+ customActions = [],
27
+ disabled = false
28
+ } = options;
29
+ const [state, setState] = useState({
30
+ showActionMenu: false,
31
+ isClosing: false,
32
+ menuPosition: {
33
+ x: 0,
34
+ y: 0
35
+ }
36
+ });
37
+ const agent = useChatAgent();
38
+ const {
39
+ i18nTranslate: t
40
+ } = useRenderOptions();
41
+ const [screenSize, setScreenSize] = useState({
42
+ width: 0,
43
+ height: 0
44
+ });
45
+ useEffect(() => {
46
+ try {
47
+ const systemInfo = getSystemInfoSync();
48
+ setScreenSize({
49
+ width: systemInfo.windowWidth,
50
+ height: systemInfo.windowHeight
51
+ });
52
+ } catch (error) {
53
+ logger.error('获取屏幕尺寸失败', error);
54
+ }
55
+ }, []);
56
+ const getActionMenuItems = useCallback(() => {
57
+ if (!actions || !message) return [];
58
+ const actionTypes = Array.isArray(actions) ? actions : [actions];
59
+ const menuItems = [];
60
+ actionTypes.forEach(type => {
61
+ switch (type) {
62
+ case 'copy':
63
+ if (typeof getMessageContent === 'function') {
64
+ menuItems.push({
65
+ key: 'copy',
66
+ label: t('t-agent.message.action.copy'),
67
+ action: () => {
68
+ const content = getMessageContent();
69
+ if (content) {
70
+ setClipboardData({
71
+ data: content,
72
+ success: () => {
73
+ showToast({
74
+ title: t('t-agent.message.copy.success'),
75
+ icon: 'none'
76
+ });
77
+ }
78
+ });
79
+ }
80
+ }
81
+ });
82
+ }
83
+ break;
84
+ case 'delete':
85
+ if (agent && message.id) {
86
+ menuItems.push({
87
+ key: 'delete',
88
+ label: t('t-agent.message.action.delete'),
89
+ action: () => {
90
+ if (typeof agent.removeMessage === 'function') {
91
+ showModal({
92
+ title: t('t-agent.message.delete.title'),
93
+ content: t('t-agent.message.delete.content'),
94
+ success: res => {
95
+ if (res.confirm) {
96
+ agent.removeMessage(message.id);
97
+ showToast({
98
+ title: t('t-agent.message.delete.success'),
99
+ icon: 'none'
100
+ });
101
+ }
102
+ }
103
+ });
104
+ }
105
+ }
106
+ });
107
+ }
108
+ break;
109
+ case 'deleteByChannel':
110
+ menuItems.push({
111
+ key: 'deleteByChannel',
112
+ label: t('t-agent.message.action.deleteByChannel'),
113
+ action: () => {
114
+ const channel = agent.session.get('AIAssistant.channel');
115
+ if (typeof agent.removeMessageByChannel === 'function') {
116
+ agent.removeMessageByChannel(channel);
117
+ }
118
+ }
119
+ });
120
+ break;
121
+ case 'like':
122
+ menuItems.push({
123
+ key: 'like',
124
+ label: t('t-agent.message.action.like'),
125
+ action: () => {
126
+ showToast({
127
+ title: t('t-agent.message.like.success'),
128
+ icon: 'none'
129
+ });
130
+ }
131
+ });
132
+ break;
133
+ case 'unlike':
134
+ menuItems.push({
135
+ key: 'unlike',
136
+ label: t('t-agent.message.action.unlike'),
137
+ action: () => {
138
+ showToast({
139
+ title: t('t-agent.message.unlike.success'),
140
+ icon: 'none'
141
+ });
142
+ }
143
+ });
144
+ break;
145
+ }
146
+ });
147
+ return [...menuItems, ...customActions];
148
+ }, [actions, message, agent, getMessageContent, t, customActions]);
149
+ const menuItems = getActionMenuItems();
150
+
151
+ // 计算菜单位置,确保不超出屏幕
152
+ const calculateMenuPosition = useCallback((x, y) => {
153
+ const estimatedMenuWidth = 150;
154
+ // 头部高度先写死
155
+ const estimatedMenuHeight = menuItems.length * 44 + 100;
156
+ let adjustedX = x;
157
+ let adjustedY = y;
158
+
159
+ // 确保菜单不超出右边界
160
+ if (x + estimatedMenuWidth > screenSize.width) {
161
+ adjustedX = screenSize.width - estimatedMenuWidth - 10;
162
+ }
163
+
164
+ // 确保菜单不超出左边界
165
+ if (adjustedX < 10) {
166
+ adjustedX = 10;
167
+ }
168
+
169
+ // 确保菜单不超出底部边界
170
+ if (y + estimatedMenuHeight > screenSize.height) {
171
+ adjustedY = screenSize.height - estimatedMenuHeight - 10;
172
+ }
173
+
174
+ // 确保菜单不超出顶部边界
175
+ if (adjustedY < 10) {
176
+ adjustedY = 10;
177
+ }
178
+ return {
179
+ x: adjustedX,
180
+ y: adjustedY
181
+ };
182
+ }, [screenSize, menuItems.length]);
183
+ const handleLongPress = useCallback(e => {
184
+ var _e$detail$x, _e$detail, _e$detail$y, _e$detail2;
185
+ if (disabled || !menuItems.length || state.showActionMenu) return;
186
+
187
+ // 检查e.detail是否存在,如果不存在,使用屏幕中心点作为默认坐标
188
+ const x = (_e$detail$x = (_e$detail = e.detail) === null || _e$detail === void 0 ? void 0 : _e$detail.x) !== null && _e$detail$x !== void 0 ? _e$detail$x : screenSize.width / 2;
189
+ const y = (_e$detail$y = (_e$detail2 = e.detail) === null || _e$detail2 === void 0 ? void 0 : _e$detail2.y) !== null && _e$detail$y !== void 0 ? _e$detail$y : screenSize.height / 2;
190
+
191
+ // 计算并设置调整后的位置
192
+ const adjustedPosition = calculateMenuPosition(x, y);
193
+ setState({
194
+ showActionMenu: true,
195
+ isClosing: false,
196
+ menuPosition: adjustedPosition
197
+ });
198
+ vibrateShort({
199
+ type: 'light'
200
+ });
201
+ if (e.origin && e.origin.stopPropagation) {
202
+ e.origin.stopPropagation();
203
+ }
204
+ }, [disabled, menuItems.length, state.showActionMenu, screenSize, calculateMenuPosition]);
205
+ const handleCloseMenu = useCallback(() => {
206
+ setState(prev => _objectSpread(_objectSpread({}, prev), {}, {
207
+ isClosing: true
208
+ }));
209
+
210
+ // 等待动画完成后再隐藏菜单
211
+ setTimeout(() => {
212
+ setState(prev => _objectSpread(_objectSpread({}, prev), {}, {
213
+ showActionMenu: false,
214
+ isClosing: false
215
+ }));
216
+ }, 200);
217
+ }, []);
218
+ const handleMenuItemClick = useCallback(item => {
219
+ item.action();
220
+ handleCloseMenu();
221
+ }, [handleCloseMenu]);
222
+ const getMenuItemLabel = useCallback(item => {
223
+ return t("t-agent.message.action.".concat(item.key)) || item.label;
224
+ }, [t]);
225
+ return {
226
+ longPressProps: {
227
+ onLongPress: handleLongPress
228
+ },
229
+ menuProps: {
230
+ showActionMenu: state.showActionMenu,
231
+ isClosing: state.isClosing,
232
+ menuPosition: state.menuPosition,
233
+ handleCloseMenu,
234
+ handleMenuItemClick,
235
+ menuItems: menuItems.map(item => _objectSpread(_objectSpread({}, item), {}, {
236
+ displayLabel: getMenuItemLabel(item)
237
+ }))
238
+ }
239
+ };
240
+ }
@@ -1,17 +1,22 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
1
2
  import "core-js/modules/es.json.stringify.js";
2
3
  import "core-js/modules/esnext.iterator.constructor.js";
4
+ import "core-js/modules/esnext.iterator.find.js";
3
5
  import "core-js/modules/esnext.iterator.map.js";
4
6
  import "core-js/modules/web.dom-collections.iterator.js";
5
7
  import './index.less';
6
- import { Text, View } from '@ray-js/components';
7
- import React, { useEffect, useState } from 'react';
8
+ import { View } from '@ray-js/components';
9
+ import React, { useEffect, useState, useCallback, memo } from 'react';
8
10
  import { Image } from '@ray-js/ray';
9
11
  import { BubbleTileStatus, ChatMessageStatus, safeParseJSON } from '@ray-js/t-agent';
10
12
  import { getCurrentHomeInfo, submitEvaluation } from '@ray-js/t-agent-plugin-assistant';
13
+ import { setStorage, getStorage, showToast } from '@ray-js/api';
11
14
  import TileRender from '../../TileRender';
12
15
  import noticeSvg from './notice.svg';
13
16
  import noticeWarnSvg from './notice-warn.svg';
14
17
  import { useChatAgent, useRenderOptions } from '../../hooks';
18
+ import LongPressActionMenu from '../../LongPressActionMenu';
19
+ import { useLongPress } from '../../hooks/useLongPress';
15
20
  const BubbleTile = props => {
16
21
  var _message$meta$request;
17
22
  const agent = useChatAgent();
@@ -38,7 +43,7 @@ const BubbleTile = props => {
38
43
  const [feedbackLoaded, setFeedbackLoaded] = useState(false);
39
44
  const [feedbackValue, setFeedbackValue] = useState(null);
40
45
  useEffect(() => {
41
- ty.getStorage({
46
+ getStorage({
42
47
  key: 'latestMessageFeedbackValue',
43
48
  success: res => {
44
49
  if (res.data) {
@@ -60,46 +65,116 @@ const BubbleTile = props => {
60
65
  }, []);
61
66
  const showInfo = () => {
62
67
  if (data.info) {
63
- ty.showToast({
68
+ showToast({
64
69
  title: data.info,
65
70
  icon: 'none'
66
71
  });
67
72
  }
68
73
  };
69
- let errorNode = null;
74
+
75
+ // 获取消息内容的函数
76
+ const getMessageContent = useCallback(() => {
77
+ let messageContent = '';
78
+ if (tile.children && tile.children.length > 0) {
79
+ // 查找文本类型的tile
80
+ const textTile = tile.children.find(child => child.type === 'text');
81
+ if (textTile && textTile.data && typeof textTile.data === 'object' && 'text' in textTile.data) {
82
+ messageContent = textTile.data.text;
83
+ }
84
+ }
85
+
86
+ // 如果是文本类型的tile,直接获取文本内容
87
+ if (tile.type === 'text' && tile.data && typeof tile.data === 'object' && 'text' in tile.data) {
88
+ messageContent = tile.data.text;
89
+ }
90
+ return messageContent;
91
+ }, [tile]);
92
+ const {
93
+ longPressProps,
94
+ menuProps
95
+ } = useLongPress({
96
+ message,
97
+ // actions: [
98
+ // 'copy',
99
+ // 'delete',
100
+ // ...(isAssistantMessage ? ['like', 'unlike', 'deleteByChannel'] : []),
101
+ // ] as ActionType[],
102
+ actions: ['copy', 'delete'],
103
+ getMessageContent,
104
+ disabled: loading
105
+ });
106
+ const showAbortedMessage = bubbleStatus === BubbleTileStatus.ABORTED;
107
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, _extends({
108
+ className: "t-agent-bubble-tile t-agent-bubble-tile-".concat(side),
109
+ "data-testid": "t-agent-bubble-tile"
110
+ }, longPressProps), side === 'end' && /*#__PURE__*/React.createElement(ErrorNotice, {
111
+ bubbleStatus: bubbleStatus,
112
+ showInfo: showInfo
113
+ }), /*#__PURE__*/React.createElement(View, {
114
+ className: "t-agent-bubble-tile-bubble ".concat(loading ? 't-agent-bubble-tile-bubble-loading' : '')
115
+ }, (() => {
116
+ return /*#__PURE__*/React.createElement(React.Fragment, null, children.map(t => /*#__PURE__*/React.createElement(TileRender, {
117
+ side: side,
118
+ tile: t,
119
+ message: message,
120
+ key: t.id,
121
+ isLatestMessage: isLatestMessage
122
+ })));
123
+ })(), /*#__PURE__*/React.createElement(LoadingIndicator, {
124
+ status: status
125
+ }), showAbortedMessage && /*#__PURE__*/React.createElement(View, {
126
+ className: "t-agent-bubble-tile-aborted"
127
+ }, t('t-agent.message.bubble.aborted'))), side === 'start' && /*#__PURE__*/React.createElement(ErrorNotice, {
128
+ bubbleStatus: bubbleStatus,
129
+ showInfo: showInfo
130
+ })), /*#__PURE__*/React.createElement(LongPressActionMenu, menuProps));
131
+ };
132
+ export default /*#__PURE__*/React.memo(BubbleTile);
133
+ const ErrorNotice = /*#__PURE__*/memo(_ref => {
134
+ let {
135
+ bubbleStatus,
136
+ showInfo
137
+ } = _ref;
70
138
  if (bubbleStatus === BubbleTileStatus.ERROR) {
71
- errorNode = /*#__PURE__*/React.createElement(Image, {
139
+ return /*#__PURE__*/React.createElement(Image, {
72
140
  onClick: showInfo,
73
141
  src: noticeSvg,
74
142
  className: "t-agent-bubble-tile-error",
75
143
  "data-testid": "t-agent-bubble-tile-error"
76
144
  });
77
- } else if (bubbleStatus === BubbleTileStatus.WARNING) {
78
- errorNode = /*#__PURE__*/React.createElement(Image, {
145
+ }
146
+ if (bubbleStatus === BubbleTileStatus.WARNING) {
147
+ return /*#__PURE__*/React.createElement(Image, {
79
148
  onClick: showInfo,
80
149
  src: noticeWarnSvg,
81
150
  className: "t-agent-bubble-tile-error",
82
151
  "data-testid": "t-agent-bubble-tile-warning"
83
152
  });
84
153
  }
85
- return /*#__PURE__*/React.createElement(View, {
86
- className: "t-agent-bubble-tile t-agent-bubble-tile-".concat(side),
87
- "data-testid": "t-agent-bubble-tile",
88
- onLongPress: () => {}
89
- }, side === 'end' && errorNode, /*#__PURE__*/React.createElement(View, {
90
- className: "t-agent-bubble-tile-bubble ".concat(loading ? 't-agent-bubble-tile-bubble-loading' : '')
91
- }, children.map(t => {
92
- return /*#__PURE__*/React.createElement(TileRender, {
93
- side: side,
94
- tile: t,
95
- message: message,
96
- key: t.id,
97
- isLatestMessage: isLatestMessage
98
- });
99
- }), status === ChatMessageStatus.START && /*#__PURE__*/React.createElement(Text, {
100
- className: "t-agent-bubble-tile-bubble-loader"
101
- }, "..."), bubbleStatus === BubbleTileStatus.ABORTED && /*#__PURE__*/React.createElement(View, {
102
- className: "t-agent-bubble-tile-aborted"
103
- }, t('t-agent.message.bubble.aborted'))), side === 'start' && errorNode);
104
- };
105
- export default /*#__PURE__*/React.memo(BubbleTile);
154
+ return null;
155
+ });
156
+ const LoadingIndicator = /*#__PURE__*/memo(_ref2 => {
157
+ let {
158
+ status
159
+ } = _ref2;
160
+ if (status === ChatMessageStatus.START) {
161
+ return /*#__PURE__*/React.createElement(View, {
162
+ className: "t-agent-bubble-tile-bubble-loader"
163
+ }, /*#__PURE__*/React.createElement(View, {
164
+ className: "t-agent-bubble-tile-bubble-loader-ball"
165
+ }), /*#__PURE__*/React.createElement(View, {
166
+ className: "t-agent-bubble-tile-bubble-loader-ball"
167
+ }), /*#__PURE__*/React.createElement(View, {
168
+ className: "t-agent-bubble-tile-bubble-loader-ball"
169
+ }));
170
+ }
171
+ if (status === ChatMessageStatus.UPDATING) {
172
+ return /*#__PURE__*/React.createElement(View, {
173
+ className: "t-agent-bubble-tile-cursor-loader",
174
+ "data-testid": "t-agent-cursor-loader"
175
+ }, /*#__PURE__*/React.createElement(View, {
176
+ className: "t-agent-bubble-tile-bubble-loader-ball"
177
+ }));
178
+ }
179
+ return null;
180
+ });
@@ -3,12 +3,6 @@
3
3
  align-items: center;
4
4
  }
5
5
 
6
- .t-agent-bubble-tile-error {
7
- width: 32rpx;
8
- height: 32rpx;
9
- margin: 0 18rpx;
10
- }
11
-
12
6
  .t-agent-bubble-tile-bubble {
13
7
  width: fit-content;
14
8
  max-width: 612rpx;
@@ -21,6 +15,64 @@
21
15
  padding: 24rpx;
22
16
  transition: all 0.2s ease-in-out;
23
17
  overflow: hidden;
18
+ position: relative;
19
+ }
20
+
21
+ .t-agent-bubble-tile-bubble-loader {
22
+ display: inline-flex;
23
+
24
+ .t-agent-bubble-tile-bubble-loader-ball {
25
+ width: 8px;
26
+ height: 8px;
27
+ background-color: var(--app-B1-N1);
28
+ border-radius: 50%;
29
+ animation: bounce 1.5s infinite ease-in-out;
30
+
31
+ & + .t-agent-bubble-tile-bubble-loader-ball {
32
+ margin-left: 5px;
33
+ }
34
+ }
35
+
36
+ .t-agent-bubble-tile-bubble-loader-ball:nth-child(2) {
37
+ animation-delay: 0.3s;
38
+ }
39
+
40
+ .t-agent-bubble-tile-bubble-loader-ball:nth-child(3) {
41
+ animation-delay: 0.6s;
42
+ }
43
+
44
+ @keyframes bounce {
45
+ 0%,
46
+ 100% {
47
+ // transform: scale(0.75);
48
+ opacity: 0.5;
49
+ }
50
+ 50% {
51
+ // transform: scale(1);
52
+ opacity: 1;
53
+ }
54
+ }
55
+ }
56
+
57
+ .t-agent-bubble-tile-cursor-loader {
58
+ position: absolute;
59
+ right: 9px;
60
+ bottom: 19px;
61
+ z-index: 10;
62
+ width: 6px;
63
+ height: 6px;
64
+ display: flex;
65
+ justify-content: center;
66
+ align-items: center;
67
+
68
+ .t-agent-bubble-tile-bubble-loader-ball {
69
+ width: 6px;
70
+ height: 6px;
71
+ background-color: var(--app-B3-N1);
72
+ opacity: 0.7;
73
+ border-radius: 50%;
74
+ animation: t-agent-cursor-bounce 1.2s infinite ease-in-out;
75
+ }
24
76
  }
25
77
 
26
78
  .t-agent-bubble-tile-start {
@@ -37,10 +89,18 @@
37
89
  }
38
90
  }
39
91
 
40
- .t-agent-bubble-tile-start {
41
- .t-agent-bubble-tile-bubble {
42
- border-bottom-left-radius: 4rpx;
43
- }
92
+ .t-agent-bubble-tile-aborted {
93
+ color: var(--app-B3-N3);
94
+ opacity: 0.75;
95
+ font-size: 28rpx;
96
+ padding-top: 8rpx;
97
+ text-align: center;
98
+ }
99
+
100
+ .t-agent-bubble-tile-error {
101
+ width: 32rpx;
102
+ height: 32rpx;
103
+ margin: 0 18rpx;
44
104
  }
45
105
 
46
106
  @keyframes t-agent-bubble-tile-blink {
@@ -52,13 +112,24 @@
52
112
  }
53
113
  }
54
114
 
55
- .t-agent-bubble-tile-bubble-loader {
115
+ @keyframes t-agent-inline-bounce {
116
+ 0%, 100% {
117
+ opacity: 0.3;
118
+ transform: scale(0.75);
119
+ }
120
+ 50% {
121
+ opacity: 0.8;
122
+ transform: scale(1);
123
+ }
56
124
  }
57
125
 
58
- .t-agent-bubble-tile-aborted {
59
- color: var(--app-B3-N3);
60
- opacity: 0.75;
61
- font-size: 28rpx;
62
- padding-top: 8rpx;
63
- text-align: center;
126
+ @keyframes t-agent-cursor-bounce {
127
+ 0%, 100% {
128
+ opacity: 0.4;
129
+ transform: scale(0.8);
130
+ }
131
+ 50% {
132
+ opacity: 0.9;
133
+ transform: scale(1.1);
134
+ }
64
135
  }
@@ -1,21 +1,34 @@
1
+ import _extends from "@babel/runtime/helpers/esm/extends";
1
2
  import React from 'react';
2
3
  import { View } from '@ray-js/components';
3
4
  import './index.less';
4
5
  import { useRenderOptions } from '../../hooks';
6
+ import LongPressActionMenu from '../../LongPressActionMenu';
7
+ import { useLongPress } from '../../hooks/useLongPress';
5
8
  const CardTile = props => {
6
9
  const {
7
10
  card
8
11
  } = props.tile.data;
12
+ const {
13
+ message
14
+ } = props;
9
15
  const {
10
16
  renderCardAs
11
17
  } = useRenderOptions();
18
+ const {
19
+ longPressProps,
20
+ menuProps
21
+ } = useLongPress({
22
+ message,
23
+ actions: ['delete']
24
+ });
12
25
  const node = renderCardAs(card);
13
26
  if (!node) {
14
27
  return null;
15
28
  }
16
- return /*#__PURE__*/React.createElement(View, {
29
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(View, _extends({
17
30
  className: "t-agent-card-tile",
18
31
  "data-testid": "t-agent-bubble-tile"
19
- }, node);
32
+ }, longPressProps), node), /*#__PURE__*/React.createElement(LongPressActionMenu, menuProps));
20
33
  };
21
34
  export default /*#__PURE__*/React.memo(CardTile);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ray-js/t-agent-ui-ray",
3
- "version": "0.0.9",
3
+ "version": "0.1.0-beta-2",
4
4
  "author": "Tuya.inc",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -41,5 +41,5 @@
41
41
  "@types/echarts": "^4.9.22",
42
42
  "@types/markdown-it": "^14.1.1"
43
43
  },
44
- "gitHead": "328a8616b0356cbaef02d7a4ad46ee0c077d04be"
44
+ "gitHead": "e5fe943c9f582704342687e11f76fa3b9b0802b1"
45
45
  }