@ray-js/t-agent-ui-ray 0.2.2-beta-2 → 0.2.3-beta-1
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.js +1 -9
- package/dist/EchartsBlockRender/index.js +8 -10
- package/dist/LazyScrollView/LazyItem/index.d.ts +18 -0
- package/dist/LazyScrollView/LazyItem/index.js +51 -0
- package/dist/LazyScrollView/LazyItem/index.json +3 -0
- package/dist/LazyScrollView/LazyItem/index.tyml +16 -0
- package/dist/LazyScrollView/index.d.ts +26 -0
- package/dist/LazyScrollView/index.js +27 -0
- package/dist/LazyScrollView/index.json +3 -0
- package/dist/LazyScrollView/index.tyml +15 -0
- package/dist/LazyScrollView/lazy-scroll-view.sjs +317 -0
- package/dist/LazyScrollView/weak-ref.sjs +45 -0
- package/dist/MessageInput/MessageInputAIStream/AsrInput.js +2 -2
- package/dist/MessageInput/MessageInputAIStream/Waveform/index.d.ts +9 -0
- package/dist/MessageInput/MessageInputAIStream/Waveform/index.js +52 -0
- package/dist/MessageInput/MessageInputAIStream/Waveform/index.json +3 -0
- package/dist/MessageInput/MessageInputAIStream/Waveform/index.tyml +9 -0
- package/dist/MessageInput/MessageInputAIStream/index.d.ts +1 -0
- package/dist/MessageInput/MessageInputAIStream/index.js +2 -4
- package/dist/MessageList/ScrollBottomView.d.ts +20 -20
- package/dist/MessageList/ScrollBottomView.js +59 -138
- package/dist/MessageList/index.d.ts +5 -8
- package/dist/MessageList/index.js +89 -11
- package/dist/MessageList/index.less +1 -2
- package/dist/MessageRender/index.d.ts +6 -1
- package/dist/MessageRender/index.js +49 -17
- package/dist/MessageRender/index.less +4 -3
- package/dist/TileRender/index.d.ts +2 -1
- package/dist/TileRender/index.js +3 -3
- package/dist/contexts.d.ts +1 -5
- package/dist/hooks/context.d.ts +0 -2
- package/dist/hooks/context.js +0 -6
- package/dist/tiles/BubbleTile/index.js +2 -1
- package/dist/tiles/CardTile/index.less +1 -1
- package/dist/tiles/ExecuteCardTile/index.js +2 -1
- package/dist/tiles/OperateCardTile/Expand.d.ts +2 -1
- package/dist/tiles/OperateCardTile/Expand.js +4 -2
- package/dist/tiles/OperateCardTile/index.js +5 -6
- package/dist/utils/object.d.ts +8 -0
- package/dist/utils/object.js +57 -0
- package/package.json +2 -2
- package/dist/MessageInput/MessageInputAIStream/WaveformVisualizer.d.ts +0 -4
- package/dist/MessageInput/MessageInputAIStream/WaveformVisualizer.js +0 -54
- package/dist/MessageList/LazyView.d.ts +0 -9
- package/dist/MessageList/LazyView.js +0 -57
|
@@ -4,7 +4,7 @@ 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
10
|
import { SharedProvider } from '../contexts';
|
|
@@ -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) {
|
|
@@ -78,7 +76,6 @@ export default function ChatContainer(props) {
|
|
|
78
76
|
messages
|
|
79
77
|
} = _ref;
|
|
80
78
|
setMessages(messages);
|
|
81
|
-
notifyHeightChanged();
|
|
82
79
|
emitEvent('scrollToBottom', {
|
|
83
80
|
animation: false
|
|
84
81
|
});
|
|
@@ -92,7 +89,6 @@ export default function ChatContainer(props) {
|
|
|
92
89
|
case 'show':
|
|
93
90
|
{
|
|
94
91
|
setMessages(prev => [...prev, message]);
|
|
95
|
-
notifyHeightChanged();
|
|
96
92
|
emitEvent('scrollToBottom', {
|
|
97
93
|
animation: false
|
|
98
94
|
});
|
|
@@ -103,7 +99,6 @@ export default function ChatContainer(props) {
|
|
|
103
99
|
setMessages(prev => {
|
|
104
100
|
return prev.map(item => {
|
|
105
101
|
if (item.id === message.id) {
|
|
106
|
-
notifyHeightChanged();
|
|
107
102
|
return message;
|
|
108
103
|
}
|
|
109
104
|
return item;
|
|
@@ -116,7 +111,6 @@ export default function ChatContainer(props) {
|
|
|
116
111
|
setMessages(prev => {
|
|
117
112
|
return prev.filter(item => item.id !== message.id);
|
|
118
113
|
});
|
|
119
|
-
notifyHeightChanged();
|
|
120
114
|
emitEvent('scrollToBottom', {
|
|
121
115
|
animation: false,
|
|
122
116
|
follow: true
|
|
@@ -187,9 +181,7 @@ export default function ChatContainer(props) {
|
|
|
187
181
|
value: {
|
|
188
182
|
agent: uiAgent,
|
|
189
183
|
messages,
|
|
190
|
-
notifyHeightChanged,
|
|
191
184
|
keyboardHeight,
|
|
192
|
-
tickValue,
|
|
193
185
|
renderOptions
|
|
194
186
|
}
|
|
195
187
|
}, children));
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import Render from './index.rjs';
|
|
2
|
-
import logger from '../logger';
|
|
3
|
-
|
|
4
2
|
// eslint-disable-next-line no-undef
|
|
5
3
|
Component({
|
|
6
4
|
properties: {
|
|
@@ -30,20 +28,16 @@ Component({
|
|
|
30
28
|
this.rjs = new Render(this);
|
|
31
29
|
},
|
|
32
30
|
ready: function () {
|
|
33
|
-
logger.debug('EchartsBlockRender ready', {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
31
|
+
// logger.debug('EchartsBlockRender ready', {
|
|
32
|
+
// canvasId: this.data.canvasId,
|
|
33
|
+
// content: this.data.content,
|
|
34
|
+
// });
|
|
37
35
|
this.updateContent(this.data.content);
|
|
38
36
|
}
|
|
39
37
|
},
|
|
40
38
|
methods: {
|
|
41
39
|
updateContent: function (content) {
|
|
42
40
|
try {
|
|
43
|
-
logger.debug('EchartsBlockRender update', {
|
|
44
|
-
canvasId: this.data.canvasId,
|
|
45
|
-
content
|
|
46
|
-
});
|
|
47
41
|
const data = JSON.parse(content);
|
|
48
42
|
if (data.option) {
|
|
49
43
|
if (!this.isInit) {
|
|
@@ -70,6 +64,10 @@ Component({
|
|
|
70
64
|
},
|
|
71
65
|
observers: {
|
|
72
66
|
content: function (content) {
|
|
67
|
+
// logger.debug('EchartsBlockRender update', {
|
|
68
|
+
// canvasId: this.data.canvasId,
|
|
69
|
+
// content,
|
|
70
|
+
// });
|
|
73
71
|
this.updateContent(content);
|
|
74
72
|
}
|
|
75
73
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface Props {
|
|
4
|
+
className?: string;
|
|
5
|
+
children?: React.ReactNode;
|
|
6
|
+
update?: string;
|
|
7
|
+
bindclick?: () => void;
|
|
8
|
+
bindshow?: (event: { detail: { show: boolean } }) => void;
|
|
9
|
+
style?: React.CSSProperties;
|
|
10
|
+
ready?: boolean;
|
|
11
|
+
scrollViewId?: string;
|
|
12
|
+
itemId?: string;
|
|
13
|
+
index: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare function SizeView(props: Props): React.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export default SizeView;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// eslint-disable-next-line no-undef
|
|
2
|
+
Component({
|
|
3
|
+
options: {
|
|
4
|
+
styleIsolation: 'shared'
|
|
5
|
+
},
|
|
6
|
+
properties: {
|
|
7
|
+
className: {
|
|
8
|
+
type: String,
|
|
9
|
+
value: ''
|
|
10
|
+
},
|
|
11
|
+
scrollViewId: {
|
|
12
|
+
type: String,
|
|
13
|
+
value: ''
|
|
14
|
+
},
|
|
15
|
+
update: {
|
|
16
|
+
type: String,
|
|
17
|
+
value: ''
|
|
18
|
+
},
|
|
19
|
+
ready: {
|
|
20
|
+
type: Boolean,
|
|
21
|
+
value: false
|
|
22
|
+
},
|
|
23
|
+
itemId: {
|
|
24
|
+
type: String,
|
|
25
|
+
value: ''
|
|
26
|
+
},
|
|
27
|
+
index: {
|
|
28
|
+
type: Number
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
data: {
|
|
32
|
+
show: true
|
|
33
|
+
},
|
|
34
|
+
lifetimes: {},
|
|
35
|
+
methods: {
|
|
36
|
+
click() {
|
|
37
|
+
this.triggerEvent('click');
|
|
38
|
+
},
|
|
39
|
+
setShow(show) {
|
|
40
|
+
if (show !== this.data.show) {
|
|
41
|
+
this.setData({
|
|
42
|
+
show
|
|
43
|
+
});
|
|
44
|
+
this.triggerEvent('show', {
|
|
45
|
+
show
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
observers: {}
|
|
51
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<sjs src="../lazy-scroll-view.sjs" module="lazyScrollView"></sjs>
|
|
2
|
+
|
|
3
|
+
<view
|
|
4
|
+
change:update="{{lazyScrollView.itemUpdateObserver}}"
|
|
5
|
+
update="{{update}}"
|
|
6
|
+
change:ready="{{lazyScrollView.itemReadyObserver}}"
|
|
7
|
+
ready="{{ready}}"
|
|
8
|
+
change:index="{{lazyScrollView.itemIndexObserver}}"
|
|
9
|
+
index="{{index}}"
|
|
10
|
+
bind:tap="click"
|
|
11
|
+
data-scroll-view-id="{{scrollViewId}}"
|
|
12
|
+
data-item-id="{{itemId}}"
|
|
13
|
+
class="{{className || ''}}"
|
|
14
|
+
>
|
|
15
|
+
<slot ty:if="{{show}}"></slot>
|
|
16
|
+
</view>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
export interface ScrollEventDetail {
|
|
4
|
+
scrollTop: number;
|
|
5
|
+
scrollHeight: number;
|
|
6
|
+
deltaY: number;
|
|
7
|
+
deltaX: number;
|
|
8
|
+
clientHeight: number;
|
|
9
|
+
clientWidth: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
className?: string;
|
|
14
|
+
children?: React.ReactNode;
|
|
15
|
+
style?: React.CSSProperties;
|
|
16
|
+
scrollViewId: string;
|
|
17
|
+
hideScrollbar?: boolean;
|
|
18
|
+
scrollWithAnimation?: boolean;
|
|
19
|
+
scrollIntoView?: string;
|
|
20
|
+
bindscroll?: (event: { detail: ScrollEventDetail }) => void;
|
|
21
|
+
binddone?: (event: { detail: { scrollIntoView: string } }) => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare function LazyScrollView(props: Props): React.JSX.Element;
|
|
25
|
+
|
|
26
|
+
export default LazyScrollView;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// eslint-disable-next-line no-undef
|
|
2
|
+
Component({
|
|
3
|
+
options: {
|
|
4
|
+
styleIsolation: 'shared'
|
|
5
|
+
},
|
|
6
|
+
properties: {
|
|
7
|
+
scrollViewId: {
|
|
8
|
+
type: String
|
|
9
|
+
},
|
|
10
|
+
hideScrollbar: {
|
|
11
|
+
type: Boolean,
|
|
12
|
+
value: false
|
|
13
|
+
},
|
|
14
|
+
scrollWithAnimation: {
|
|
15
|
+
type: Boolean,
|
|
16
|
+
value: false
|
|
17
|
+
},
|
|
18
|
+
scrollIntoView: {
|
|
19
|
+
type: String,
|
|
20
|
+
value: ''
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
data: {},
|
|
24
|
+
lifetimes: {},
|
|
25
|
+
methods: {},
|
|
26
|
+
observers: {}
|
|
27
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<sjs src="./lazy-scroll-view.sjs" module="lazyScrollView"></sjs>
|
|
2
|
+
|
|
3
|
+
<scroll-view
|
|
4
|
+
scroll-y="{{true}}"
|
|
5
|
+
class="{{className}}"
|
|
6
|
+
id="{{scrollViewId}}"
|
|
7
|
+
hideScrollbar="{{hideScrollbar}}"
|
|
8
|
+
data-scroll-view-id="{{scrollViewId}}"
|
|
9
|
+
scrollWithAnimation="{{scrollWithAnimation}}"
|
|
10
|
+
change:scrollIntoView="{{lazyScrollView.scrollIntoViewObserver}}"
|
|
11
|
+
scrollIntoView="{{scrollIntoView}}"
|
|
12
|
+
bind:scroll="{{lazyScrollView.scroll}}"
|
|
13
|
+
>
|
|
14
|
+
<slot></slot>
|
|
15
|
+
</scroll-view>
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// ownerInstance:表示的是触发事件的组件所在组件的 ComponentDescriptor 实例。如果触发事件的组件是在页面内的,ownerInstance 表示的是页面实例。
|
|
2
|
+
// instance:表示触发事件的组件的 ComponentDescriptor 实例。
|
|
3
|
+
|
|
4
|
+
const { createWeakRefPonyfill } = require('./weak-ref.sjs');
|
|
5
|
+
|
|
6
|
+
const WeakRef = createWeakRefPonyfill();
|
|
7
|
+
|
|
8
|
+
// scrollViewId -> WeakRef(ScrollViewContext)
|
|
9
|
+
const map = new Map();
|
|
10
|
+
|
|
11
|
+
function getVisibleItemIdsBinary(input) {
|
|
12
|
+
const {
|
|
13
|
+
sizes,
|
|
14
|
+
containerSize,
|
|
15
|
+
offset,
|
|
16
|
+
overscanCount,
|
|
17
|
+
} = input
|
|
18
|
+
|
|
19
|
+
if (!offset || !containerSize || !sizes.length) {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const total = sizes.length;
|
|
24
|
+
const avgHeight = sizes.reduce((sum, s) => sum + s.height, 0) / total || 0;
|
|
25
|
+
const overscanHeight = overscanCount * avgHeight;
|
|
26
|
+
|
|
27
|
+
const visibleTop = offset;
|
|
28
|
+
const visibleBottom = offset + containerSize;
|
|
29
|
+
const overscanTop = visibleTop - overscanHeight;
|
|
30
|
+
const overscanBottom = visibleBottom + overscanHeight;
|
|
31
|
+
|
|
32
|
+
// Step 1: 构建 offsets(每个 item 的 top)
|
|
33
|
+
const offsets = [];
|
|
34
|
+
let currTop = 0;
|
|
35
|
+
for (let i = 0; i < total; i++) {
|
|
36
|
+
offsets.push(currTop);
|
|
37
|
+
currTop += sizes[i].height;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Step 2: 二分查找第一个 bottom > overscanTop 的 item
|
|
41
|
+
let start = 0, end = total - 1, startIndex = total;
|
|
42
|
+
while (start <= end) {
|
|
43
|
+
const mid = Math.floor((start + end) / 2);
|
|
44
|
+
const bottom = offsets[mid] + sizes[mid].height;
|
|
45
|
+
if (bottom >= overscanTop) {
|
|
46
|
+
startIndex = mid;
|
|
47
|
+
end = mid - 1;
|
|
48
|
+
} else {
|
|
49
|
+
start = mid + 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Step 3: 向后遍历直到 top > overscanBottom
|
|
54
|
+
const visibleMap = Object.create(null);
|
|
55
|
+
|
|
56
|
+
let i = 0;
|
|
57
|
+
while (i < startIndex) {
|
|
58
|
+
i++
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
while (i < total && offsets[i] <= overscanBottom) {
|
|
62
|
+
visibleMap[sizes[i].itemId] = true;
|
|
63
|
+
i++;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return visibleMap
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const getScrollViewContext = function (ownerInstance, instance) {
|
|
70
|
+
const state = ownerInstance.getState()
|
|
71
|
+
let context = state.scrollViewContext
|
|
72
|
+
if (!context) {
|
|
73
|
+
const { scrollViewId } = instance.getDataset()
|
|
74
|
+
const rect = instance.getBoundingClientRect()
|
|
75
|
+
|
|
76
|
+
context = {
|
|
77
|
+
scrollViewId,
|
|
78
|
+
height: rect.height,
|
|
79
|
+
width: rect.width,
|
|
80
|
+
overscanCount: 5,
|
|
81
|
+
items: new Map(), // itemId -> WeakRef(ItemContext)
|
|
82
|
+
updateShowPending: false,
|
|
83
|
+
offset: 0,
|
|
84
|
+
lastScrollEventDetail: null,
|
|
85
|
+
lastScrollIntoView: null,
|
|
86
|
+
refresh() {
|
|
87
|
+
const rect = instance.getBoundingClientRect()
|
|
88
|
+
context.height = rect.height
|
|
89
|
+
context.width = rect.width
|
|
90
|
+
},
|
|
91
|
+
refreshSizes() {
|
|
92
|
+
const sizes = [];
|
|
93
|
+
context.items.forEach((ref) => {
|
|
94
|
+
const itemContext = ref.deref()
|
|
95
|
+
if (itemContext) {
|
|
96
|
+
sizes.push(itemContext.data)
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
sizes.sort((a, b) => a.index - b.index); // 按照 top 排序
|
|
100
|
+
context.sizes = sizes;
|
|
101
|
+
},
|
|
102
|
+
updateVisibleItems() {
|
|
103
|
+
if (context.updateShowPending) {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
context.updateShowPending = true;
|
|
107
|
+
ownerInstance.requestAnimationFrame(() => {
|
|
108
|
+
const visibleMap = getVisibleItemIdsBinary({
|
|
109
|
+
sizes: context.sizes,
|
|
110
|
+
containerSize: context.height,
|
|
111
|
+
offset: context.offset,
|
|
112
|
+
overscanCount: context.overscanCount,
|
|
113
|
+
})
|
|
114
|
+
if (visibleMap) {
|
|
115
|
+
context.items.forEach((ref, itemId) => {
|
|
116
|
+
const itemContext = ref.deref()
|
|
117
|
+
if (itemContext) {
|
|
118
|
+
itemContext.setShow(!!visibleMap[itemId]);
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
context.updateShowPending = false;
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
state.scrollViewContext = context;
|
|
127
|
+
// 使用 WeakRef 来避免内存泄漏
|
|
128
|
+
map.set(scrollViewId, new WeakRef(context));
|
|
129
|
+
}
|
|
130
|
+
return context;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const getScrollViewContextById = function (scrollViewId) {
|
|
134
|
+
const ref = map.get(scrollViewId);
|
|
135
|
+
if (!ref) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const context = ref.deref();
|
|
139
|
+
if (!context) {
|
|
140
|
+
console.warn(`ScrollViewContext for scrollViewId ${scrollViewId} has been garbage collected.`);
|
|
141
|
+
map.delete(scrollViewId);
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
return context;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const scroll = function (event, ownerInstance) {
|
|
148
|
+
const instance = event.instance
|
|
149
|
+
const context = getScrollViewContext(ownerInstance, instance)
|
|
150
|
+
context.offset = event.detail.scrollTop;
|
|
151
|
+
// 触发父组件的滚动事件
|
|
152
|
+
ownerInstance.triggerEvent('scroll', {
|
|
153
|
+
...event.detail,
|
|
154
|
+
clientHeight: context.height,
|
|
155
|
+
clientWidth: context.width,
|
|
156
|
+
});
|
|
157
|
+
context.lastScrollEventDetail = event.detail;
|
|
158
|
+
context.updateVisibleItems();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const getItemContext = function (ownerInstance, instance) {
|
|
162
|
+
const state = ownerInstance.getState()
|
|
163
|
+
let itemContext = state.context
|
|
164
|
+
if (!itemContext) {
|
|
165
|
+
const { scrollViewId, itemId } = instance.getDataset()
|
|
166
|
+
const rect = instance.getBoundingClientRect()
|
|
167
|
+
itemContext = {
|
|
168
|
+
show: true,
|
|
169
|
+
scrollViewId,
|
|
170
|
+
data: {
|
|
171
|
+
itemId,
|
|
172
|
+
index: null,
|
|
173
|
+
height: rect.height,
|
|
174
|
+
},
|
|
175
|
+
ready: false,
|
|
176
|
+
setShow(show) {
|
|
177
|
+
if (show === itemContext.show || !itemContext.ready) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
itemContext.show = show;
|
|
181
|
+
if (show) {
|
|
182
|
+
ownerInstance.requestAnimationFrame(() => {
|
|
183
|
+
itemContext.refreshSize();
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
ownerInstance.callMethod('setShow', show);
|
|
187
|
+
},
|
|
188
|
+
refreshSize(byUpdate = false) {
|
|
189
|
+
if (byUpdate && itemContext.ready && itemContext.show) {
|
|
190
|
+
// 为了测量真实的高度,先清除 minHeight
|
|
191
|
+
instance.setStyle({
|
|
192
|
+
minHeight: '',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const rect = instance.getBoundingClientRect()
|
|
197
|
+
itemContext.data.height = rect.height;
|
|
198
|
+
if (itemContext.ready) {
|
|
199
|
+
instance.setStyle({
|
|
200
|
+
minHeight: `${rect.height}px`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const context = getScrollViewContextById(scrollViewId)
|
|
206
|
+
if (context) {
|
|
207
|
+
context.items.set(itemId, new WeakRef(itemContext));
|
|
208
|
+
} else {
|
|
209
|
+
console.warn(`ScrollViewContext not found for scrollViewId: ${scrollViewId}`);
|
|
210
|
+
}
|
|
211
|
+
state.context = itemContext;
|
|
212
|
+
}
|
|
213
|
+
return itemContext;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const itemUpdateObserver = function (newValue, oldValue, ownerInstance, instance) {
|
|
217
|
+
if (newValue === oldValue) {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const itemContext = getItemContext(ownerInstance, instance)
|
|
222
|
+
itemContext.refreshSize(true);
|
|
223
|
+
if (itemContext.ready) {
|
|
224
|
+
ownerInstance.requestAnimationFrame(() => {
|
|
225
|
+
const context = getScrollViewContextById(itemContext.scrollViewId);
|
|
226
|
+
if (context) {
|
|
227
|
+
context.refreshSizes();
|
|
228
|
+
context.updateVisibleItems();
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const itemReadyObserver = function (newValue, oldValue, ownerInstance, instance) {
|
|
236
|
+
if (newValue === oldValue) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const itemContext = getItemContext(ownerInstance, instance)
|
|
241
|
+
|
|
242
|
+
// ready 属性变化时,设置 ready 状态
|
|
243
|
+
if (newValue === true) {
|
|
244
|
+
itemContext.ready = true;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
itemContext.refreshSize();
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const itemIndexObserver = function (newValue, oldValue, ownerInstance, instance) {
|
|
251
|
+
if (newValue === oldValue || newValue == null) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const itemContext = getItemContext(ownerInstance, instance)
|
|
255
|
+
itemContext.data.index = newValue;
|
|
256
|
+
const context = getScrollViewContextById(itemContext.scrollViewId);
|
|
257
|
+
if (context) {
|
|
258
|
+
context.refreshSizes();
|
|
259
|
+
context.updateVisibleItems();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const scrollIntoViewObserver = function (newValue, oldValue, ownerInstance, instance) {
|
|
264
|
+
const context = getScrollViewContext(ownerInstance, instance)
|
|
265
|
+
if (newValue === oldValue) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
ownerInstance.requestAnimationFrame(() => {
|
|
270
|
+
ownerInstance.triggerEvent('done', {
|
|
271
|
+
scrollIntoView: newValue,
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
if (!newValue) {
|
|
276
|
+
return
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const last = context.lastScrollIntoView;
|
|
280
|
+
|
|
281
|
+
if (last && last === newValue) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
context.lastScrollIntoView = newValue
|
|
286
|
+
|
|
287
|
+
const rect = instance.getBoundingClientRect()
|
|
288
|
+
if (context.lastScrollEventDetail == null) {
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// 这个就是用来滚动到底部的,所以直接计算底部 offset 就行
|
|
293
|
+
|
|
294
|
+
const lastOffset = context.offset
|
|
295
|
+
context.offset = context.lastScrollEventDetail.scrollHeight - rect.height;
|
|
296
|
+
context.refresh()
|
|
297
|
+
context.updateVisibleItems();
|
|
298
|
+
|
|
299
|
+
ownerInstance.triggerEvent('scroll', {
|
|
300
|
+
scrollTop: context.offset,
|
|
301
|
+
deltaX: 0,
|
|
302
|
+
deltaY: context.offset - lastOffset,
|
|
303
|
+
scrollLeft: context.lastScrollEventDetail.scrollLeft,
|
|
304
|
+
scrollHeight: context.lastScrollEventDetail.scrollHeight,
|
|
305
|
+
scrollWidth: context.lastScrollEventDetail.scrollWidth,
|
|
306
|
+
clientHeight: context.height,
|
|
307
|
+
clientWidth: context.width,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
export default {
|
|
312
|
+
itemIndexObserver,
|
|
313
|
+
itemUpdateObserver,
|
|
314
|
+
itemReadyObserver,
|
|
315
|
+
scrollIntoViewObserver,
|
|
316
|
+
scroll
|
|
317
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function createWeakRefPonyfill() {
|
|
2
|
+
if (typeof globalThis.WeakRef === 'function') {
|
|
3
|
+
return globalThis.WeakRef; // 用原生的
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
console.warn('[ponyfill] WeakRef not supported. Using WeakMap + FinalizationRegistry fallback.');
|
|
7
|
+
|
|
8
|
+
const _refs = new WeakMap(); // WeakRef实例 -> target
|
|
9
|
+
const _reverse = new WeakMap(); // target -> WeakRef实例数组
|
|
10
|
+
|
|
11
|
+
const registry = typeof FinalizationRegistry !== 'undefined'
|
|
12
|
+
? new FinalizationRegistry((heldValue) => {
|
|
13
|
+
const { targetKey } = heldValue;
|
|
14
|
+
const refs = _reverse.get(targetKey);
|
|
15
|
+
if (refs) {
|
|
16
|
+
for (const ref of refs) {
|
|
17
|
+
_refs.delete(ref);
|
|
18
|
+
}
|
|
19
|
+
_reverse.delete(targetKey);
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
: null;
|
|
23
|
+
|
|
24
|
+
return class WeakRefPonyfill {
|
|
25
|
+
constructor(target) {
|
|
26
|
+
if (typeof target !== 'object' || target === null) {
|
|
27
|
+
throw new TypeError('WeakRef target must be an object');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_refs.set(this, target);
|
|
31
|
+
|
|
32
|
+
if (registry) {
|
|
33
|
+
registry.register(target, { targetKey: target });
|
|
34
|
+
|
|
35
|
+
const existing = _reverse.get(target) || [];
|
|
36
|
+
existing.push(this);
|
|
37
|
+
_reverse.set(target, existing);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
deref() {
|
|
42
|
+
return _refs.get(this);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -3,7 +3,7 @@ import React, { useEffect, useRef, useState } from 'react';
|
|
|
3
3
|
import { Button, View } from '@ray-js/ray';
|
|
4
4
|
import cx from 'clsx';
|
|
5
5
|
import { useTranslate } from '../../hooks';
|
|
6
|
-
import
|
|
6
|
+
import Waveform from './Waveform';
|
|
7
7
|
import logger from '../../logger';
|
|
8
8
|
const AsrInput = props => {
|
|
9
9
|
const touchRef = useRef({
|
|
@@ -92,7 +92,7 @@ const AsrInput = props => {
|
|
|
92
92
|
className: "t-agent-message-input-ptt-active-text-top"
|
|
93
93
|
}, t('t-agent.input.asr.oninput.text.top')), /*#__PURE__*/React.createElement(View, {
|
|
94
94
|
className: "t-agent-message-input-ptt-active-text-center"
|
|
95
|
-
}, t('t-agent.input.asr.oninput.text.center')), /*#__PURE__*/React.createElement(
|
|
95
|
+
}, t('t-agent.input.asr.oninput.text.center')), /*#__PURE__*/React.createElement(Waveform, {
|
|
96
96
|
amplitudeCount: props.amplitudeCount
|
|
97
97
|
}))), !props.recording && /*#__PURE__*/React.createElement(Button, {
|
|
98
98
|
className: cx('t-agent-message-input-button', 't-agent-message-input-ptt-action-button', props.responding ? 't-agent-message-input-button-stop' : 't-agent-message-input-button-keyboard'),
|