@ray-js/t-agent-ui-ray 0.0.5-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/LICENSE.md +21 -0
- package/README-zh_CN.md +14 -0
- package/README.md +14 -0
- package/dist/ChatContainer/index.d.ts +9 -0
- package/dist/ChatContainer/index.js +124 -0
- package/dist/ChatContainer/index.less +10 -0
- package/dist/CustomCardRender/index.d.ts +8 -0
- package/dist/CustomCardRender/index.js +21 -0
- package/dist/CustomCardRender/index.less +2 -0
- package/dist/EchartsBlockRender/index.js +73 -0
- package/dist/EchartsBlockRender/index.json +3 -0
- package/dist/EchartsBlockRender/index.less +26 -0
- package/dist/EchartsBlockRender/index.rjs +15 -0
- package/dist/EchartsBlockRender/index.tyml +12 -0
- package/dist/EchartsBlockRender/loading.svg +1 -0
- package/dist/LowCodeCardRender/index.d.ts +8 -0
- package/dist/LowCodeCardRender/index.js +14 -0
- package/dist/LowCodeCardRender/index.less +2 -0
- package/dist/MarkdownRender/BlockParser.d.ts +18 -0
- package/dist/MarkdownRender/BlockParser.js +261 -0
- package/dist/MarkdownRender/index.d.ts +14 -0
- package/dist/MarkdownRender/index.js +72 -0
- package/dist/MarkdownRender/index.less +417 -0
- package/dist/MarkdownRender/theme/dark.less +65 -0
- package/dist/MarkdownRender/theme/light.less +64 -0
- package/dist/MessageInput/AsrInput.d.ts +14 -0
- package/dist/MessageInput/AsrInput.js +78 -0
- package/dist/MessageInput/icons/close-circle.svg +1 -0
- package/dist/MessageInput/icons/image.svg +1 -0
- package/dist/MessageInput/icons/loading.svg +1 -0
- package/dist/MessageInput/icons/plus.svg +1 -0
- package/dist/MessageInput/icons/send.svg +1 -0
- package/dist/MessageInput/icons/text.svg +11 -0
- package/dist/MessageInput/icons/video.svg +1 -0
- package/dist/MessageInput/icons/voice-active.svg +9 -0
- package/dist/MessageInput/icons/voice.svg +1 -0
- package/dist/MessageInput/index.d.ts +9 -0
- package/dist/MessageInput/index.js +246 -0
- package/dist/MessageInput/index.less +289 -0
- package/dist/MessageList/index.d.ts +12 -0
- package/dist/MessageList/index.js +61 -0
- package/dist/MessageList/index.less +19 -0
- package/dist/MessageRender/index.d.ts +10 -0
- package/dist/MessageRender/index.js +34 -0
- package/dist/MessageRender/index.less +14 -0
- package/dist/PrivateImage/index.d.ts +8 -0
- package/dist/PrivateImage/index.js +113 -0
- package/dist/TileRender/index.d.ts +11 -0
- package/dist/TileRender/index.js +32 -0
- package/dist/TileRender/index.less +4 -0
- package/dist/cards/WorkflowReplyCard/index.d.ts +11 -0
- package/dist/cards/WorkflowReplyCard/index.js +67 -0
- package/dist/cards/WorkflowReplyCard/index.less +37 -0
- package/dist/cards/map.d.ts +5 -0
- package/dist/cards/map.js +4 -0
- package/dist/contexts.d.ts +11 -0
- package/dist/contexts.js +16 -0
- package/dist/global.d.ts +19 -0
- package/dist/hooks/context.d.ts +11 -0
- package/dist/hooks/context.js +40 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/useAsrInput.d.ts +38 -0
- package/dist/hooks/useAsrInput.js +111 -0
- package/dist/hooks/useBlockInput.d.ts +18 -0
- package/dist/hooks/useBlockInput.js +148 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +14 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +3 -0
- package/dist/renderOption.d.ts +2 -0
- package/dist/renderOption.js +76 -0
- package/dist/tiles/BubbleTile/Feedback.d.ts +8 -0
- package/dist/tiles/BubbleTile/Feedback.js +39 -0
- package/dist/tiles/BubbleTile/feedback.less +35 -0
- package/dist/tiles/BubbleTile/index.d.ts +6 -0
- package/dist/tiles/BubbleTile/index.js +123 -0
- package/dist/tiles/BubbleTile/index.less +56 -0
- package/dist/tiles/BubbleTile/notice.svg +1 -0
- package/dist/tiles/BubbleTile/thumb-down-empty.svg +1 -0
- package/dist/tiles/BubbleTile/thumb-up-fill.svg +1 -0
- package/dist/tiles/ButtonsTile/index.d.ts +5 -0
- package/dist/tiles/ButtonsTile/index.js +18 -0
- package/dist/tiles/ButtonsTile/index.less +25 -0
- package/dist/tiles/CardTile/index.d.ts +6 -0
- package/dist/tiles/CardTile/index.js +20 -0
- package/dist/tiles/CardTile/index.less +3 -0
- package/dist/tiles/DocumentsTile/index.d.ts +5 -0
- package/dist/tiles/DocumentsTile/index.js +23 -0
- package/dist/tiles/DocumentsTile/index.less +13 -0
- package/dist/tiles/ImageTile/index.d.ts +5 -0
- package/dist/tiles/ImageTile/index.js +37 -0
- package/dist/tiles/ImageTile/index.less +9 -0
- package/dist/tiles/RecommendationsTile/index.d.ts +5 -0
- package/dist/tiles/RecommendationsTile/index.js +31 -0
- package/dist/tiles/RecommendationsTile/index.less +13 -0
- package/dist/tiles/TextTile/index.d.ts +9 -0
- package/dist/tiles/TextTile/index.js +27 -0
- package/dist/tiles/TextTile/index.less +3 -0
- package/dist/tiles/TimeTile/index.d.ts +5 -0
- package/dist/tiles/TimeTile/index.js +35 -0
- package/dist/tiles/TimeTile/index.less +10 -0
- package/dist/tiles/TipTile/index.d.ts +6 -0
- package/dist/tiles/TipTile/index.js +12 -0
- package/dist/tiles/TipTile/index.less +9 -0
- package/dist/tiles/VideoTile/index.d.ts +5 -0
- package/dist/tiles/VideoTile/index.js +49 -0
- package/dist/tiles/VideoTile/index.less +37 -0
- package/dist/tiles/WorkflowTile/index.d.ts +11 -0
- package/dist/tiles/WorkflowTile/index.js +30 -0
- package/dist/tiles/WorkflowTile/index.less +31 -0
- package/dist/tiles/map.d.ts +3 -0
- package/dist/tiles/map.js +24 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.js +1 -0
- package/package.json +45 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Tuya Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README-zh_CN.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
English | [简体中文](./README-zh_CN.md)
|
|
2
|
+
|
|
3
|
+
# @ray-js/t-agent-ui-ray
|
|
4
|
+
|
|
5
|
+
> AI Agent SDK
|
|
6
|
+
> For detailed documentation, see @ray-js/t-agent
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
$ npm install @ray-js/t-agent-ui-ray
|
|
12
|
+
// or
|
|
13
|
+
$ yarn add @ray-js/t-agent-ui-ray
|
|
14
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import './index.less';
|
|
2
|
+
import React, { PropsWithChildren } from 'react';
|
|
3
|
+
import { ChatAgent } from '@ray-js/t-agent';
|
|
4
|
+
import { RenderOptions } from '../types';
|
|
5
|
+
export default function ChatContainer<T extends ChatAgent<any>>(props: PropsWithChildren<{
|
|
6
|
+
createAgent: () => T;
|
|
7
|
+
renderOptions?: RenderOptions;
|
|
8
|
+
className?: string;
|
|
9
|
+
}>): React.JSX.Element;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import "core-js/modules/esnext.iterator.constructor.js";
|
|
2
|
+
import "core-js/modules/esnext.iterator.filter.js";
|
|
3
|
+
import "core-js/modules/esnext.iterator.map.js";
|
|
4
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
5
|
+
import './index.less';
|
|
6
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
7
|
+
import { View } from '@ray-js/components';
|
|
8
|
+
import { getWebSocketStatusSync, SocketStatus } from '@ray-js/t-agent-plugin-assistant';
|
|
9
|
+
import { getSystemInfoSync } from '@ray-js/ray';
|
|
10
|
+
import { ChatAgentContext, MessageContext, RenderContext } from '../contexts';
|
|
11
|
+
import { defaultRenderOptions } from '../renderOption';
|
|
12
|
+
import logger from '../logger';
|
|
13
|
+
export default function ChatContainer(props) {
|
|
14
|
+
const {
|
|
15
|
+
createAgent,
|
|
16
|
+
renderOptions = defaultRenderOptions,
|
|
17
|
+
children,
|
|
18
|
+
className = ''
|
|
19
|
+
} = props;
|
|
20
|
+
const [messages, setMessages] = useState([]);
|
|
21
|
+
const [socketStatus, setSocketStatus] = useState(() => {
|
|
22
|
+
try {
|
|
23
|
+
return getWebSocketStatusSync().status;
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return SocketStatus.WAITING;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const [agent] = useState(() => {
|
|
29
|
+
const agent = createAgent();
|
|
30
|
+
if (!agent.plugins.ui) {
|
|
31
|
+
throw new Error('UI plugin not found');
|
|
32
|
+
}
|
|
33
|
+
if (!agent.plugins.assistant) {
|
|
34
|
+
throw new Error('Assistant plugin not found');
|
|
35
|
+
}
|
|
36
|
+
return agent;
|
|
37
|
+
});
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
const {
|
|
40
|
+
onEvent,
|
|
41
|
+
emitEvent
|
|
42
|
+
} = agent.plugins.ui;
|
|
43
|
+
const offSocketStatusChange = agent.plugins.assistant.onSocketStatusChange(status => {
|
|
44
|
+
setSocketStatus(status);
|
|
45
|
+
});
|
|
46
|
+
const offMessageListInit = onEvent('messageListInit', _ref => {
|
|
47
|
+
let {
|
|
48
|
+
messages
|
|
49
|
+
} = _ref;
|
|
50
|
+
setMessages(messages);
|
|
51
|
+
emitEvent('scrollToBottom', {
|
|
52
|
+
animation: false
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
const offMessageChange = onEvent('messageChange', _ref2 => {
|
|
56
|
+
let {
|
|
57
|
+
type,
|
|
58
|
+
message
|
|
59
|
+
} = _ref2;
|
|
60
|
+
switch (type) {
|
|
61
|
+
case 'show':
|
|
62
|
+
setMessages(prev => [...prev, message]);
|
|
63
|
+
emitEvent('scrollToBottom', {
|
|
64
|
+
animation: false
|
|
65
|
+
});
|
|
66
|
+
break;
|
|
67
|
+
case 'update':
|
|
68
|
+
setMessages(prev => {
|
|
69
|
+
if (getSystemInfoSync().platform === 'android') {
|
|
70
|
+
var _prev;
|
|
71
|
+
// Android 上有兼容问题,需要手动滚动到底部
|
|
72
|
+
if (((_prev = prev[prev.length - 1]) === null || _prev === void 0 ? void 0 : _prev.id) === message.id) {
|
|
73
|
+
// 是最后一条消息,滚动到最底部
|
|
74
|
+
emitEvent('scrollToBottom', {
|
|
75
|
+
animation: false
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return prev.map(item => {
|
|
80
|
+
if (item.id === message.id) {
|
|
81
|
+
return message;
|
|
82
|
+
}
|
|
83
|
+
return item;
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
break;
|
|
87
|
+
case 'remove':
|
|
88
|
+
setMessages(prev => {
|
|
89
|
+
return prev.filter(item => item.id !== message.id);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return () => {
|
|
94
|
+
offSocketStatusChange();
|
|
95
|
+
offMessageListInit();
|
|
96
|
+
offMessageChange();
|
|
97
|
+
};
|
|
98
|
+
}, [agent]);
|
|
99
|
+
const messageValue = useMemo(() => {
|
|
100
|
+
return {
|
|
101
|
+
messages,
|
|
102
|
+
socketStatus
|
|
103
|
+
};
|
|
104
|
+
}, [messages, socketStatus]);
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
(async function () {
|
|
107
|
+
logger.debug('[ChatProvider] agent.start');
|
|
108
|
+
try {
|
|
109
|
+
await agent.start();
|
|
110
|
+
} catch (error) {
|
|
111
|
+
logger.error('[ChatProvider] agent.start error', error);
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
114
|
+
}, []);
|
|
115
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
116
|
+
className: "t-agent-chat-container ".concat(className || '')
|
|
117
|
+
}, /*#__PURE__*/React.createElement(ChatAgentContext.Provider, {
|
|
118
|
+
value: agent
|
|
119
|
+
}, /*#__PURE__*/React.createElement(RenderContext.Provider, {
|
|
120
|
+
value: renderOptions
|
|
121
|
+
}, /*#__PURE__*/React.createElement(MessageContext.Provider, {
|
|
122
|
+
value: messageValue
|
|
123
|
+
}, children))));
|
|
124
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import './index.less';
|
|
2
|
+
import { View } from '@ray-js/components';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useRenderOptions } from '../hooks';
|
|
5
|
+
export default function CustomCardRender(_ref) {
|
|
6
|
+
let {
|
|
7
|
+
card
|
|
8
|
+
} = _ref;
|
|
9
|
+
const {
|
|
10
|
+
customCardMap
|
|
11
|
+
} = useRenderOptions();
|
|
12
|
+
const Card = customCardMap[card.cardCode];
|
|
13
|
+
if (!Card) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
17
|
+
className: "t-agent-custom-card-render"
|
|
18
|
+
}, /*#__PURE__*/React.createElement(Card, {
|
|
19
|
+
card: card
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import Render from './index.rjs';
|
|
2
|
+
import logger from '../logger';
|
|
3
|
+
import { getSystemInfoSync } from '@ray-js/ray';
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line no-undef
|
|
6
|
+
Component({
|
|
7
|
+
properties: {
|
|
8
|
+
canvasId: {
|
|
9
|
+
type: String,
|
|
10
|
+
value: 'chart'
|
|
11
|
+
},
|
|
12
|
+
width: {
|
|
13
|
+
type: Number,
|
|
14
|
+
value: 564
|
|
15
|
+
},
|
|
16
|
+
height: {
|
|
17
|
+
type: Number,
|
|
18
|
+
value: 564
|
|
19
|
+
},
|
|
20
|
+
content: {
|
|
21
|
+
type: String,
|
|
22
|
+
value: '{}'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
data: {
|
|
26
|
+
loading: true,
|
|
27
|
+
error: false
|
|
28
|
+
},
|
|
29
|
+
lifetimes: {
|
|
30
|
+
attached() {
|
|
31
|
+
this.rjs = new Render(this);
|
|
32
|
+
},
|
|
33
|
+
ready: function () {
|
|
34
|
+
logger.debug('EchartsBlockRender ready', {
|
|
35
|
+
canvasId: this.data.canvasId,
|
|
36
|
+
content: this.data.content
|
|
37
|
+
});
|
|
38
|
+
this.updateContent(this.data.content);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
methods: {
|
|
42
|
+
updateContent: function (content) {
|
|
43
|
+
try {
|
|
44
|
+
logger.debug('EchartsBlockRender update', {
|
|
45
|
+
canvasId: this.data.canvasId,
|
|
46
|
+
content
|
|
47
|
+
});
|
|
48
|
+
const data = JSON.parse(content);
|
|
49
|
+
if (data.option) {
|
|
50
|
+
const pixelRatio = getSystemInfoSync().pixelRatio;
|
|
51
|
+
this.rjs.update(this.data.canvasId, pixelRatio, data.option);
|
|
52
|
+
this.setData({
|
|
53
|
+
loading: false,
|
|
54
|
+
error: false
|
|
55
|
+
});
|
|
56
|
+
} else {
|
|
57
|
+
this.setData({
|
|
58
|
+
error: true
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
} catch (e) {
|
|
62
|
+
this.setData({
|
|
63
|
+
loading: true
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
observers: {
|
|
69
|
+
content: function (content) {
|
|
70
|
+
this.updateContent(content);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
.t-agent-echarts-block-render {
|
|
2
|
+
position: relative;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
.t-agent-echarts-block-render-loading {
|
|
6
|
+
--t-agent-echarts-block-render-loading-size: 80rpx;
|
|
7
|
+
position: absolute;
|
|
8
|
+
top: calc(50% - var(--t-agent-echarts-block-render-loading-size) / 2);
|
|
9
|
+
left: calc(50% - var(--t-agent-echarts-block-render-loading-size) / 2);
|
|
10
|
+
width: var(--t-agent-echarts-block-render-loading-size);
|
|
11
|
+
height: var(--t-agent-echarts-block-render-loading-size);
|
|
12
|
+
background-size: cover;
|
|
13
|
+
background-position: center;
|
|
14
|
+
background-repeat: no-repeat;
|
|
15
|
+
background-image: url("./loading.svg");
|
|
16
|
+
animation: t-agent-message-input-rotating 2s infinite;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@keyframes t-agent-echarts-block-render-loading-rotating {
|
|
20
|
+
from {
|
|
21
|
+
transform: rotate(0deg);
|
|
22
|
+
}
|
|
23
|
+
to {
|
|
24
|
+
transform: rotate(360deg);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default Render({
|
|
2
|
+
myChart: null,
|
|
3
|
+
async update(canvasId, devicePixelRatio, option) {
|
|
4
|
+
if (!this.myChart) {
|
|
5
|
+
const canvas = await this.instance.getCanvasById(canvasId)
|
|
6
|
+
const echarts = await requirePlugin('rjs://echarts')
|
|
7
|
+
|
|
8
|
+
this.myChart = echarts.init(canvas, undefined, {
|
|
9
|
+
devicePixelRatio,
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
// 使用刚指定的配置项和数据显示图表。
|
|
13
|
+
this.myChart.setOption(option, true)
|
|
14
|
+
},
|
|
15
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<view
|
|
2
|
+
class="t-agent-echarts-block-render"
|
|
3
|
+
style="width: {{width}}rpx;height: {{height}}rpx;"
|
|
4
|
+
>
|
|
5
|
+
<canvas
|
|
6
|
+
canvas-id="{{canvasId}}"
|
|
7
|
+
style="width: {{width}}rpx;height: {{height}}rpx"
|
|
8
|
+
id="{{canvasId}}"
|
|
9
|
+
type="2d"
|
|
10
|
+
/>
|
|
11
|
+
<view ty:if="{{loading}}" class="t-agent-echarts-block-render-loading"></view>
|
|
12
|
+
</view>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1735889067185" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1851" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M512 170.666667v85.333333a256 256 0 1 1-223.573333 131.2L213.930667 345.6A341.333333 341.333333 0 1 0 512 170.666667z" fill="#000000" opacity=".3" p-id="1852"></path></svg>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import './index.less';
|
|
2
|
+
import { View } from '@ray-js/components';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { useTileProps } from '../hooks';
|
|
5
|
+
export default function LowCodeCardRender(_ref) {
|
|
6
|
+
let {
|
|
7
|
+
card
|
|
8
|
+
} = _ref;
|
|
9
|
+
// const { data, type } = card;
|
|
10
|
+
useTileProps();
|
|
11
|
+
return /*#__PURE__*/React.createElement(View, {
|
|
12
|
+
className: "t-agent-low-code-card-render"
|
|
13
|
+
});
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import MarkdownIt from 'markdown-it';
|
|
2
|
+
import { MarkdownBlock } from '../types';
|
|
3
|
+
export declare class BlockParser {
|
|
4
|
+
readonly prefix: string;
|
|
5
|
+
readonly types: string[];
|
|
6
|
+
readonly richTextClassName: string;
|
|
7
|
+
private list;
|
|
8
|
+
private pendingBlocks;
|
|
9
|
+
private currentInput;
|
|
10
|
+
constructor(prefix: string, types: string[], richTextClassName: string);
|
|
11
|
+
static plugin(MD: MarkdownIt): void;
|
|
12
|
+
isSupportedType(type: string): boolean;
|
|
13
|
+
addBlock(block: Omit<MarkdownBlock, 'id'>): string;
|
|
14
|
+
parse(input: string): MarkdownBlock[];
|
|
15
|
+
private split;
|
|
16
|
+
private parseBlock;
|
|
17
|
+
private lineToPosition;
|
|
18
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
3
|
+
import "core-js/modules/es.regexp.constructor.js";
|
|
4
|
+
import "core-js/modules/es.regexp.dot-all.js";
|
|
5
|
+
import "core-js/modules/es.regexp.exec.js";
|
|
6
|
+
import "core-js/modules/es.string.replace.js";
|
|
7
|
+
import "core-js/modules/es.string.trim.js";
|
|
8
|
+
import "core-js/modules/esnext.iterator.constructor.js";
|
|
9
|
+
import "core-js/modules/esnext.iterator.for-each.js";
|
|
10
|
+
import "core-js/modules/esnext.iterator.map.js";
|
|
11
|
+
import "core-js/modules/web.dom-collections.iterator.js";
|
|
12
|
+
import MarkdownIt from 'markdown-it';
|
|
13
|
+
import { full as emoji } from 'markdown-it-emoji';
|
|
14
|
+
import footnote from 'markdown-it-footnote';
|
|
15
|
+
import { generateId } from '@ray-js/t-agent';
|
|
16
|
+
const md = new MarkdownIt();
|
|
17
|
+
function addClassToTag(MD) {
|
|
18
|
+
// 拦截所有的 token
|
|
19
|
+
MD.core.ruler.push('_add_class_to_tags', state => {
|
|
20
|
+
const addClass = token => {
|
|
21
|
+
if (token.tag === 'img') {
|
|
22
|
+
token.attrPush(['class', "h2w__img"]);
|
|
23
|
+
token.attrPush(['style', 'width:100%;height:auto;']);
|
|
24
|
+
token.attrPush(['width', '100%']);
|
|
25
|
+
token.attrPush(['height', 'auto']);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (token.children && token.children.length) {
|
|
29
|
+
token.children.forEach(addClass);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (token.type.endsWith('_open')) {
|
|
33
|
+
const classIndex = token.attrIndex('class');
|
|
34
|
+
if (classIndex < 0) {
|
|
35
|
+
token.attrPush(['class', "h2w__".concat(token.tag)]);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
state.tokens.forEach(addClass);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 为 table 添加 wrapper,使其可以滚动
|
|
44
|
+
function tableWrapper(MD) {
|
|
45
|
+
// 保存默认的 table_open 和 table_close 渲染规则
|
|
46
|
+
const defaultTableOpenRender = MD.renderer.rules.table_open || function (tokens, idx, options, env, self) {
|
|
47
|
+
return self.renderToken(tokens, idx, options);
|
|
48
|
+
};
|
|
49
|
+
const defaultTableCloseRender = MD.renderer.rules.table_close || function (tokens, idx, options, env, self) {
|
|
50
|
+
return self.renderToken(tokens, idx, options);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// 重写 table_open 渲染规则,添加 wrapper 的开始标签
|
|
54
|
+
MD.renderer.rules.table_open = function (tokens, idx, options, env, self) {
|
|
55
|
+
return '<div class="h2w__tableParent">\n' + defaultTableOpenRender(tokens, idx, options, env, self);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// 重写 table_close 渲染规则,添加 wrapper 的结束标签
|
|
59
|
+
MD.renderer.rules.table_close = function (tokens, idx, options, env, self) {
|
|
60
|
+
return defaultTableCloseRender(tokens, idx, options, env, self) + '</div>\n';
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function fenceWrapper(MD) {
|
|
64
|
+
const defaultFenceRender = MD.renderer.rules.fence || function (tokens, idx, options, env, self) {
|
|
65
|
+
return self.renderToken(tokens, idx, options);
|
|
66
|
+
};
|
|
67
|
+
MD.renderer.rules.fence = function (tokens, idx, options, env, self) {
|
|
68
|
+
const token = tokens[idx];
|
|
69
|
+
|
|
70
|
+
// 在 token 的 attrs 中添加 class 属性
|
|
71
|
+
token.attrSet('class', 'h2w__code');
|
|
72
|
+
|
|
73
|
+
// 使用默认的渲染方法生成代码块的 HTML
|
|
74
|
+
let html = defaultFenceRender(tokens, idx, options, env, self);
|
|
75
|
+
if (html) {
|
|
76
|
+
html = html.replace(/^<pre>/, '<pre class="h2w__pre h2w__fence">');
|
|
77
|
+
}
|
|
78
|
+
return html;
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export class BlockParser {
|
|
82
|
+
constructor(prefix, types, richTextClassName) {
|
|
83
|
+
_defineProperty(this, "list", []);
|
|
84
|
+
_defineProperty(this, "pendingBlocks", []);
|
|
85
|
+
_defineProperty(this, "currentInput", '');
|
|
86
|
+
this.prefix = prefix;
|
|
87
|
+
this.types = types;
|
|
88
|
+
this.richTextClassName = richTextClassName;
|
|
89
|
+
}
|
|
90
|
+
static plugin(MD) {
|
|
91
|
+
MD.core.ruler.push('parse_block', function (state) {
|
|
92
|
+
const tokens = state.tokens;
|
|
93
|
+
const blockParser = state.env.blockParser;
|
|
94
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
95
|
+
const token = tokens[i];
|
|
96
|
+
|
|
97
|
+
// 查找代码块
|
|
98
|
+
if (token.type === 'fence') {
|
|
99
|
+
const blockType = token.info.trim();
|
|
100
|
+
if (blockType && blockParser.isSupportedType(blockType)) {
|
|
101
|
+
const blockId = blockParser.addBlock({
|
|
102
|
+
map: token.map,
|
|
103
|
+
type: blockType,
|
|
104
|
+
children: token.content.trim()
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// 替换成 <custom-block- /> 标签
|
|
108
|
+
tokens[i].type = 'html_inline';
|
|
109
|
+
tokens[i].content = "<".concat(blockId, " />");
|
|
110
|
+
tokens[i].tag = '';
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
isSupportedType(type) {
|
|
117
|
+
return this.types.includes(type);
|
|
118
|
+
}
|
|
119
|
+
addBlock(block) {
|
|
120
|
+
const id = "custom-block-".concat(this.prefix, "-").concat(generateId(8));
|
|
121
|
+
this.pendingBlocks.push(_objectSpread({
|
|
122
|
+
id
|
|
123
|
+
}, block));
|
|
124
|
+
return id;
|
|
125
|
+
}
|
|
126
|
+
parse(input) {
|
|
127
|
+
this.list = this.parseBlock(input);
|
|
128
|
+
// if (!this.currentInput) {
|
|
129
|
+
// // 第一次解析
|
|
130
|
+
// this.list = this.parseBlock(input)
|
|
131
|
+
// } else if (input.length < this.currentInput.length) {
|
|
132
|
+
// // 长度有减少,重新开始
|
|
133
|
+
// this.list = this.parseBlock(input)
|
|
134
|
+
// } else if (input === this.currentInput) {
|
|
135
|
+
// // 完全相等不需要处理
|
|
136
|
+
// return this.list
|
|
137
|
+
// } else if (input.startsWith(this.currentInput)) {
|
|
138
|
+
// // 继续解析
|
|
139
|
+
// const last = this.list.pop() // 丢弃掉最后一个 block
|
|
140
|
+
// const position = this.lineToPosition(last.map[0], input)
|
|
141
|
+
// const delta = input.slice(position)
|
|
142
|
+
// const blocks = this.parseBlock(delta)
|
|
143
|
+
// this.list = this.list.concat(blocks)
|
|
144
|
+
// } else {
|
|
145
|
+
// // 完全不匹配,重新开始
|
|
146
|
+
// this.list = this.parseBlock(input)
|
|
147
|
+
// }
|
|
148
|
+
|
|
149
|
+
this.currentInput = input;
|
|
150
|
+
return this.list;
|
|
151
|
+
}
|
|
152
|
+
split(html, tags) {
|
|
153
|
+
// 创建匹配自闭合标签的正则表达式
|
|
154
|
+
const tagPattern = new RegExp("<(".concat(tags.join('|'), ") />"), 'gi');
|
|
155
|
+
const result = [];
|
|
156
|
+
let lastIndex = 0;
|
|
157
|
+
|
|
158
|
+
// 遍历匹配所有自闭合标签
|
|
159
|
+
let match;
|
|
160
|
+
while ((match = tagPattern.exec(html)) !== null) {
|
|
161
|
+
// 提取自闭合标签前的部分
|
|
162
|
+
if (match.index > lastIndex) {
|
|
163
|
+
result.push(html.slice(lastIndex, match.index));
|
|
164
|
+
}
|
|
165
|
+
// 提取自闭合标签本身
|
|
166
|
+
result.push(match[0]);
|
|
167
|
+
// 更新最后的索引
|
|
168
|
+
lastIndex = tagPattern.lastIndex;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 添加最后一个标签后的部分
|
|
172
|
+
if (lastIndex < html.length) {
|
|
173
|
+
result.push(html.slice(lastIndex));
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
177
|
+
parseBlock(input) {
|
|
178
|
+
const _input = input.replace(/\\n/g, '<br>').replace(/\\<br>/g, '<br>').replace(/\\"/g, '"');
|
|
179
|
+
this.pendingBlocks = [];
|
|
180
|
+
const html = md.render(_input, {
|
|
181
|
+
blockParser: this
|
|
182
|
+
});
|
|
183
|
+
if (!this.pendingBlocks.length) {
|
|
184
|
+
const last = this.list[this.list.length - 1];
|
|
185
|
+
const id = "".concat(this.prefix, "-block-").concat(this.list.length);
|
|
186
|
+
const blocks = [{
|
|
187
|
+
id,
|
|
188
|
+
type: 'rich-text',
|
|
189
|
+
map: [last ? last.map[1] + 1 : 1, Infinity],
|
|
190
|
+
children: "<div class=\"".concat(this.richTextClassName, "\">").concat(html, "</div>")
|
|
191
|
+
}];
|
|
192
|
+
return blocks;
|
|
193
|
+
}
|
|
194
|
+
const map = new Map();
|
|
195
|
+
const ids = [];
|
|
196
|
+
for (const item of this.pendingBlocks) {
|
|
197
|
+
map.set("<".concat(item.id, " />"), item);
|
|
198
|
+
ids.push(item.id);
|
|
199
|
+
}
|
|
200
|
+
const parts = this.split(html, ids);
|
|
201
|
+
const blocks = [];
|
|
202
|
+
let nextBlockLine = 1;
|
|
203
|
+
let prevTextBlock = null;
|
|
204
|
+
for (let i = 0; i < parts.length; i++) {
|
|
205
|
+
const part = parts[i];
|
|
206
|
+
const id = "".concat(this.prefix, "-block-").concat(i);
|
|
207
|
+
if (map.has(part)) {
|
|
208
|
+
const block = map.get(part);
|
|
209
|
+
blocks.push({
|
|
210
|
+
id,
|
|
211
|
+
map: block.map,
|
|
212
|
+
type: block.type,
|
|
213
|
+
children: block.children
|
|
214
|
+
});
|
|
215
|
+
nextBlockLine = block.map[1] + 1;
|
|
216
|
+
if (prevTextBlock) {
|
|
217
|
+
prevTextBlock.map[1] = block.map[0] - 1;
|
|
218
|
+
}
|
|
219
|
+
prevTextBlock = null;
|
|
220
|
+
} else {
|
|
221
|
+
const block = {
|
|
222
|
+
id,
|
|
223
|
+
map: [nextBlockLine, Infinity],
|
|
224
|
+
type: 'rich-text',
|
|
225
|
+
children: "<div class=\"".concat(this.richTextClassName, "\">").concat(part, "</div>")
|
|
226
|
+
};
|
|
227
|
+
prevTextBlock = block;
|
|
228
|
+
blocks.push(block);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return blocks;
|
|
232
|
+
}
|
|
233
|
+
lineToPosition(lineNumber, input) {
|
|
234
|
+
let position = 0;
|
|
235
|
+
if (lineNumber === 1) {
|
|
236
|
+
return position;
|
|
237
|
+
}
|
|
238
|
+
if (lineNumber === Infinity) {
|
|
239
|
+
const lastNewlineIndex = input.lastIndexOf('\n');
|
|
240
|
+
return lastNewlineIndex === -1 ? 0 : lastNewlineIndex + 1;
|
|
241
|
+
}
|
|
242
|
+
let currentLine = 1; // 当前行号
|
|
243
|
+
|
|
244
|
+
// 从文本开始搜索每个换行符
|
|
245
|
+
while (currentLine < lineNumber) {
|
|
246
|
+
// 查找下一个换行符的位置
|
|
247
|
+
position = input.indexOf('\n', position);
|
|
248
|
+
|
|
249
|
+
// 如果没有找到换行符,说明行号超出范围
|
|
250
|
+
if (position === -1) {
|
|
251
|
+
return input.lastIndexOf('\n') + 1 || 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// 换行符的位置 + 1 为下一行的起始位置
|
|
255
|
+
position += 1;
|
|
256
|
+
currentLine++;
|
|
257
|
+
}
|
|
258
|
+
return position;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
md.use(addClassToTag).use(tableWrapper).use(fenceWrapper).use(emoji).use(footnote).use(BlockParser.plugin);
|