@ray-js/t-agent-ui-ray 0.2.0-beta.20 → 0.2.1-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.
- package/dist/ChatContainer/index.d.ts +1 -2
- package/dist/ChatContainer/index.js +48 -53
- package/dist/EchartsBlockRender/index.js +4 -6
- package/dist/EchartsBlockRender/index.rjs +9 -35
- package/dist/MessageInput/MessageInputAIStream/WaveformVisualizer.js +21 -28
- package/dist/MessageInput/MessageInputAIStream/index.js +0 -9
- package/dist/MessageList/index.d.ts +2 -4
- package/dist/MessageList/index.js +87 -23
- package/dist/MessageList/index.less +4 -15
- package/dist/TileRender/index.js +3 -5
- package/dist/contexts.d.ts +6 -18
- package/dist/contexts.js +17 -5
- package/dist/hooks/context.d.ts +4 -4
- package/dist/hooks/context.js +4 -13
- package/dist/tiles/BubbleTile/index.js +4 -4
- package/dist/tiles/OperateCardTile/index.js +1 -5
- package/dist/types.d.ts +0 -1
- package/package.json +2 -2
- package/dist/MessageList/LazyView.d.ts +0 -9
- package/dist/MessageList/LazyView.js +0 -57
- package/dist/MessageList/ScrollBottomView.d.ts +0 -46
- package/dist/MessageList/ScrollBottomView.js +0 -202
- package/dist/hooks/useStableCallback.d.ts +0 -1
- package/dist/hooks/useStableCallback.js +0 -13
- package/dist/utils/createSharedStore.d.ts +0 -4
- package/dist/utils/createSharedStore.js +0 -64
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import './index.less';
|
|
2
2
|
import React, { PropsWithChildren } from 'react';
|
|
3
3
|
import { ChatAgent } from '@ray-js/t-agent';
|
|
4
|
-
import { UIChatAgent } from '../contexts';
|
|
5
4
|
import { RenderOptions } from '../types';
|
|
6
5
|
export default function ChatContainer<T extends ChatAgent<any>>(props: PropsWithChildren<{
|
|
7
6
|
createAgent: () => T;
|
|
8
7
|
renderOptions?: RenderOptions;
|
|
9
8
|
className?: string;
|
|
10
9
|
style?: React.CSSProperties;
|
|
11
|
-
agentRef?: React.MutableRefObject<
|
|
10
|
+
agentRef?: React.MutableRefObject<T>;
|
|
12
11
|
}>): React.JSX.Element;
|
|
@@ -4,10 +4,10 @@ import "core-js/modules/esnext.iterator.filter.js";
|
|
|
4
4
|
import "core-js/modules/esnext.iterator.map.js";
|
|
5
5
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
6
6
|
import './index.less';
|
|
7
|
-
import React, {
|
|
7
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
8
8
|
import { View } from '@ray-js/components';
|
|
9
9
|
import cx from 'clsx';
|
|
10
|
-
import {
|
|
10
|
+
import { ChatAgentContext, MessageContext, RenderContext } from '../contexts';
|
|
11
11
|
import { defaultRenderOptions } from '../renderOption';
|
|
12
12
|
import logger from '../logger';
|
|
13
13
|
import { systemInfo } from '../utils';
|
|
@@ -27,8 +27,6 @@ export default function ChatContainer(props) {
|
|
|
27
27
|
style
|
|
28
28
|
} = props;
|
|
29
29
|
const [messages, setMessages] = useState([]);
|
|
30
|
-
const [tickValue, setRenderTick] = useState(0);
|
|
31
|
-
const notifyHeightChanged = useCallback(() => setRenderTick(t => t + 1), []);
|
|
32
30
|
const [agent] = useState(() => {
|
|
33
31
|
const agent = createAgent();
|
|
34
32
|
if (!agent.plugins.ui) {
|
|
@@ -43,6 +41,9 @@ export default function ChatContainer(props) {
|
|
|
43
41
|
});
|
|
44
42
|
return agent;
|
|
45
43
|
});
|
|
44
|
+
if (props.agentRef) {
|
|
45
|
+
props.agentRef.current = agent;
|
|
46
|
+
}
|
|
46
47
|
const uiAgent = useMemo(() => {
|
|
47
48
|
const session = {
|
|
48
49
|
get: agent.session.get,
|
|
@@ -57,72 +58,63 @@ export default function ChatContainer(props) {
|
|
|
57
58
|
});
|
|
58
59
|
return {
|
|
59
60
|
session,
|
|
60
|
-
plugins:
|
|
61
|
-
ui: agent.plugins.ui
|
|
62
|
-
},
|
|
61
|
+
plugins: agent.plugins,
|
|
63
62
|
pushInputBlocks: agent.pushInputBlocks,
|
|
64
63
|
emitTileEvent: agent.emitTileEvent,
|
|
65
64
|
removeMessage: agent.removeMessage
|
|
66
65
|
};
|
|
67
66
|
}, [agent]);
|
|
68
|
-
if (props.agentRef) {
|
|
69
|
-
props.agentRef.current = uiAgent;
|
|
70
|
-
}
|
|
71
67
|
useEffect(() => {
|
|
72
68
|
const {
|
|
73
69
|
onEvent,
|
|
74
70
|
emitEvent
|
|
75
71
|
} = agent.plugins.ui;
|
|
76
|
-
const offMessageListInit = onEvent('messageListInit',
|
|
72
|
+
const offMessageListInit = onEvent('messageListInit', _ref => {
|
|
77
73
|
let {
|
|
78
74
|
messages
|
|
79
75
|
} = _ref;
|
|
80
76
|
setMessages(messages);
|
|
81
|
-
notifyHeightChanged();
|
|
82
77
|
emitEvent('scrollToBottom', {
|
|
83
78
|
animation: false
|
|
84
79
|
});
|
|
85
80
|
});
|
|
86
|
-
const offMessageChange = onEvent('messageChange',
|
|
81
|
+
const offMessageChange = onEvent('messageChange', _ref2 => {
|
|
87
82
|
let {
|
|
88
83
|
type,
|
|
89
84
|
message
|
|
90
85
|
} = _ref2;
|
|
91
86
|
switch (type) {
|
|
92
87
|
case 'show':
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
});
|
|
99
|
-
break;
|
|
100
|
-
}
|
|
88
|
+
setMessages(prev => [...prev, message]);
|
|
89
|
+
emitEvent('scrollToBottom', {
|
|
90
|
+
animation: false
|
|
91
|
+
});
|
|
92
|
+
break;
|
|
101
93
|
case 'update':
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
94
|
+
setMessages(prev => {
|
|
95
|
+
if (systemInfo.platform === 'android') {
|
|
96
|
+
var _prev;
|
|
97
|
+
// Android 上有兼容问题,需要手动滚动到底部
|
|
98
|
+
if (((_prev = prev[prev.length - 1]) === null || _prev === void 0 ? void 0 : _prev.id) === message.id) {
|
|
99
|
+
// 是最后一条消息,滚动到最底部
|
|
100
|
+
emitEvent('scrollToBottom', {
|
|
101
|
+
animation: false,
|
|
102
|
+
follow: true
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return prev.map(item => {
|
|
107
|
+
if (item.id === message.id) {
|
|
108
|
+
return message;
|
|
109
|
+
}
|
|
110
|
+
return item;
|
|
111
111
|
});
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
});
|
|
113
|
+
break;
|
|
114
114
|
case 'remove':
|
|
115
|
-
{
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
notifyHeightChanged();
|
|
120
|
-
emitEvent('scrollToBottom', {
|
|
121
|
-
animation: false,
|
|
122
|
-
follow: true
|
|
123
|
-
});
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
115
|
+
setMessages(prev => {
|
|
116
|
+
return prev.filter(item => item.id !== message.id);
|
|
117
|
+
});
|
|
126
118
|
}
|
|
127
119
|
});
|
|
128
120
|
return () => {
|
|
@@ -130,6 +122,12 @@ export default function ChatContainer(props) {
|
|
|
130
122
|
offMessageChange();
|
|
131
123
|
};
|
|
132
124
|
}, [agent]);
|
|
125
|
+
const messageValue = useMemo(() => {
|
|
126
|
+
return {
|
|
127
|
+
messages,
|
|
128
|
+
keyboardHeight
|
|
129
|
+
};
|
|
130
|
+
}, [messages, keyboardHeight]);
|
|
133
131
|
useEffect(() => {
|
|
134
132
|
logger.debug('ChatProvider agent.start');
|
|
135
133
|
agent.start().then(() => {
|
|
@@ -183,14 +181,11 @@ export default function ChatContainer(props) {
|
|
|
183
181
|
className: cx('t-agent-chat-container', className, {
|
|
184
182
|
't-agent-chat-container-keyboard-show': keyboardHeight > 0
|
|
185
183
|
})
|
|
186
|
-
}, /*#__PURE__*/React.createElement(
|
|
187
|
-
value:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
renderOptions
|
|
194
|
-
}
|
|
195
|
-
}, children));
|
|
184
|
+
}, /*#__PURE__*/React.createElement(ChatAgentContext.Provider, {
|
|
185
|
+
value: uiAgent
|
|
186
|
+
}, /*#__PURE__*/React.createElement(RenderContext.Provider, {
|
|
187
|
+
value: renderOptions
|
|
188
|
+
}, /*#__PURE__*/React.createElement(MessageContext.Provider, {
|
|
189
|
+
value: messageValue
|
|
190
|
+
}, children))));
|
|
196
191
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import Render from './index.rjs';
|
|
2
2
|
import logger from '../logger';
|
|
3
|
+
import { systemInfo } from '../utils';
|
|
3
4
|
|
|
4
5
|
// eslint-disable-next-line no-undef
|
|
5
6
|
Component({
|
|
@@ -46,12 +47,9 @@ Component({
|
|
|
46
47
|
});
|
|
47
48
|
const data = JSON.parse(content);
|
|
48
49
|
if (data.option) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} else {
|
|
53
|
-
this.rjs.update(data.option);
|
|
54
|
-
}
|
|
50
|
+
// eslint-disable-next-line no-undef
|
|
51
|
+
const pixelRatio = systemInfo.pixelRatio;
|
|
52
|
+
this.rjs.update(this.data.canvasId, pixelRatio, data.option);
|
|
55
53
|
this.setData({
|
|
56
54
|
loading: false,
|
|
57
55
|
error: false
|
|
@@ -1,41 +1,15 @@
|
|
|
1
1
|
export default Render({
|
|
2
2
|
myChart: null,
|
|
3
|
-
option
|
|
4
|
-
|
|
5
|
-
const { pixelRatio } = this.instance.getSystemInfo()
|
|
6
|
-
this.option = option
|
|
7
|
-
try {
|
|
3
|
+
async update(canvasId, devicePixelRatio, option) {
|
|
4
|
+
if (!this.myChart) {
|
|
8
5
|
const canvas = await this.instance.getCanvasById(canvasId)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
myChart.setOption(this.option, true)
|
|
15
|
-
this.myChart = myChart;
|
|
16
|
-
}
|
|
17
|
-
} catch (err) {
|
|
18
|
-
// ignore
|
|
6
|
+
const echarts = await requirePlugin('rjs://echarts')
|
|
7
|
+
|
|
8
|
+
this.myChart = echarts.init(canvas, undefined, {
|
|
9
|
+
devicePixelRatio,
|
|
10
|
+
})
|
|
19
11
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.option = option
|
|
23
|
-
if (this.myChart) {
|
|
24
|
-
this.myChart.setOption(this.option, true)
|
|
25
|
-
}
|
|
26
|
-
// const { pixelRatio } = this.instance.getSystemInfo()
|
|
27
|
-
// if (!this.myChart) {
|
|
28
|
-
// const canvas = await this.instance.getCanvasById(canvasId)
|
|
29
|
-
// console.log(`EchartsBlockRender init render, ${canvasId}`, Object.keys(canvas))
|
|
30
|
-
// if (canvas) {
|
|
31
|
-
// const echarts = await requirePlugin('rjs://echarts')
|
|
32
|
-
// this.myChart = echarts.init(canvas, undefined, {
|
|
33
|
-
// devicePixelRatio: pixelRatio,
|
|
34
|
-
// })
|
|
35
|
-
// }
|
|
36
|
-
// }
|
|
37
|
-
// console.log(`EchartsBlockRender set option, ${canvasId}`)
|
|
38
|
-
// // 使用刚指定的配置项和数据显示图表。
|
|
39
|
-
// this.myChart.setOption(option, true)
|
|
12
|
+
// 使用刚指定的配置项和数据显示图表。
|
|
13
|
+
this.myChart.setOption(option, true)
|
|
40
14
|
},
|
|
41
15
|
})
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import "core-js/modules/esnext.iterator.constructor.js";
|
|
2
2
|
import "core-js/modules/esnext.iterator.map.js";
|
|
3
3
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
4
|
-
import React, {
|
|
4
|
+
import React, { useState } from 'react';
|
|
5
5
|
import { View } from '@ray-js/ray';
|
|
6
|
+
import { useOnEvent } from '../../hooks';
|
|
6
7
|
export const WaveformVisualizer = _ref => {
|
|
7
8
|
let {
|
|
8
9
|
amplitudeCount
|
|
@@ -20,34 +21,26 @@ export const WaveformVisualizer = _ref => {
|
|
|
20
21
|
animationDelay: "".concat(index * 10, "ms")
|
|
21
22
|
}
|
|
22
23
|
})));
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// 添加渐变色偏移效果
|
|
40
|
-
animationDelay: "".concat(index * 10, "ms")
|
|
41
|
-
}
|
|
42
|
-
});
|
|
24
|
+
useOnEvent('amplitudes', val => {
|
|
25
|
+
const waveBase = val.body.amplitudes || [];
|
|
26
|
+
const bars = waveBase.map((item, index) => {
|
|
27
|
+
const value = item > 1 ? 1 : item * 100;
|
|
28
|
+
// 将数值映射到高度范围(0-100 → 2px-20px)
|
|
29
|
+
// const height = 2 + (value / 100) * 18;
|
|
30
|
+
return /*#__PURE__*/React.createElement(View
|
|
31
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
32
|
+
, {
|
|
33
|
+
key: "asr_wave_".concat(index),
|
|
34
|
+
className: "t-agent-message-input-waveform-bar",
|
|
35
|
+
style: {
|
|
36
|
+
height: "".concat(value, "%"),
|
|
37
|
+
// 添加渐变色偏移效果
|
|
38
|
+
animationDelay: "".concat(index * 10, "ms")
|
|
39
|
+
}
|
|
43
40
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return () => {
|
|
48
|
-
ty.aistream.offRecordAmplitudes(handle);
|
|
49
|
-
};
|
|
50
|
-
}, []);
|
|
41
|
+
});
|
|
42
|
+
setBars(bars);
|
|
43
|
+
});
|
|
51
44
|
return /*#__PURE__*/React.createElement(View, {
|
|
52
45
|
className: "t-agent-message-input-waveform-container"
|
|
53
46
|
}, bars);
|
|
@@ -17,7 +17,6 @@ import { useAttachmentInput, useChatAgent, useEmitEvent, useIsUnmounted, useOnEv
|
|
|
17
17
|
import AsrInput from './AsrInput';
|
|
18
18
|
import logger from '../../logger';
|
|
19
19
|
import { systemInfo } from '../../utils';
|
|
20
|
-
import { useSleep } from '../../hooks/useSleep';
|
|
21
20
|
const AMPLITUDE_COUNT = 60;
|
|
22
21
|
var InputState = /*#__PURE__*/function (InputState) {
|
|
23
22
|
InputState["PENDING"] = "pending";
|
|
@@ -197,7 +196,6 @@ export default function MessageInputAIStream(props) {
|
|
|
197
196
|
const canSend = text.trim().length && state.current === InputState.PENDING && !attachmentInput.uploading;
|
|
198
197
|
const canAbort = state.current === InputState.RESPONDING || state.current === InputState.ASR;
|
|
199
198
|
const recordingFlagRef = useRef(false);
|
|
200
|
-
const sleep = useSleep();
|
|
201
199
|
if (mode === 'text') {
|
|
202
200
|
container = /*#__PURE__*/React.createElement(View, {
|
|
203
201
|
className: "t-agent-message-input-text-bar"
|
|
@@ -225,13 +223,6 @@ export default function MessageInputAIStream(props) {
|
|
|
225
223
|
emitEvent('scrollToBottom', {
|
|
226
224
|
animation: true
|
|
227
225
|
});
|
|
228
|
-
},
|
|
229
|
-
onBlur: () => {
|
|
230
|
-
sleep(200).then(() => {
|
|
231
|
-
emitEvent('scrollToBottom', {
|
|
232
|
-
follow: true
|
|
233
|
-
});
|
|
234
|
-
});
|
|
235
226
|
}
|
|
236
227
|
}), /*#__PURE__*/React.createElement(Button, {
|
|
237
228
|
"data-testid": "t-agent-message-input-button-asr",
|
|
@@ -6,8 +6,6 @@ interface Props {
|
|
|
6
6
|
wrapperClassName?: string;
|
|
7
7
|
wrapperStyle?: React.CSSProperties;
|
|
8
8
|
renderTop?: React.ReactNode;
|
|
9
|
-
renderBottom?: React.ReactNode;
|
|
10
|
-
onScroll?: (event: any) => void;
|
|
11
9
|
roleSide?: {
|
|
12
10
|
user?: 'start' | 'end' | string;
|
|
13
11
|
assistant?: 'start' | 'end' | string;
|
|
@@ -20,5 +18,5 @@ interface Props {
|
|
|
20
18
|
tipText: string;
|
|
21
19
|
};
|
|
22
20
|
}
|
|
23
|
-
|
|
24
|
-
export
|
|
21
|
+
export default function MessageList(props: Props): React.JSX.Element;
|
|
22
|
+
export {};
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
+
import "core-js/modules/es.array.reverse.js";
|
|
1
3
|
import "core-js/modules/esnext.iterator.constructor.js";
|
|
2
4
|
import "core-js/modules/esnext.iterator.map.js";
|
|
3
5
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
4
6
|
import './index.less';
|
|
5
7
|
import { View } from '@ray-js/components';
|
|
6
|
-
import React from 'react';
|
|
8
|
+
import React, { useMemo, useRef, useState } from 'react';
|
|
9
|
+
import { ScrollView } from '@ray-js/ray';
|
|
10
|
+
import { generateId } from '@ray-js/t-agent';
|
|
7
11
|
import MessageRender from '../MessageRender';
|
|
8
|
-
import { useAgentMessage, useAgentSessionValue } from '../hooks';
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
+
import { useAgentMessage, useAgentSessionValue, useOnEvent } from '../hooks';
|
|
13
|
+
import { useDebouncedFn } from '../hooks/useDebouncedFn';
|
|
14
|
+
import { useSleep } from '../hooks/useSleep';
|
|
15
|
+
import { systemInfo } from '../utils';
|
|
16
|
+
export default function MessageList(props) {
|
|
12
17
|
const {
|
|
13
18
|
className,
|
|
14
19
|
roleSide,
|
|
@@ -17,38 +22,97 @@ const MessageList = props => {
|
|
|
17
22
|
wrapperStyle,
|
|
18
23
|
historyLimit
|
|
19
24
|
} = props;
|
|
20
|
-
const
|
|
21
|
-
|
|
25
|
+
const {
|
|
26
|
+
messages
|
|
27
|
+
} = useAgentMessage();
|
|
28
|
+
const [id] = useState(() => "ScrollView-".concat(generateId()));
|
|
29
|
+
const [scrollAnimation, setScrollAnimation] = useState(false);
|
|
30
|
+
// 最大整数位数,用于强制滚动到底部,收到连续 scrollToBottom 时,每 10 毫秒更新一次
|
|
31
|
+
const [scrollTop, setScrollTop] = useState(() => 1000000000000000 + Math.floor(Date.now() / 10));
|
|
32
|
+
const followNewMessageRef = useRef(true);
|
|
33
|
+
const sleep = useSleep();
|
|
22
34
|
const [showSelect] = useAgentSessionValue('UIRay.multiSelect.show');
|
|
35
|
+
const canIUse = useMemo(() => {
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
const {
|
|
38
|
+
containerVersion
|
|
39
|
+
} = systemInfo;
|
|
40
|
+
return {
|
|
41
|
+
// 在 2.27.2 版本之前,pageScrollTo 在某些场景不生效
|
|
42
|
+
scroll: false
|
|
43
|
+
};
|
|
44
|
+
}, []);
|
|
45
|
+
const scroll = useDebouncedFn(animation => {
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
ty.pageScrollTo({
|
|
48
|
+
scrollTop: 0,
|
|
49
|
+
duration: animation ? 100 : 1,
|
|
50
|
+
selector: "#".concat(id)
|
|
51
|
+
});
|
|
52
|
+
}, 100);
|
|
53
|
+
|
|
54
|
+
// 强制滚动到底部
|
|
55
|
+
useOnEvent('scrollToBottom', _ref => {
|
|
56
|
+
let {
|
|
57
|
+
animation,
|
|
58
|
+
follow
|
|
59
|
+
} = _ref;
|
|
60
|
+
// 如果发送的跟随新消息的滚动,判断当前是不是滚动到了底部,如果没有滚动到底部,不执行滚动
|
|
61
|
+
if (follow && !followNewMessageRef.current) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (canIUse.scroll) {
|
|
65
|
+
scroll(animation);
|
|
66
|
+
} else {
|
|
67
|
+
sleep(100).then(() => {
|
|
68
|
+
setScrollAnimation(!!animation);
|
|
69
|
+
const top = 1000000000000000 + Math.floor(Date.now() / 10);
|
|
70
|
+
if (top !== scrollTop) {
|
|
71
|
+
setScrollTop(top);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 使用翻转列表,让滚动和新消息出现在第一条,这样可以避免滚动到底部时的闪烁
|
|
78
|
+
const reversed = useMemo(() => [...messages].reverse(), [messages]);
|
|
79
|
+
const scrollProps = canIUse.scroll ? {} : {
|
|
80
|
+
scrollWithAnimation: scrollAnimation,
|
|
81
|
+
scrollTop
|
|
82
|
+
};
|
|
23
83
|
return /*#__PURE__*/React.createElement(View, {
|
|
24
84
|
className: "t-agent-message-list ".concat(wrapperClassName || ''),
|
|
25
85
|
"data-testid": "t-agent-message-list",
|
|
26
|
-
style: wrapperStyle
|
|
27
|
-
|
|
28
|
-
}, /*#__PURE__*/React.createElement(ScrollBottomView, {
|
|
86
|
+
style: wrapperStyle
|
|
87
|
+
}, /*#__PURE__*/React.createElement(ScrollView, _extends({
|
|
29
88
|
className: "".concat(className || '', " t-agent-message-list-scroll"),
|
|
30
|
-
contentClassName: "t-agent-message-list-scroll-content",
|
|
31
89
|
style: style,
|
|
32
|
-
|
|
33
|
-
},
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
90
|
+
id: id
|
|
91
|
+
}, scrollProps, {
|
|
92
|
+
refresherTriggered: false,
|
|
93
|
+
enableFlex: true,
|
|
94
|
+
scrollY: true,
|
|
95
|
+
onScroll: event => {
|
|
96
|
+
// 使用了 flex-direction: column-reverse,所以滚动到顶部时,scrollTop = 0
|
|
97
|
+
followNewMessageRef.current = event.detail.scrollTop > -10;
|
|
98
|
+
}
|
|
99
|
+
}), /*#__PURE__*/React.createElement(View, {
|
|
100
|
+
className: "t-agent-message-list-padding"
|
|
101
|
+
}), reversed.map((msg, index) => {
|
|
38
102
|
let side = roleSide === null || roleSide === void 0 ? void 0 : roleSide[msg.role];
|
|
39
103
|
if (!side) {
|
|
40
104
|
side = msg.role === 'user' ? 'end' : 'start';
|
|
41
105
|
}
|
|
42
|
-
const isLatestMessage = index === messages.length - 1;
|
|
43
106
|
return /*#__PURE__*/React.createElement(MessageRender, {
|
|
44
107
|
showSelect: showSelect,
|
|
45
108
|
key: msg.id,
|
|
46
109
|
message: msg,
|
|
47
|
-
isLatestMessage:
|
|
110
|
+
isLatestMessage: index === 0,
|
|
48
111
|
side: side
|
|
49
112
|
});
|
|
50
|
-
}),
|
|
51
|
-
className: "t-agent-message-list-
|
|
113
|
+
}), historyLimit && historyLimit.count < reversed.length && /*#__PURE__*/React.createElement(View, {
|
|
114
|
+
className: "t-agent-message-list-history-tip"
|
|
115
|
+
}, historyLimit.tipText), props.renderTop, /*#__PURE__*/React.createElement(View, {
|
|
116
|
+
className: "t-agent-message-list-padding-start"
|
|
52
117
|
})));
|
|
53
|
-
}
|
|
54
|
-
export default MessageList;
|
|
118
|
+
}
|
|
@@ -4,32 +4,21 @@
|
|
|
4
4
|
overflow-x: hidden;
|
|
5
5
|
position: relative;
|
|
6
6
|
background: var(--app-B1);
|
|
7
|
+
padding: 16rpx 32rpx 0;
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
.t-agent-message-list-scroll {
|
|
11
|
+
display: flex;
|
|
10
12
|
width: 100%;
|
|
11
13
|
height: 100%;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.t-agent-message-list-scroll-content {
|
|
15
|
-
padding: 0 32rpx;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.t-agent-message-list-block {
|
|
19
|
-
border: 2rpx solid green;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.t-agent-message-list-padding-start {
|
|
23
|
-
height: 16rpx;
|
|
14
|
+
flex-direction: column-reverse;
|
|
24
15
|
}
|
|
25
16
|
|
|
26
17
|
.t-agent-message-list-padding {
|
|
27
18
|
flex: 1
|
|
28
19
|
}
|
|
29
20
|
|
|
30
|
-
.t-agent-message-list-
|
|
31
|
-
opacity: 0;
|
|
32
|
-
}
|
|
21
|
+
.t-agent-message-list-padding-start {}
|
|
33
22
|
|
|
34
23
|
.t-agent-message-list-history-tip {
|
|
35
24
|
width: 100%;
|
package/dist/TileRender/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './index.less';
|
|
2
2
|
import React, { useCallback, useMemo } from 'react';
|
|
3
|
-
import { useChatAgent,
|
|
3
|
+
import { useChatAgent, useRenderOptions } from '../hooks';
|
|
4
4
|
import { TilePropsContext } from '../contexts';
|
|
5
5
|
const TileRender = _ref => {
|
|
6
6
|
let {
|
|
@@ -11,7 +11,6 @@ const TileRender = _ref => {
|
|
|
11
11
|
} = _ref;
|
|
12
12
|
const agent = useChatAgent();
|
|
13
13
|
const emitTileEvent = useCallback(async payload => agent.emitTileEvent(tile.id, payload), [agent, tile.id]);
|
|
14
|
-
const notifyHeightChanged = useNotifyHeightChanged();
|
|
15
14
|
const {
|
|
16
15
|
renderTileAs
|
|
17
16
|
} = useRenderOptions();
|
|
@@ -23,10 +22,9 @@ const TileRender = _ref => {
|
|
|
23
22
|
side,
|
|
24
23
|
isLatestMessage,
|
|
25
24
|
emitEvent: emitTileEvent,
|
|
26
|
-
emitTileEvent
|
|
27
|
-
notifyHeightChanged
|
|
25
|
+
emitTileEvent
|
|
28
26
|
};
|
|
29
|
-
}, [agent, tile, message, side, isLatestMessage, emitTileEvent
|
|
27
|
+
}, [agent, tile, message, side, isLatestMessage, emitTileEvent]);
|
|
30
28
|
const node = renderTileAs(props);
|
|
31
29
|
return /*#__PURE__*/React.createElement(TilePropsContext.Provider, {
|
|
32
30
|
value: props
|
package/dist/contexts.d.ts
CHANGED
|
@@ -2,26 +2,14 @@
|
|
|
2
2
|
import { ChatAgent, ChatMessageObject, UIPlugin } from '@ray-js/t-agent';
|
|
3
3
|
import { RenderOptions, TileProps } from './types';
|
|
4
4
|
import { ChatSession } from '@ray-js/t-agent';
|
|
5
|
+
export declare const MessageContext: import("react").Context<{
|
|
6
|
+
messages: ChatMessageObject[];
|
|
7
|
+
keyboardHeight: number;
|
|
8
|
+
}>;
|
|
9
|
+
export declare const RenderContext: import("react").Context<RenderOptions>;
|
|
5
10
|
export type UIChatSession = Pick<ChatSession, 'get' | 'getData' | 'set' | 'sessionId'>;
|
|
6
11
|
export type UIChatAgent = Pick<ChatAgent<UIPlugin>, 'pushInputBlocks' | 'plugins' | 'emitTileEvent' | 'removeMessage'> & {
|
|
7
12
|
session: UIChatSession;
|
|
8
13
|
};
|
|
14
|
+
export declare const ChatAgentContext: import("react").Context<UIChatAgent>;
|
|
9
15
|
export declare const TilePropsContext: import("react").Context<TileProps<any, any>>;
|
|
10
|
-
declare const SharedProvider: ({ value, children }: import("react").PropsWithChildren<{
|
|
11
|
-
value: {
|
|
12
|
-
agent: UIChatAgent;
|
|
13
|
-
messages: ChatMessageObject[];
|
|
14
|
-
keyboardHeight: number;
|
|
15
|
-
renderOptions: RenderOptions;
|
|
16
|
-
notifyHeightChanged: () => void;
|
|
17
|
-
tickValue: number;
|
|
18
|
-
};
|
|
19
|
-
}>) => import("react").JSX.Element, useSharedState: <K extends "agent" | "messages" | "keyboardHeight" | "renderOptions" | "notifyHeightChanged" | "tickValue">(key: K) => {
|
|
20
|
-
agent: UIChatAgent;
|
|
21
|
-
messages: ChatMessageObject[];
|
|
22
|
-
keyboardHeight: number;
|
|
23
|
-
renderOptions: RenderOptions;
|
|
24
|
-
notifyHeightChanged: () => void;
|
|
25
|
-
tickValue: number;
|
|
26
|
-
}[K];
|
|
27
|
-
export { SharedProvider, useSharedState };
|
package/dist/contexts.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
2
1
|
import { createContext } from 'react';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
export const MessageContext = /*#__PURE__*/createContext({
|
|
3
|
+
messages: [],
|
|
4
|
+
keyboardHeight: 0
|
|
5
|
+
});
|
|
6
|
+
export const RenderContext = /*#__PURE__*/createContext({
|
|
7
|
+
formatErrorMessageAs: message => message,
|
|
8
|
+
renderTileAs: () => null,
|
|
9
|
+
renderCustomBlockAs: () => null,
|
|
10
|
+
renderCardAs: () => null,
|
|
11
|
+
renderLongPressAs: () => null,
|
|
12
|
+
customBlockTypes: [],
|
|
13
|
+
customCardMap: {},
|
|
14
|
+
getStaticResourceBizType: () => '',
|
|
15
|
+
i18nTranslate: key => key
|
|
16
|
+
});
|
|
17
|
+
export const ChatAgentContext = /*#__PURE__*/createContext({});
|
|
18
|
+
export const TilePropsContext = /*#__PURE__*/createContext({});
|
package/dist/hooks/context.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Dispatch, SetStateAction } from 'react';
|
|
2
2
|
import { TTTAction } from '../types';
|
|
3
3
|
export declare const useChatAgent: () => import("../contexts").UIChatAgent;
|
|
4
|
-
export declare const
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export declare const useAgentMessage: () => {
|
|
5
|
+
messages: import("@ray-js/t-agent").ChatMessageObject[];
|
|
6
|
+
keyboardHeight: number;
|
|
7
|
+
};
|
|
7
8
|
export declare const useRenderOptions: () => import("../types").RenderOptions;
|
|
8
|
-
export declare const useKeyboardHeight: () => number;
|
|
9
9
|
export declare const useOnEvent: (eventName: string, callback: (details: any) => void) => void;
|
|
10
10
|
export declare const useEmitEvent: () => <T extends keyof import("@ray-js/t-agent").UIEventMap>(eventName: T, detail: import("@ray-js/t-agent").UIEventMap[T]) => void;
|
|
11
11
|
export declare const useTileProps: () => import("../types").TileProps<any, any>;
|
package/dist/hooks/context.js
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
2
2
|
import { useEffect, useContext, useCallback, useRef, useState } from 'react';
|
|
3
|
-
import { TilePropsContext,
|
|
3
|
+
import { TilePropsContext, ChatAgentContext, MessageContext, RenderContext } from '../contexts';
|
|
4
4
|
export const useChatAgent = () => {
|
|
5
|
-
return
|
|
6
|
-
};
|
|
7
|
-
export const useTick = () => {
|
|
8
|
-
return useSharedState('tickValue');
|
|
9
|
-
};
|
|
10
|
-
export const useNotifyHeightChanged = () => {
|
|
11
|
-
return useSharedState('notifyHeightChanged');
|
|
5
|
+
return useContext(ChatAgentContext);
|
|
12
6
|
};
|
|
13
7
|
export const useAgentMessage = () => {
|
|
14
|
-
return
|
|
8
|
+
return useContext(MessageContext);
|
|
15
9
|
};
|
|
16
10
|
export const useRenderOptions = () => {
|
|
17
|
-
return
|
|
18
|
-
};
|
|
19
|
-
export const useKeyboardHeight = () => {
|
|
20
|
-
return useSharedState('keyboardHeight');
|
|
11
|
+
return useContext(RenderContext);
|
|
21
12
|
};
|
|
22
13
|
export const useOnEvent = (eventName, callback) => {
|
|
23
14
|
const callbackRef = useRef(callback);
|
|
@@ -108,13 +108,13 @@ const BubbleTile = props => {
|
|
|
108
108
|
}), /*#__PURE__*/React.createElement(View, {
|
|
109
109
|
className: "t-agent-bubble-tile-bubble ".concat(loading ? 't-agent-bubble-tile-bubble-loading' : '')
|
|
110
110
|
}, (() => {
|
|
111
|
-
return children.map(t => /*#__PURE__*/React.createElement(TileRender, {
|
|
111
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, children.map(t => /*#__PURE__*/React.createElement(TileRender, {
|
|
112
112
|
side: side,
|
|
113
113
|
tile: t,
|
|
114
114
|
message: message,
|
|
115
115
|
key: t.id,
|
|
116
116
|
isLatestMessage: isLatestMessage
|
|
117
|
-
}));
|
|
117
|
+
})));
|
|
118
118
|
})(), /*#__PURE__*/React.createElement(LoadingIndicator, {
|
|
119
119
|
status: status
|
|
120
120
|
}), showAbortedMessage && /*#__PURE__*/React.createElement(View, {
|
|
@@ -126,6 +126,7 @@ const BubbleTile = props => {
|
|
|
126
126
|
nodeId: workflowNode
|
|
127
127
|
}));
|
|
128
128
|
};
|
|
129
|
+
export default /*#__PURE__*/React.memo(BubbleTile);
|
|
129
130
|
const ErrorNotice = /*#__PURE__*/memo(_ref => {
|
|
130
131
|
let {
|
|
131
132
|
bubbleStatus,
|
|
@@ -171,5 +172,4 @@ const LoadingIndicator = /*#__PURE__*/memo(_ref2 => {
|
|
|
171
172
|
}));
|
|
172
173
|
}
|
|
173
174
|
return null;
|
|
174
|
-
});
|
|
175
|
-
export default /*#__PURE__*/React.memo(BubbleTile);
|
|
175
|
+
});
|
|
@@ -7,7 +7,7 @@ import React, { useMemo, useState } from 'react';
|
|
|
7
7
|
import './index.less';
|
|
8
8
|
// import { ChangeInfoItem, DeviceInfoItem, SceneInfoItem } from '@ray-js/t-agent-plugin-assistant';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { useTranslate } from '../../hooks';
|
|
11
11
|
import Expand from './Expand';
|
|
12
12
|
import { formatMessage } from '../../utils';
|
|
13
13
|
const handleDesc = (detail, t) => {
|
|
@@ -197,9 +197,6 @@ export default function OperateCardTile(props) {
|
|
|
197
197
|
};
|
|
198
198
|
}, [deviceInfo, sceneInfo, changeInfo, t]);
|
|
199
199
|
const desc = useMemo(() => handleDesc(operations, t), [operations, t]);
|
|
200
|
-
const {
|
|
201
|
-
notifyHeightChanged
|
|
202
|
-
} = useTileProps();
|
|
203
200
|
if (!operations.device.length && !operations.scene.length && !operations.moreDevice.length && !operations.moreScene.length) {
|
|
204
201
|
return null;
|
|
205
202
|
}
|
|
@@ -211,7 +208,6 @@ export default function OperateCardTile(props) {
|
|
|
211
208
|
className: "t-agent-scene-control-tile-summary-detail",
|
|
212
209
|
onClick: () => {
|
|
213
210
|
setShowDetail(!showDetail);
|
|
214
|
-
notifyHeightChanged();
|
|
215
211
|
}
|
|
216
212
|
}, showDetail ? t('t-agent.operate-card-tile.hide.details') : t('t-agent.operate-card-tile.view.details'))), renderDetail && renderDetail({
|
|
217
213
|
operations,
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ray-js/t-agent-ui-ray",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1-beta.2",
|
|
4
4
|
"author": "Tuya.inc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"@types/echarts": "^4.9.22",
|
|
41
41
|
"@types/markdown-it": "^14.1.1"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "3d7b5c0ca1816855f1a0c4a2da3e59ad44f1b6da"
|
|
44
44
|
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import "core-js/modules/es.regexp.exec.js";
|
|
2
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
3
|
-
import { View } from '@ray-js/components';
|
|
4
|
-
import React, { useEffect, useRef, useState } from 'react';
|
|
5
|
-
import { usePageInstance } from '@ray-js/ray';
|
|
6
|
-
const queryHeight = id => {
|
|
7
|
-
return new Promise(resolve => {
|
|
8
|
-
// @ts-ignore
|
|
9
|
-
const query = ty.createSelectorQuery();
|
|
10
|
-
query.select("#".concat(id)).boundingClientRect(res => {
|
|
11
|
-
resolve(res.height);
|
|
12
|
-
}).exec();
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
export default function LazyView(props) {
|
|
16
|
-
const {
|
|
17
|
-
id,
|
|
18
|
-
className,
|
|
19
|
-
children,
|
|
20
|
-
containerId
|
|
21
|
-
} = props;
|
|
22
|
-
const [visible, setVisible] = useState(true);
|
|
23
|
-
const heightRef = useRef(0);
|
|
24
|
-
const valid = heightRef.current > 0;
|
|
25
|
-
console.log();
|
|
26
|
-
const page = usePageInstance();
|
|
27
|
-
useEffect(() => {
|
|
28
|
-
// @ts-ignore
|
|
29
|
-
const observer = ty.createIntersectionObserver(page, {
|
|
30
|
-
thresholds: [0, 1],
|
|
31
|
-
initialRatio: 0
|
|
32
|
-
});
|
|
33
|
-
observer.relativeTo("#".concat(containerId), {
|
|
34
|
-
top: 50,
|
|
35
|
-
bottom: 50
|
|
36
|
-
}).observe("#".concat(id), res => {
|
|
37
|
-
setVisible(res.intersectionRatio > 0);
|
|
38
|
-
console.log(id, res);
|
|
39
|
-
});
|
|
40
|
-
return () => {
|
|
41
|
-
observer.disconnect();
|
|
42
|
-
};
|
|
43
|
-
}, [id, containerId]);
|
|
44
|
-
useEffect(() => {
|
|
45
|
-
queryHeight(id).then(height => {
|
|
46
|
-
console.log('queryHeight', id, height);
|
|
47
|
-
heightRef.current = height;
|
|
48
|
-
});
|
|
49
|
-
}, [id]);
|
|
50
|
-
console.log('rerender', id);
|
|
51
|
-
return /*#__PURE__*/React.createElement(View, {
|
|
52
|
-
className: className,
|
|
53
|
-
"data-hide": !visible && valid,
|
|
54
|
-
id: id
|
|
55
|
-
// style={hide ? { visibility: 'hidden' } : null}
|
|
56
|
-
}, children);
|
|
57
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
interface ScrollBottomViewParams {
|
|
3
|
-
onScroll?: (event: any) => void;
|
|
4
|
-
}
|
|
5
|
-
export declare function useScrollBottomView(params: ScrollBottomViewParams): {
|
|
6
|
-
scrollToBottom: ({ animation, follow }: {
|
|
7
|
-
animation?: boolean | undefined;
|
|
8
|
-
follow?: boolean | undefined;
|
|
9
|
-
}) => void;
|
|
10
|
-
scrollViewLoading: boolean;
|
|
11
|
-
scrollIntoViewId: string;
|
|
12
|
-
contentViewProps: {
|
|
13
|
-
contentViewId: string;
|
|
14
|
-
};
|
|
15
|
-
scrollViewProps: {
|
|
16
|
-
'data-render-tick': number;
|
|
17
|
-
id: string;
|
|
18
|
-
scrollY: boolean;
|
|
19
|
-
onScroll: (event: {
|
|
20
|
-
detail: {
|
|
21
|
-
scrollTop: number;
|
|
22
|
-
scrollHeight: number;
|
|
23
|
-
deltaY: number;
|
|
24
|
-
};
|
|
25
|
-
currentTarget: any;
|
|
26
|
-
timeStamp: number;
|
|
27
|
-
}) => void;
|
|
28
|
-
scrollWithAnimation: boolean;
|
|
29
|
-
scrollIntoView: string;
|
|
30
|
-
};
|
|
31
|
-
};
|
|
32
|
-
interface Props {
|
|
33
|
-
className?: string;
|
|
34
|
-
contentClassName?: string;
|
|
35
|
-
children: React.ReactNode;
|
|
36
|
-
style?: React.CSSProperties;
|
|
37
|
-
onScroll?: (event: any) => void;
|
|
38
|
-
}
|
|
39
|
-
interface Ref {
|
|
40
|
-
scrollToBottom: (options?: {
|
|
41
|
-
animation?: boolean;
|
|
42
|
-
follow?: boolean;
|
|
43
|
-
}) => void;
|
|
44
|
-
}
|
|
45
|
-
declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Props & React.RefAttributes<Ref>>>;
|
|
46
|
-
export default _default;
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
2
|
-
import "core-js/modules/es.regexp.exec.js";
|
|
3
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
4
|
-
import React, { useCallback, useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react';
|
|
5
|
-
import { useSleep } from '../hooks/useSleep';
|
|
6
|
-
import { generateId } from '@ray-js/t-agent';
|
|
7
|
-
import { useOnEvent, useTick } from '../hooks';
|
|
8
|
-
import { ScrollView } from '@ray-js/ray';
|
|
9
|
-
import { View } from '@ray-js/components';
|
|
10
|
-
export function useScrollBottomView(params) {
|
|
11
|
-
const [scrollViewId] = useState(() => "ScrollView-".concat(generateId()));
|
|
12
|
-
const contentViewId = "".concat(scrollViewId, "-content");
|
|
13
|
-
const tickValue = useTick();
|
|
14
|
-
const [ready, setReady] = useState(false);
|
|
15
|
-
const [scrollIntoViewFlag, setScrollIntoViewIdFlag] = useState(() => "".concat(Date.now()));
|
|
16
|
-
const [scrollWithAnimation, setScrollWithAnimation] = useState(false);
|
|
17
|
-
const ref = useRef({
|
|
18
|
-
clientHeight: 0,
|
|
19
|
-
needFollow: true,
|
|
20
|
-
following: false,
|
|
21
|
-
lastScrollEvent: null,
|
|
22
|
-
startTimestamp: 0
|
|
23
|
-
});
|
|
24
|
-
const sleep = useSleep();
|
|
25
|
-
const makeScrollBottomEvent = useCallback(() => {
|
|
26
|
-
if (ref.current.lastScrollEvent) {
|
|
27
|
-
const {
|
|
28
|
-
detail,
|
|
29
|
-
currentTarget,
|
|
30
|
-
target
|
|
31
|
-
} = ref.current.lastScrollEvent;
|
|
32
|
-
const {
|
|
33
|
-
scrollTop,
|
|
34
|
-
scrollHeight
|
|
35
|
-
} = detail;
|
|
36
|
-
const newDetail = {
|
|
37
|
-
deltaX: 0,
|
|
38
|
-
scrollLeft: 0,
|
|
39
|
-
scrollTop: scrollHeight - ref.current.clientHeight,
|
|
40
|
-
scrollWidth: detail.scrollWidth,
|
|
41
|
-
scrollHeight,
|
|
42
|
-
deltaY: scrollTop - (scrollHeight - ref.current.clientHeight)
|
|
43
|
-
};
|
|
44
|
-
if (scrollTop === newDetail.scrollTop) {
|
|
45
|
-
// 如果滚动位置没有变化,则不触发事件
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
type: 'scroll',
|
|
50
|
-
timeStamp: Date.now() - ref.current.startTimestamp,
|
|
51
|
-
currentTarget,
|
|
52
|
-
target,
|
|
53
|
-
stopPropagation: () => {},
|
|
54
|
-
detail: newDetail
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
return null;
|
|
58
|
-
}, []);
|
|
59
|
-
const scrollToBottom = useCallback(_ref => {
|
|
60
|
-
let {
|
|
61
|
-
animation,
|
|
62
|
-
follow
|
|
63
|
-
} = _ref;
|
|
64
|
-
if (follow) {
|
|
65
|
-
if (ref.current.needFollow) {
|
|
66
|
-
setScrollIntoViewIdFlag("".concat(Date.now()));
|
|
67
|
-
ref.current.needFollow = true;
|
|
68
|
-
const event = makeScrollBottomEvent();
|
|
69
|
-
if (event) {
|
|
70
|
-
sleep(10).then(() => {
|
|
71
|
-
var _params$onScroll;
|
|
72
|
-
params === null || params === void 0 || (_params$onScroll = params.onScroll) === null || _params$onScroll === void 0 || _params$onScroll.call(params, event);
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
} else {
|
|
77
|
-
if (animation) {
|
|
78
|
-
setScrollWithAnimation(true);
|
|
79
|
-
}
|
|
80
|
-
ref.current.needFollow = true;
|
|
81
|
-
setScrollIntoViewIdFlag("".concat(Date.now()));
|
|
82
|
-
const event = makeScrollBottomEvent();
|
|
83
|
-
if (event) {
|
|
84
|
-
sleep(100).then(() => {
|
|
85
|
-
var _params$onScroll2;
|
|
86
|
-
params === null || params === void 0 || (_params$onScroll2 = params.onScroll) === null || _params$onScroll2 === void 0 || _params$onScroll2.call(params, event);
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
if (animation) {
|
|
90
|
-
sleep(10).then(() => {
|
|
91
|
-
setScrollWithAnimation(false);
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}, []);
|
|
96
|
-
useEffect(() => {
|
|
97
|
-
const getDomTick = () => {
|
|
98
|
-
return new Promise(resolve => {
|
|
99
|
-
// @ts-ignore
|
|
100
|
-
const query = ty.createSelectorQuery();
|
|
101
|
-
query.select("#".concat(scrollViewId)).fields({
|
|
102
|
-
dataset: true
|
|
103
|
-
}, res => {
|
|
104
|
-
resolve(res.dataset.renderTick);
|
|
105
|
-
}).exec();
|
|
106
|
-
});
|
|
107
|
-
};
|
|
108
|
-
const getClientHeight = () => {
|
|
109
|
-
return new Promise(resolve => {
|
|
110
|
-
// @ts-ignore
|
|
111
|
-
const query = ty.createSelectorQuery();
|
|
112
|
-
query.select("#".concat(scrollViewId)).fields({
|
|
113
|
-
size: true
|
|
114
|
-
}, res => {
|
|
115
|
-
resolve(res.height);
|
|
116
|
-
}).exec();
|
|
117
|
-
});
|
|
118
|
-
};
|
|
119
|
-
const scrollViewInterval = setInterval(() => {
|
|
120
|
-
// 外部容器高度变化不频繁,1 秒查一次
|
|
121
|
-
getClientHeight().then(height => {
|
|
122
|
-
ref.current.clientHeight = height;
|
|
123
|
-
});
|
|
124
|
-
}, 1000);
|
|
125
|
-
|
|
126
|
-
// 初始化好 clientHeight
|
|
127
|
-
(async () => {
|
|
128
|
-
let tick = await getDomTick();
|
|
129
|
-
while (tick <= 0) {
|
|
130
|
-
await sleep(1);
|
|
131
|
-
tick = await getDomTick();
|
|
132
|
-
}
|
|
133
|
-
return tick;
|
|
134
|
-
})().then(() => getClientHeight()).then(height => {
|
|
135
|
-
console.log('scrollView clientHeight', height);
|
|
136
|
-
ref.current.clientHeight = height;
|
|
137
|
-
})
|
|
138
|
-
// 渲染完毕后,开始滚动到最底部
|
|
139
|
-
.then(() => scrollToBottom({}))
|
|
140
|
-
// 展示列表
|
|
141
|
-
.then(() => setReady(true));
|
|
142
|
-
return () => {
|
|
143
|
-
clearInterval(scrollViewInterval);
|
|
144
|
-
};
|
|
145
|
-
}, [scrollViewId]);
|
|
146
|
-
let scrollIntoViewId = "".concat(scrollViewId, "-toView-").concat(tickValue, "-").concat(scrollIntoViewFlag);
|
|
147
|
-
if (!ref.current.needFollow) {
|
|
148
|
-
scrollIntoViewId = null;
|
|
149
|
-
}
|
|
150
|
-
return {
|
|
151
|
-
scrollToBottom,
|
|
152
|
-
scrollViewLoading: !ready,
|
|
153
|
-
scrollIntoViewId,
|
|
154
|
-
contentViewProps: {
|
|
155
|
-
contentViewId
|
|
156
|
-
},
|
|
157
|
-
scrollViewProps: {
|
|
158
|
-
'data-render-tick': tickValue,
|
|
159
|
-
id: scrollViewId,
|
|
160
|
-
scrollY: true,
|
|
161
|
-
onScroll: event => {
|
|
162
|
-
var _params$onScroll3;
|
|
163
|
-
ref.current.lastScrollEvent = event;
|
|
164
|
-
const {
|
|
165
|
-
scrollTop,
|
|
166
|
-
scrollHeight
|
|
167
|
-
} = event.detail;
|
|
168
|
-
ref.current.needFollow = scrollHeight - scrollTop <= ref.current.clientHeight + 25;
|
|
169
|
-
params === null || params === void 0 || (_params$onScroll3 = params.onScroll) === null || _params$onScroll3 === void 0 || _params$onScroll3.call(params, event);
|
|
170
|
-
if (!ref.current.startTimestamp) {
|
|
171
|
-
ref.current.startTimestamp = Date.now() - event.timeStamp;
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
scrollWithAnimation,
|
|
175
|
-
scrollIntoView: scrollIntoViewId
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
const ScrollBottomView = /*#__PURE__*/forwardRef((props, ref) => {
|
|
180
|
-
const {
|
|
181
|
-
scrollToBottom,
|
|
182
|
-
scrollViewProps,
|
|
183
|
-
scrollIntoViewId,
|
|
184
|
-
contentViewProps,
|
|
185
|
-
scrollViewLoading
|
|
186
|
-
} = useScrollBottomView({
|
|
187
|
-
onScroll: props.onScroll
|
|
188
|
-
});
|
|
189
|
-
useOnEvent('scrollToBottom', scrollToBottom);
|
|
190
|
-
useImperativeHandle(ref, () => ({
|
|
191
|
-
scrollToBottom
|
|
192
|
-
}), [scrollToBottom]);
|
|
193
|
-
return /*#__PURE__*/React.createElement(ScrollView, _extends({
|
|
194
|
-
className: "".concat(props.className || '', " ").concat(scrollViewLoading ? 't-agent-message-list-hide' : ''),
|
|
195
|
-
style: props.style
|
|
196
|
-
}, scrollViewProps), /*#__PURE__*/React.createElement(View, _extends({}, contentViewProps, {
|
|
197
|
-
className: "".concat(props.contentClassName || '')
|
|
198
|
-
}), props.children, /*#__PURE__*/React.createElement(View, {
|
|
199
|
-
id: scrollIntoViewId
|
|
200
|
-
})));
|
|
201
|
-
});
|
|
202
|
-
export default /*#__PURE__*/React.memo(ScrollBottomView);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const useStableCallback: <T extends (...args: any[]) => any>(fn: T) => T;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import "core-js/modules/web.dom-collections.iterator.js";
|
|
2
|
-
import { useCallback, useRef } from 'react';
|
|
3
|
-
export const useStableCallback = fn => {
|
|
4
|
-
const ref = useRef(fn);
|
|
5
|
-
ref.current = fn;
|
|
6
|
-
const cb = useCallback(function () {
|
|
7
|
-
return ref.current(...arguments);
|
|
8
|
-
}, []);
|
|
9
|
-
if (!fn) {
|
|
10
|
-
return fn;
|
|
11
|
-
}
|
|
12
|
-
return cb;
|
|
13
|
-
};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import React, { PropsWithChildren } from 'react';
|
|
2
|
-
export declare function createSharedStore<T>(): readonly [({ value, children }: React.PropsWithChildren<{
|
|
3
|
-
value: T;
|
|
4
|
-
}>) => React.JSX.Element, <K extends keyof T>(key: K) => T[K], <K_1 extends keyof T>(key: K_1) => [T[K_1], (v: T[K_1]) => void]];
|
|
@@ -1,64 +0,0 @@
|
|
|
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/web.dom-collections.iterator.js";
|
|
5
|
-
import React, { createContext, useContext, useRef, useState, useEffect, useLayoutEffect } from 'react';
|
|
6
|
-
export function createSharedStore() {
|
|
7
|
-
const Context = /*#__PURE__*/createContext(null);
|
|
8
|
-
return [function (_ref) {
|
|
9
|
-
let {
|
|
10
|
-
value,
|
|
11
|
-
children
|
|
12
|
-
} = _ref;
|
|
13
|
-
const storeRef = useRef({
|
|
14
|
-
value,
|
|
15
|
-
listeners: new Map(),
|
|
16
|
-
setValue(newValue) {
|
|
17
|
-
const oldValue = storeRef.current.value;
|
|
18
|
-
storeRef.current.value = newValue;
|
|
19
|
-
for (const key of Object.keys(newValue)) {
|
|
20
|
-
if (oldValue[key] !== newValue[key]) {
|
|
21
|
-
var _storeRef$current$lis;
|
|
22
|
-
(_storeRef$current$lis = storeRef.current.listeners.get(key)) === null || _storeRef$current$lis === void 0 || _storeRef$current$lis.forEach(fn => fn());
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
},
|
|
26
|
-
updateKey(key, val) {
|
|
27
|
-
const newValue = _objectSpread(_objectSpread({}, storeRef.current.value), {}, {
|
|
28
|
-
[key]: val
|
|
29
|
-
});
|
|
30
|
-
storeRef.current.setValue(newValue);
|
|
31
|
-
},
|
|
32
|
-
subscribe(key, fn) {
|
|
33
|
-
if (!storeRef.current.listeners.has(key)) {
|
|
34
|
-
storeRef.current.listeners.set(key, new Set());
|
|
35
|
-
}
|
|
36
|
-
storeRef.current.listeners.get(key).add(fn);
|
|
37
|
-
return () => {
|
|
38
|
-
storeRef.current.listeners.get(key).delete(fn);
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
useLayoutEffect(() => {
|
|
43
|
-
// ✅ 在 render 阶段同步设置最新 value
|
|
44
|
-
storeRef.current.setValue(value);
|
|
45
|
-
}, [value]);
|
|
46
|
-
return /*#__PURE__*/React.createElement(Context.Provider, {
|
|
47
|
-
value: storeRef.current
|
|
48
|
-
}, children);
|
|
49
|
-
}, function (key) {
|
|
50
|
-
const store = useContext(Context);
|
|
51
|
-
if (!store) throw new Error('useSharedValue must be used within Provider');
|
|
52
|
-
const [, forceUpdate] = useState(0);
|
|
53
|
-
useEffect(() => store.subscribe(key, () => forceUpdate(n => n + 1)), [key, store]);
|
|
54
|
-
return store.value[key];
|
|
55
|
-
}, function (key) {
|
|
56
|
-
const store = useContext(Context);
|
|
57
|
-
if (!store) throw new Error('useSharedState must be used within Provider');
|
|
58
|
-
const [, forceUpdate] = useState(0);
|
|
59
|
-
useEffect(() => store.subscribe(key, () => forceUpdate(n => n + 1)), [key, store]);
|
|
60
|
-
return [store.value[key], val => {
|
|
61
|
-
store.updateKey(key, val);
|
|
62
|
-
}];
|
|
63
|
-
}];
|
|
64
|
-
}
|