@douyinfe/semi-foundation 2.88.0-beta.1 → 2.88.0
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/aiChatDialogue/dataAdapter/chatInputToChatCompletion.ts +7 -4
- package/aiChatInput/foundation.ts +40 -9
- package/aiChatInput/interface.ts +4 -4
- package/aiChatInput/utils.ts +53 -11
- package/chat/foundation.ts +4 -0
- package/cropper/cropper.scss +5 -0
- package/image/image.scss +9 -6
- package/lib/cjs/aiChatDialogue/dataAdapter/chatInputToChatCompletion.js +7 -4
- package/lib/cjs/aiChatInput/foundation.d.ts +1 -0
- package/lib/cjs/aiChatInput/foundation.js +44 -8
- package/lib/cjs/aiChatInput/interface.d.ts +4 -4
- package/lib/cjs/aiChatInput/utils.d.ts +14 -5
- package/lib/cjs/aiChatInput/utils.js +57 -8
- package/lib/cjs/chat/foundation.d.ts +1 -0
- package/lib/cjs/chat/foundation.js +3 -0
- package/lib/cjs/cropper/cropper.css +3 -0
- package/lib/cjs/cropper/cropper.scss +5 -0
- package/lib/cjs/image/image.css +8 -6
- package/lib/cjs/image/image.scss +9 -6
- package/lib/cjs/tag/tag.scss +4 -4
- package/lib/es/aiChatDialogue/dataAdapter/chatInputToChatCompletion.js +7 -4
- package/lib/es/aiChatInput/foundation.d.ts +1 -0
- package/lib/es/aiChatInput/foundation.js +45 -9
- package/lib/es/aiChatInput/interface.d.ts +4 -4
- package/lib/es/aiChatInput/utils.d.ts +14 -5
- package/lib/es/aiChatInput/utils.js +55 -8
- package/lib/es/chat/foundation.d.ts +1 -0
- package/lib/es/chat/foundation.js +3 -0
- package/lib/es/cropper/cropper.css +3 -0
- package/lib/es/cropper/cropper.scss +5 -0
- package/lib/es/image/image.css +8 -6
- package/lib/es/image/image.scss +9 -6
- package/lib/es/tag/tag.scss +4 -4
- package/package.json +4 -4
- package/tag/tag.scss +4 -4
|
@@ -39,10 +39,13 @@ export default function chatInputToChatCompletion(inputContent: any): ChatComple
|
|
|
39
39
|
|
|
40
40
|
return {
|
|
41
41
|
role: "user",
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
messages: [{
|
|
43
|
+
role: "user",
|
|
44
|
+
content: inputs,
|
|
45
|
+
}],
|
|
46
|
+
model: setup?.model,
|
|
47
|
+
references,
|
|
48
|
+
setup: setup ?? {}
|
|
46
49
|
};
|
|
47
50
|
|
|
48
51
|
}
|
|
@@ -2,7 +2,7 @@ import BaseFoundation, { DefaultAdapter } from '../base/foundation';
|
|
|
2
2
|
import { Attachment, BaseSkill, Suggestion, Reference, Content, LeftMenuChangeProps, MessageContent } from './interface';
|
|
3
3
|
import { isNumber, isString } from 'lodash';
|
|
4
4
|
import { cssClasses } from './constants';
|
|
5
|
-
import { transformJSONResult } from './utils';
|
|
5
|
+
import { findSkillSlotInString, getSkillSlotString, transformJSONResult } from './utils';
|
|
6
6
|
|
|
7
7
|
export interface AIChatInputAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
|
|
8
8
|
reposPopover: () => void;
|
|
@@ -16,6 +16,7 @@ export interface AIChatInputAdapter<P = Record<string, any>, S = Record<string,
|
|
|
16
16
|
manualUpload: (files: File[]) => void;
|
|
17
17
|
notifyMessageSend: (props: MessageContent) => void;
|
|
18
18
|
notifyStopGenerate: () => void;
|
|
19
|
+
notifySkillChange: (skill: BaseSkill) => void;
|
|
19
20
|
clearContent: () => void;
|
|
20
21
|
clearAttachments: () => void;
|
|
21
22
|
getRichTextDiv: () => HTMLDivElement | null;
|
|
@@ -51,7 +52,8 @@ export default class AIChatInputFoundation extends BaseFoundation<AIChatInputAda
|
|
|
51
52
|
skill: skill,
|
|
52
53
|
skillVisible: false
|
|
53
54
|
});
|
|
54
|
-
this._adapter.
|
|
55
|
+
this._adapter.notifySkillChange(skill);
|
|
56
|
+
this._adapter.setContent(getSkillSlotString(skill));
|
|
55
57
|
this._adapter.focusEditor();
|
|
56
58
|
}
|
|
57
59
|
|
|
@@ -199,16 +201,25 @@ export default class AIChatInputFoundation extends BaseFoundation<AIChatInputAda
|
|
|
199
201
|
const { transformer } = this.getProps();
|
|
200
202
|
const { skill } = this.getStates();
|
|
201
203
|
const editor = this._adapter.getEditor();
|
|
202
|
-
const jsonResult = editor.getJSON();
|
|
203
|
-
const finalResult = transformJSONResult(jsonResult, transformer);
|
|
204
|
-
this._adapter.notifyContentChange(finalResult);
|
|
205
204
|
const html = editor.getHTML();
|
|
206
|
-
if (
|
|
205
|
+
if (skill && !html.includes('</skill-slot>')) {
|
|
207
206
|
this.setState({
|
|
208
|
-
skill:
|
|
207
|
+
skill: undefined,
|
|
209
208
|
templateVisible: false
|
|
210
209
|
});
|
|
210
|
+
this._adapter.notifySkillChange(undefined);
|
|
211
|
+
this._adapter.notifyContentChange([]);
|
|
212
|
+
return;
|
|
213
|
+
} else if (html.includes('</skill-slot>')) {
|
|
214
|
+
const newSkill = findSkillSlotInString(html);
|
|
215
|
+
if (newSkill?.value !== skill?.value) {
|
|
216
|
+
this.setState({ skill: newSkill });
|
|
217
|
+
this._adapter.notifySkillChange(newSkill);
|
|
218
|
+
}
|
|
211
219
|
}
|
|
220
|
+
const jsonResult = editor.getJSON();
|
|
221
|
+
const finalResult = transformJSONResult(jsonResult, transformer);
|
|
222
|
+
this._adapter.notifyContentChange(finalResult);
|
|
212
223
|
this.setState({
|
|
213
224
|
content: jsonResult,
|
|
214
225
|
});
|
|
@@ -265,7 +276,7 @@ export default class AIChatInputFoundation extends BaseFoundation<AIChatInputAda
|
|
|
265
276
|
}
|
|
266
277
|
|
|
267
278
|
handleSend = () => {
|
|
268
|
-
const { generating } = this.getProps();
|
|
279
|
+
const { generating, transformer } = this.getProps();
|
|
269
280
|
if (generating) {
|
|
270
281
|
this._adapter.notifyStopGenerate();
|
|
271
282
|
return;
|
|
@@ -279,7 +290,7 @@ export default class AIChatInputFoundation extends BaseFoundation<AIChatInputAda
|
|
|
279
290
|
let richTextResult = [];
|
|
280
291
|
if (editor) {
|
|
281
292
|
const json = editor.getJSON?.();
|
|
282
|
-
richTextResult = transformJSONResult(json);
|
|
293
|
+
richTextResult = transformJSONResult(json, transformer);
|
|
283
294
|
}
|
|
284
295
|
// close popup layer for template/skill/suggestion
|
|
285
296
|
this.setState({
|
|
@@ -338,6 +349,26 @@ export default class AIChatInputFoundation extends BaseFoundation<AIChatInputAda
|
|
|
338
349
|
this.handleSend();
|
|
339
350
|
return true;
|
|
340
351
|
}
|
|
352
|
+
if (event.key === 'Enter' && event.shiftKey) {
|
|
353
|
+
/**
|
|
354
|
+
* Tiptap 默认情况下 Enter + Shift 时候是使用 <br /> 实现换行
|
|
355
|
+
* 为保证自定义的一些逻辑生效(比如零宽字符的插入),Enter + Shift 希望实现通过新建 p 标签的方式完成换行
|
|
356
|
+
* 此处拦截默认操作,使用新建 p 标签方式实现换行
|
|
357
|
+
* Tiptap, by default, uses <br /> to create a newline character when you press Enter + Shift.
|
|
358
|
+
* To ensure that some custom logic works (such as the insertion of zero-width characters),
|
|
359
|
+
* we want Enter + Shift to create a new p tag to initiate a line break.
|
|
360
|
+
* This section intercepts the default operation and uses a newly created `<p>` tag to achieve line breaks.
|
|
361
|
+
*/
|
|
362
|
+
event.preventDefault();
|
|
363
|
+
const editor = this._adapter.getEditor();
|
|
364
|
+
if (editor && editor.chain && editor.chain().splitBlock) {
|
|
365
|
+
editor.chain().focus().splitBlock().run();
|
|
366
|
+
} else if (editor && editor.view) {
|
|
367
|
+
const { state, view } = editor;
|
|
368
|
+
view.dispatch(state.tr.split(state.selection.from));
|
|
369
|
+
}
|
|
370
|
+
return true;
|
|
371
|
+
}
|
|
341
372
|
if (event.key !== 'Backspace') return false;
|
|
342
373
|
return false;
|
|
343
374
|
}
|
package/aiChatInput/interface.ts
CHANGED
package/aiChatInput/utils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Attachment, Reference } from "./interface";
|
|
1
|
+
import { Attachment, BaseSkill, Reference } from "./interface";
|
|
2
2
|
import { strings } from './constants';
|
|
3
3
|
|
|
4
4
|
export function getAttachmentType(item: Attachment | Reference) {
|
|
@@ -53,12 +53,8 @@ export function transformSelectSlot(obj: any) {
|
|
|
53
53
|
|
|
54
54
|
export function transformSkillSlot(obj: any) {
|
|
55
55
|
const { type, attrs } = obj;
|
|
56
|
-
const { value,
|
|
57
|
-
return {
|
|
58
|
-
type,
|
|
59
|
-
value,
|
|
60
|
-
...(JSON.parse(info) ?? {}),
|
|
61
|
-
};
|
|
56
|
+
const { value, label, hasTemplate } = attrs;
|
|
57
|
+
return omitUndefinedFromObj({ type, value, label, hasTemplate });
|
|
62
58
|
}
|
|
63
59
|
|
|
64
60
|
export function transformInputSlot(obj: any) {
|
|
@@ -71,14 +67,18 @@ export function transformInputSlot(obj: any) {
|
|
|
71
67
|
}
|
|
72
68
|
|
|
73
69
|
export function transformText(obj: any) {
|
|
74
|
-
|
|
70
|
+
const { text } = obj;
|
|
71
|
+
return {
|
|
72
|
+
type: 'text',
|
|
73
|
+
text: text !== strings.ZERO_WIDTH_CHAR ? text : ''
|
|
74
|
+
};
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
export const transformMap = new Map([
|
|
77
|
+
export const transformMap = new Map<string, any>([
|
|
78
78
|
['text', transformText],
|
|
79
79
|
['selectSlot', transformSelectSlot],
|
|
80
80
|
['inputSlot', transformInputSlot],
|
|
81
|
-
['
|
|
81
|
+
['skillSlot', transformSkillSlot],
|
|
82
82
|
]);
|
|
83
83
|
|
|
84
84
|
export function transformJSONResult(input: any, customTransformObj: Map<string, (obj: any) => any> = new Map()) {
|
|
@@ -116,6 +116,10 @@ export function transformJSONResult(input: any, customTransformObj: Map<string,
|
|
|
116
116
|
const lastItem = output[output.length - 1];
|
|
117
117
|
if (lastItem && lastItem.type === 'text') {
|
|
118
118
|
lastItem.text += result.text;
|
|
119
|
+
} else if (typeof result.text === 'string') {
|
|
120
|
+
// 如果 result.text 为空字符串(比如text 节点中只有单个的零宽字符),则无需作为 output 结果
|
|
121
|
+
// if result.text is an empty string,then it does not need to be included in output result.
|
|
122
|
+
result.text.length && output.push(result);
|
|
119
123
|
} else {
|
|
120
124
|
output.push(result);
|
|
121
125
|
}
|
|
@@ -134,7 +138,45 @@ export function getCustomSlotAttribute() {
|
|
|
134
138
|
default: true,
|
|
135
139
|
parseHTML: element => true,
|
|
136
140
|
renderHTML: attributes => ({
|
|
137
|
-
'data-custom-slot': attributes.isCustomSlot ?
|
|
141
|
+
'data-custom-slot': attributes.isCustomSlot ? true : undefined,
|
|
138
142
|
}),
|
|
139
143
|
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function findSkillSlotInString(content: string) {
|
|
147
|
+
const reg = /<skill-slot\s+([^>]*)><\/skill-slot>/i;
|
|
148
|
+
const attrReg = /([\w-]+)=["']?([^"'\s>]+)["']?/g;
|
|
149
|
+
const match = reg.exec(content);
|
|
150
|
+
if (match) {
|
|
151
|
+
const attrsStr = match[1];
|
|
152
|
+
let attrMatch;
|
|
153
|
+
let attrs = {};
|
|
154
|
+
while ((attrMatch = attrReg.exec(attrsStr)) !== null) {
|
|
155
|
+
attrs[attrMatch[1]] = attrMatch[2];
|
|
156
|
+
}
|
|
157
|
+
if (attrs['data-value']) {
|
|
158
|
+
const obj = {
|
|
159
|
+
label: attrs['data-label'],
|
|
160
|
+
value: attrs['data-value'],
|
|
161
|
+
hasTemplate: attrs['data-template'] ? attrs['data-template'] === 'true' : undefined
|
|
162
|
+
};
|
|
163
|
+
return omitUndefinedFromObj(obj);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
function omitUndefinedFromObj(obj: { [key: string]: any }) {
|
|
171
|
+
return Object.fromEntries(
|
|
172
|
+
Object.entries(obj).filter(([key, value]) => value !== undefined)
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function getSkillSlotString(skill: BaseSkill) {
|
|
177
|
+
let skillParams = '';
|
|
178
|
+
skill.label && (skillParams += ` data-label=${skill.label}`);
|
|
179
|
+
skill.value && (skillParams += ` data-value=${skill.value}`);
|
|
180
|
+
(typeof skill.hasTemplate === 'boolean') && (skillParams += ` data-template=${skill.hasTemplate}`);
|
|
181
|
+
return `<skill-slot ${skillParams}"></skill-slot>`;
|
|
140
182
|
}
|
package/chat/foundation.ts
CHANGED
|
@@ -145,6 +145,10 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
|
|
|
145
145
|
return scroll;
|
|
146
146
|
}, 100)
|
|
147
147
|
|
|
148
|
+
handleScrollContainerResize = () => {
|
|
149
|
+
this.getScroll(this._adapter.getContainerRef());
|
|
150
|
+
}
|
|
151
|
+
|
|
148
152
|
clearContext = (e: any) => {
|
|
149
153
|
const { chats } = this.getStates();
|
|
150
154
|
if (chats[chats.length - 1].role === ROLE.DIVIDER) {
|
package/cropper/cropper.scss
CHANGED
|
@@ -6,6 +6,11 @@ $half_corner_width: calc($width-cropper_box_corner / 2);
|
|
|
6
6
|
.#{$module} {
|
|
7
7
|
position: relative;
|
|
8
8
|
|
|
9
|
+
& img {
|
|
10
|
+
// To avoid the `max-Width` setting of `img` to 100% in `tailwindCSS` affecting the style of img in Cropper.
|
|
11
|
+
max-width: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
&-img {
|
|
10
15
|
position: absolute;
|
|
11
16
|
user-select: none;
|
package/image/image.scss
CHANGED
|
@@ -10,6 +10,15 @@ $module: #{$prefix}-image;
|
|
|
10
10
|
display: inline-block;
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
|
|
13
|
+
img {
|
|
14
|
+
/**
|
|
15
|
+
* In tailwind, the max-width of img/video is set to 100%,
|
|
16
|
+
* which will affect the amplification effect of the picture.
|
|
17
|
+
* So we need to set max-width to none.
|
|
18
|
+
*/
|
|
19
|
+
max-width: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
&-img {
|
|
14
23
|
vertical-align: top;
|
|
15
24
|
border-radius: inherit;
|
|
@@ -204,12 +213,6 @@ $module: #{$prefix}-image;
|
|
|
204
213
|
// transition: transform $transition_duration-image_preview_image_img $transition_delay-image_preview_image_img;
|
|
205
214
|
z-index: 0;
|
|
206
215
|
user-select: none;
|
|
207
|
-
/**
|
|
208
|
-
* In tailwind, the max-width of img/video is set to 100%,
|
|
209
|
-
* which will affect the amplification effect of the picture.
|
|
210
|
-
* So we need to set max-width to none.
|
|
211
|
-
*/
|
|
212
|
-
max-width: none;
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
&-spin {
|
|
@@ -49,9 +49,12 @@ function chatInputToChatCompletion(inputContent) {
|
|
|
49
49
|
}
|
|
50
50
|
return {
|
|
51
51
|
role: "user",
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
messages: [{
|
|
53
|
+
role: "user",
|
|
54
|
+
content: inputs
|
|
55
|
+
}],
|
|
56
|
+
model: setup === null || setup === void 0 ? void 0 : setup.model,
|
|
57
|
+
references,
|
|
58
|
+
setup: setup !== null && setup !== void 0 ? setup : {}
|
|
56
59
|
};
|
|
57
60
|
}
|
|
@@ -12,6 +12,7 @@ export interface AIChatInputAdapter<P = Record<string, any>, S = Record<string,
|
|
|
12
12
|
manualUpload: (files: File[]) => void;
|
|
13
13
|
notifyMessageSend: (props: MessageContent) => void;
|
|
14
14
|
notifyStopGenerate: () => void;
|
|
15
|
+
notifySkillChange: (skill: BaseSkill) => void;
|
|
15
16
|
clearContent: () => void;
|
|
16
17
|
clearAttachments: () => void;
|
|
17
18
|
getRichTextDiv: () => HTMLDivElement | null;
|
|
@@ -24,7 +24,8 @@ class AIChatInputFoundation extends _foundation.default {
|
|
|
24
24
|
skill: skill,
|
|
25
25
|
skillVisible: false
|
|
26
26
|
});
|
|
27
|
-
this._adapter.
|
|
27
|
+
this._adapter.notifySkillChange(skill);
|
|
28
|
+
this._adapter.setContent((0, _utils.getSkillSlotString)(skill));
|
|
28
29
|
this._adapter.focusEditor();
|
|
29
30
|
};
|
|
30
31
|
this.changeTemplateVisible = value => {
|
|
@@ -170,16 +171,27 @@ class AIChatInputFoundation extends _foundation.default {
|
|
|
170
171
|
skill
|
|
171
172
|
} = this.getStates();
|
|
172
173
|
const editor = this._adapter.getEditor();
|
|
173
|
-
const jsonResult = editor.getJSON();
|
|
174
|
-
const finalResult = (0, _utils.transformJSONResult)(jsonResult, transformer);
|
|
175
|
-
this._adapter.notifyContentChange(finalResult);
|
|
176
174
|
const html = editor.getHTML();
|
|
177
|
-
if (
|
|
175
|
+
if (skill && !html.includes('</skill-slot>')) {
|
|
178
176
|
this.setState({
|
|
179
|
-
skill:
|
|
177
|
+
skill: undefined,
|
|
180
178
|
templateVisible: false
|
|
181
179
|
});
|
|
180
|
+
this._adapter.notifySkillChange(undefined);
|
|
181
|
+
this._adapter.notifyContentChange([]);
|
|
182
|
+
return;
|
|
183
|
+
} else if (html.includes('</skill-slot>')) {
|
|
184
|
+
const newSkill = (0, _utils.findSkillSlotInString)(html);
|
|
185
|
+
if ((newSkill === null || newSkill === void 0 ? void 0 : newSkill.value) !== (skill === null || skill === void 0 ? void 0 : skill.value)) {
|
|
186
|
+
this.setState({
|
|
187
|
+
skill: newSkill
|
|
188
|
+
});
|
|
189
|
+
this._adapter.notifySkillChange(newSkill);
|
|
190
|
+
}
|
|
182
191
|
}
|
|
192
|
+
const jsonResult = editor.getJSON();
|
|
193
|
+
const finalResult = (0, _utils.transformJSONResult)(jsonResult, transformer);
|
|
194
|
+
this._adapter.notifyContentChange(finalResult);
|
|
183
195
|
this.setState({
|
|
184
196
|
content: jsonResult
|
|
185
197
|
});
|
|
@@ -245,7 +257,8 @@ class AIChatInputFoundation extends _foundation.default {
|
|
|
245
257
|
this.handleSend = () => {
|
|
246
258
|
var _a, _b;
|
|
247
259
|
const {
|
|
248
|
-
generating
|
|
260
|
+
generating,
|
|
261
|
+
transformer
|
|
249
262
|
} = this.getProps();
|
|
250
263
|
if (generating) {
|
|
251
264
|
this._adapter.notifyStopGenerate();
|
|
@@ -262,7 +275,7 @@ class AIChatInputFoundation extends _foundation.default {
|
|
|
262
275
|
let richTextResult = [];
|
|
263
276
|
if (editor) {
|
|
264
277
|
const json = (_a = editor.getJSON) === null || _a === void 0 ? void 0 : _a.call(editor);
|
|
265
|
-
richTextResult = (0, _utils.transformJSONResult)(json);
|
|
278
|
+
richTextResult = (0, _utils.transformJSONResult)(json, transformer);
|
|
266
279
|
}
|
|
267
280
|
// close popup layer for template/skill/suggestion
|
|
268
281
|
this.setState({
|
|
@@ -323,6 +336,29 @@ class AIChatInputFoundation extends _foundation.default {
|
|
|
323
336
|
this.handleSend();
|
|
324
337
|
return true;
|
|
325
338
|
}
|
|
339
|
+
if (event.key === 'Enter' && event.shiftKey) {
|
|
340
|
+
/**
|
|
341
|
+
* Tiptap 默认情况下 Enter + Shift 时候是使用 <br /> 实现换行
|
|
342
|
+
* 为保证自定义的一些逻辑生效(比如零宽字符的插入),Enter + Shift 希望实现通过新建 p 标签的方式完成换行
|
|
343
|
+
* 此处拦截默认操作,使用新建 p 标签方式实现换行
|
|
344
|
+
* Tiptap, by default, uses <br /> to create a newline character when you press Enter + Shift.
|
|
345
|
+
* To ensure that some custom logic works (such as the insertion of zero-width characters),
|
|
346
|
+
* we want Enter + Shift to create a new p tag to initiate a line break.
|
|
347
|
+
* This section intercepts the default operation and uses a newly created `<p>` tag to achieve line breaks.
|
|
348
|
+
*/
|
|
349
|
+
event.preventDefault();
|
|
350
|
+
const editor = this._adapter.getEditor();
|
|
351
|
+
if (editor && editor.chain && editor.chain().splitBlock) {
|
|
352
|
+
editor.chain().focus().splitBlock().run();
|
|
353
|
+
} else if (editor && editor.view) {
|
|
354
|
+
const {
|
|
355
|
+
state,
|
|
356
|
+
view
|
|
357
|
+
} = editor;
|
|
358
|
+
view.dispatch(state.tr.split(state.selection.from));
|
|
359
|
+
}
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
326
362
|
if (event.key !== 'Backspace') return false;
|
|
327
363
|
return false;
|
|
328
364
|
};
|
|
@@ -4,10 +4,10 @@ export interface RichTextJSON {
|
|
|
4
4
|
[key: string]: any;
|
|
5
5
|
}
|
|
6
6
|
export interface BaseSkill {
|
|
7
|
-
icon
|
|
8
|
-
value
|
|
9
|
-
label
|
|
10
|
-
hasTemplate
|
|
7
|
+
icon?: any;
|
|
8
|
+
value?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
hasTemplate?: boolean;
|
|
11
11
|
[key: string]: any;
|
|
12
12
|
}
|
|
13
13
|
export type Suggestion = string[] | {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Attachment, Reference } from "./interface";
|
|
1
|
+
import { Attachment, BaseSkill, Reference } from "./interface";
|
|
2
2
|
export declare function getAttachmentType(item: Attachment | Reference): any;
|
|
3
3
|
export declare function isImageType(item: Attachment | Reference): any;
|
|
4
4
|
export declare function getContentType(type: string): string;
|
|
@@ -6,18 +6,27 @@ export declare function transformSelectSlot(obj: any): {
|
|
|
6
6
|
type: string;
|
|
7
7
|
text: any;
|
|
8
8
|
};
|
|
9
|
-
export declare function transformSkillSlot(obj: any):
|
|
9
|
+
export declare function transformSkillSlot(obj: any): {
|
|
10
|
+
[k: string]: any;
|
|
11
|
+
};
|
|
10
12
|
export declare function transformInputSlot(obj: any): {
|
|
11
13
|
type: string;
|
|
12
14
|
text: any;
|
|
13
15
|
};
|
|
14
|
-
export declare function transformText(obj: any):
|
|
15
|
-
|
|
16
|
+
export declare function transformText(obj: any): {
|
|
17
|
+
type: string;
|
|
18
|
+
text: any;
|
|
19
|
+
};
|
|
20
|
+
export declare const transformMap: Map<string, any>;
|
|
16
21
|
export declare function transformJSONResult(input: any, customTransformObj?: Map<string, (obj: any) => any>): any[];
|
|
17
22
|
export declare function getCustomSlotAttribute(): {
|
|
18
23
|
default: boolean;
|
|
19
24
|
parseHTML: (element: any) => boolean;
|
|
20
25
|
renderHTML: (attributes: any) => {
|
|
21
|
-
'data-custom-slot':
|
|
26
|
+
'data-custom-slot': boolean;
|
|
22
27
|
};
|
|
23
28
|
};
|
|
29
|
+
export declare function findSkillSlotInString(content: string): {
|
|
30
|
+
[k: string]: any;
|
|
31
|
+
};
|
|
32
|
+
export declare function getSkillSlotString(skill: BaseSkill): string;
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
+
exports.findSkillSlotInString = findSkillSlotInString;
|
|
6
7
|
exports.getAttachmentType = getAttachmentType;
|
|
7
8
|
exports.getContentType = getContentType;
|
|
8
9
|
exports.getCustomSlotAttribute = getCustomSlotAttribute;
|
|
10
|
+
exports.getSkillSlotString = getSkillSlotString;
|
|
9
11
|
exports.isImageType = isImageType;
|
|
10
12
|
exports.transformInputSlot = transformInputSlot;
|
|
11
13
|
exports.transformJSONResult = transformJSONResult;
|
|
@@ -69,19 +71,21 @@ function transformSelectSlot(obj) {
|
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
73
|
function transformSkillSlot(obj) {
|
|
72
|
-
var _a;
|
|
73
74
|
const {
|
|
74
75
|
type,
|
|
75
76
|
attrs
|
|
76
77
|
} = obj;
|
|
77
78
|
const {
|
|
78
79
|
value,
|
|
79
|
-
|
|
80
|
+
label,
|
|
81
|
+
hasTemplate
|
|
80
82
|
} = attrs;
|
|
81
|
-
return
|
|
83
|
+
return omitUndefinedFromObj({
|
|
82
84
|
type,
|
|
83
|
-
value
|
|
84
|
-
|
|
85
|
+
value,
|
|
86
|
+
label,
|
|
87
|
+
hasTemplate
|
|
88
|
+
});
|
|
85
89
|
}
|
|
86
90
|
function transformInputSlot(obj) {
|
|
87
91
|
var _a, _b;
|
|
@@ -96,9 +100,15 @@ function transformInputSlot(obj) {
|
|
|
96
100
|
};
|
|
97
101
|
}
|
|
98
102
|
function transformText(obj) {
|
|
99
|
-
|
|
103
|
+
const {
|
|
104
|
+
text
|
|
105
|
+
} = obj;
|
|
106
|
+
return {
|
|
107
|
+
type: 'text',
|
|
108
|
+
text: text !== _constants.strings.ZERO_WIDTH_CHAR ? text : ''
|
|
109
|
+
};
|
|
100
110
|
}
|
|
101
|
-
const transformMap = exports.transformMap = new Map([['text', transformText], ['selectSlot', transformSelectSlot], ['inputSlot', transformInputSlot], ['
|
|
111
|
+
const transformMap = exports.transformMap = new Map([['text', transformText], ['selectSlot', transformSelectSlot], ['inputSlot', transformInputSlot], ['skillSlot', transformSkillSlot]]);
|
|
102
112
|
function transformJSONResult(input) {
|
|
103
113
|
let customTransformObj = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Map();
|
|
104
114
|
const output = [];
|
|
@@ -141,6 +151,10 @@ function transformJSONResult(input) {
|
|
|
141
151
|
const lastItem = output[output.length - 1];
|
|
142
152
|
if (lastItem && lastItem.type === 'text') {
|
|
143
153
|
lastItem.text += result.text;
|
|
154
|
+
} else if (typeof result.text === 'string') {
|
|
155
|
+
// 如果 result.text 为空字符串(比如text 节点中只有单个的零宽字符),则无需作为 output 结果
|
|
156
|
+
// if result.text is an empty string,then it does not need to be included in output result.
|
|
157
|
+
result.text.length && output.push(result);
|
|
144
158
|
} else {
|
|
145
159
|
output.push(result);
|
|
146
160
|
}
|
|
@@ -157,7 +171,42 @@ function getCustomSlotAttribute() {
|
|
|
157
171
|
default: true,
|
|
158
172
|
parseHTML: element => true,
|
|
159
173
|
renderHTML: attributes => ({
|
|
160
|
-
'data-custom-slot': attributes.isCustomSlot ?
|
|
174
|
+
'data-custom-slot': attributes.isCustomSlot ? true : undefined
|
|
161
175
|
})
|
|
162
176
|
};
|
|
177
|
+
}
|
|
178
|
+
function findSkillSlotInString(content) {
|
|
179
|
+
const reg = /<skill-slot\s+([^>]*)><\/skill-slot>/i;
|
|
180
|
+
const attrReg = /([\w-]+)=["']?([^"'\s>]+)["']?/g;
|
|
181
|
+
const match = reg.exec(content);
|
|
182
|
+
if (match) {
|
|
183
|
+
const attrsStr = match[1];
|
|
184
|
+
let attrMatch;
|
|
185
|
+
let attrs = {};
|
|
186
|
+
while ((attrMatch = attrReg.exec(attrsStr)) !== null) {
|
|
187
|
+
attrs[attrMatch[1]] = attrMatch[2];
|
|
188
|
+
}
|
|
189
|
+
if (attrs['data-value']) {
|
|
190
|
+
const obj = {
|
|
191
|
+
label: attrs['data-label'],
|
|
192
|
+
value: attrs['data-value'],
|
|
193
|
+
hasTemplate: attrs['data-template'] ? attrs['data-template'] === 'true' : undefined
|
|
194
|
+
};
|
|
195
|
+
return omitUndefinedFromObj(obj);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return undefined;
|
|
199
|
+
}
|
|
200
|
+
function omitUndefinedFromObj(obj) {
|
|
201
|
+
return Object.fromEntries(Object.entries(obj).filter(_ref => {
|
|
202
|
+
let [key, value] = _ref;
|
|
203
|
+
return value !== undefined;
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
function getSkillSlotString(skill) {
|
|
207
|
+
let skillParams = '';
|
|
208
|
+
skill.label && (skillParams += ` data-label=${skill.label}`);
|
|
209
|
+
skill.value && (skillParams += ` data-value=${skill.value}`);
|
|
210
|
+
typeof skill.hasTemplate === 'boolean' && (skillParams += ` data-template=${skill.hasTemplate}`);
|
|
211
|
+
return `<skill-slot ${skillParams}"></skill-slot>`;
|
|
163
212
|
}
|
|
@@ -64,6 +64,7 @@ export default class ChatFoundation<P = Record<string, any>, S = Record<string,
|
|
|
64
64
|
scrollToBottomWithAnimation: () => void;
|
|
65
65
|
containerScroll: (e: any) => void;
|
|
66
66
|
getScroll: import("lodash").DebouncedFunc<(target: any) => typeof scroll>;
|
|
67
|
+
handleScrollContainerResize: () => void;
|
|
67
68
|
clearContext: (e: any) => void;
|
|
68
69
|
onMessageSend: (input: string, attachment: any[]) => void;
|
|
69
70
|
onHintClick: (hint: string) => void;
|
|
@@ -6,6 +6,11 @@ $half_corner_width: calc($width-cropper_box_corner / 2);
|
|
|
6
6
|
.#{$module} {
|
|
7
7
|
position: relative;
|
|
8
8
|
|
|
9
|
+
& img {
|
|
10
|
+
// To avoid the `max-Width` setting of `img` to 100% in `tailwindCSS` affecting the style of img in Cropper.
|
|
11
|
+
max-width: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
&-img {
|
|
10
15
|
position: absolute;
|
|
11
16
|
user-select: none;
|
package/lib/cjs/image/image.css
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
display: inline-block;
|
|
8
8
|
overflow: hidden;
|
|
9
9
|
}
|
|
10
|
+
.semi-image img {
|
|
11
|
+
/**
|
|
12
|
+
* In tailwind, the max-width of img/video is set to 100%,
|
|
13
|
+
* which will affect the amplification effect of the picture.
|
|
14
|
+
* So we need to set max-width to none.
|
|
15
|
+
*/
|
|
16
|
+
max-width: none;
|
|
17
|
+
}
|
|
10
18
|
.semi-image-img {
|
|
11
19
|
vertical-align: top;
|
|
12
20
|
border-radius: inherit;
|
|
@@ -177,12 +185,6 @@
|
|
|
177
185
|
transform: scale3d(1, 1, 1) var(--semi-transform-rotate-none);
|
|
178
186
|
z-index: 0;
|
|
179
187
|
user-select: none;
|
|
180
|
-
/**
|
|
181
|
-
* In tailwind, the max-width of img/video is set to 100%,
|
|
182
|
-
* which will affect the amplification effect of the picture.
|
|
183
|
-
* So we need to set max-width to none.
|
|
184
|
-
*/
|
|
185
|
-
max-width: none;
|
|
186
188
|
}
|
|
187
189
|
.semi-image-preview-image-spin {
|
|
188
190
|
position: absolute;
|
package/lib/cjs/image/image.scss
CHANGED
|
@@ -10,6 +10,15 @@ $module: #{$prefix}-image;
|
|
|
10
10
|
display: inline-block;
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
|
|
13
|
+
img {
|
|
14
|
+
/**
|
|
15
|
+
* In tailwind, the max-width of img/video is set to 100%,
|
|
16
|
+
* which will affect the amplification effect of the picture.
|
|
17
|
+
* So we need to set max-width to none.
|
|
18
|
+
*/
|
|
19
|
+
max-width: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
&-img {
|
|
14
23
|
vertical-align: top;
|
|
15
24
|
border-radius: inherit;
|
|
@@ -204,12 +213,6 @@ $module: #{$prefix}-image;
|
|
|
204
213
|
// transition: transform $transition_duration-image_preview_image_img $transition_delay-image_preview_image_img;
|
|
205
214
|
z-index: 0;
|
|
206
215
|
user-select: none;
|
|
207
|
-
/**
|
|
208
|
-
* In tailwind, the max-width of img/video is set to 100%,
|
|
209
|
-
* which will affect the amplification effect of the picture.
|
|
210
|
-
* So we need to set max-width to none.
|
|
211
|
-
*/
|
|
212
|
-
max-width: none;
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
&-spin {
|
package/lib/cjs/tag/tag.scss
CHANGED
|
@@ -139,7 +139,7 @@ $types: "ghost", "solid", "light";
|
|
|
139
139
|
&-avatar-circle.#{$module}-small,
|
|
140
140
|
&-avatar-circle.#{$module}-default {
|
|
141
141
|
// when avatarShape=circle change tag border radius
|
|
142
|
-
border-radius: $height-tag_small * 0.5 +
|
|
142
|
+
border-radius: $height-tag_small * 0.5 + 1px;
|
|
143
143
|
|
|
144
144
|
.#{$prefix}-avatar {
|
|
145
145
|
width: $width-tag_avatar_circle_small;
|
|
@@ -148,7 +148,7 @@ $types: "ghost", "solid", "light";
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
&-avatar-circle.#{$module}-large {
|
|
151
|
-
border-radius: $height-tag_large * 0.5 +
|
|
151
|
+
border-radius: $height-tag_large * 0.5 + 1px;
|
|
152
152
|
|
|
153
153
|
.#{$prefix}-avatar {
|
|
154
154
|
width: $width-tag_avatar_circle_large;
|
|
@@ -272,10 +272,10 @@ $types: "ghost", "solid", "light";
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
&-max.#{$module}-group-small {
|
|
275
|
-
height: ($height-tag_small +
|
|
275
|
+
height: ($height-tag_small + 2px);
|
|
276
276
|
}
|
|
277
277
|
&-max.#{$module}-group-large {
|
|
278
|
-
height: ($height-tag_large +
|
|
278
|
+
height: ($height-tag_large + 2px);
|
|
279
279
|
}
|
|
280
280
|
// &-small {
|
|
281
281
|
// height: ($height-tag_small + 2);
|
|
@@ -43,9 +43,12 @@ export default function chatInputToChatCompletion(inputContent) {
|
|
|
43
43
|
}
|
|
44
44
|
return {
|
|
45
45
|
role: "user",
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
messages: [{
|
|
47
|
+
role: "user",
|
|
48
|
+
content: inputs
|
|
49
|
+
}],
|
|
50
|
+
model: setup === null || setup === void 0 ? void 0 : setup.model,
|
|
51
|
+
references,
|
|
52
|
+
setup: setup !== null && setup !== void 0 ? setup : {}
|
|
50
53
|
};
|
|
51
54
|
}
|
|
@@ -12,6 +12,7 @@ export interface AIChatInputAdapter<P = Record<string, any>, S = Record<string,
|
|
|
12
12
|
manualUpload: (files: File[]) => void;
|
|
13
13
|
notifyMessageSend: (props: MessageContent) => void;
|
|
14
14
|
notifyStopGenerate: () => void;
|
|
15
|
+
notifySkillChange: (skill: BaseSkill) => void;
|
|
15
16
|
clearContent: () => void;
|
|
16
17
|
clearAttachments: () => void;
|
|
17
18
|
getRichTextDiv: () => HTMLDivElement | null;
|
|
@@ -2,7 +2,7 @@ import _isString from "lodash/isString";
|
|
|
2
2
|
import _isNumber from "lodash/isNumber";
|
|
3
3
|
import BaseFoundation from '../base/foundation';
|
|
4
4
|
import { cssClasses } from './constants';
|
|
5
|
-
import { transformJSONResult } from './utils';
|
|
5
|
+
import { findSkillSlotInString, getSkillSlotString, transformJSONResult } from './utils';
|
|
6
6
|
const prefixCls = cssClasses.PREFIX;
|
|
7
7
|
export default class AIChatInputFoundation extends BaseFoundation {
|
|
8
8
|
constructor(adapter) {
|
|
@@ -17,7 +17,8 @@ export default class AIChatInputFoundation extends BaseFoundation {
|
|
|
17
17
|
skill: skill,
|
|
18
18
|
skillVisible: false
|
|
19
19
|
});
|
|
20
|
-
this._adapter.
|
|
20
|
+
this._adapter.notifySkillChange(skill);
|
|
21
|
+
this._adapter.setContent(getSkillSlotString(skill));
|
|
21
22
|
this._adapter.focusEditor();
|
|
22
23
|
};
|
|
23
24
|
this.changeTemplateVisible = value => {
|
|
@@ -163,16 +164,27 @@ export default class AIChatInputFoundation extends BaseFoundation {
|
|
|
163
164
|
skill
|
|
164
165
|
} = this.getStates();
|
|
165
166
|
const editor = this._adapter.getEditor();
|
|
166
|
-
const jsonResult = editor.getJSON();
|
|
167
|
-
const finalResult = transformJSONResult(jsonResult, transformer);
|
|
168
|
-
this._adapter.notifyContentChange(finalResult);
|
|
169
167
|
const html = editor.getHTML();
|
|
170
|
-
if (
|
|
168
|
+
if (skill && !html.includes('</skill-slot>')) {
|
|
171
169
|
this.setState({
|
|
172
|
-
skill:
|
|
170
|
+
skill: undefined,
|
|
173
171
|
templateVisible: false
|
|
174
172
|
});
|
|
173
|
+
this._adapter.notifySkillChange(undefined);
|
|
174
|
+
this._adapter.notifyContentChange([]);
|
|
175
|
+
return;
|
|
176
|
+
} else if (html.includes('</skill-slot>')) {
|
|
177
|
+
const newSkill = findSkillSlotInString(html);
|
|
178
|
+
if ((newSkill === null || newSkill === void 0 ? void 0 : newSkill.value) !== (skill === null || skill === void 0 ? void 0 : skill.value)) {
|
|
179
|
+
this.setState({
|
|
180
|
+
skill: newSkill
|
|
181
|
+
});
|
|
182
|
+
this._adapter.notifySkillChange(newSkill);
|
|
183
|
+
}
|
|
175
184
|
}
|
|
185
|
+
const jsonResult = editor.getJSON();
|
|
186
|
+
const finalResult = transformJSONResult(jsonResult, transformer);
|
|
187
|
+
this._adapter.notifyContentChange(finalResult);
|
|
176
188
|
this.setState({
|
|
177
189
|
content: jsonResult
|
|
178
190
|
});
|
|
@@ -238,7 +250,8 @@ export default class AIChatInputFoundation extends BaseFoundation {
|
|
|
238
250
|
this.handleSend = () => {
|
|
239
251
|
var _a, _b;
|
|
240
252
|
const {
|
|
241
|
-
generating
|
|
253
|
+
generating,
|
|
254
|
+
transformer
|
|
242
255
|
} = this.getProps();
|
|
243
256
|
if (generating) {
|
|
244
257
|
this._adapter.notifyStopGenerate();
|
|
@@ -255,7 +268,7 @@ export default class AIChatInputFoundation extends BaseFoundation {
|
|
|
255
268
|
let richTextResult = [];
|
|
256
269
|
if (editor) {
|
|
257
270
|
const json = (_a = editor.getJSON) === null || _a === void 0 ? void 0 : _a.call(editor);
|
|
258
|
-
richTextResult = transformJSONResult(json);
|
|
271
|
+
richTextResult = transformJSONResult(json, transformer);
|
|
259
272
|
}
|
|
260
273
|
// close popup layer for template/skill/suggestion
|
|
261
274
|
this.setState({
|
|
@@ -316,6 +329,29 @@ export default class AIChatInputFoundation extends BaseFoundation {
|
|
|
316
329
|
this.handleSend();
|
|
317
330
|
return true;
|
|
318
331
|
}
|
|
332
|
+
if (event.key === 'Enter' && event.shiftKey) {
|
|
333
|
+
/**
|
|
334
|
+
* Tiptap 默认情况下 Enter + Shift 时候是使用 <br /> 实现换行
|
|
335
|
+
* 为保证自定义的一些逻辑生效(比如零宽字符的插入),Enter + Shift 希望实现通过新建 p 标签的方式完成换行
|
|
336
|
+
* 此处拦截默认操作,使用新建 p 标签方式实现换行
|
|
337
|
+
* Tiptap, by default, uses <br /> to create a newline character when you press Enter + Shift.
|
|
338
|
+
* To ensure that some custom logic works (such as the insertion of zero-width characters),
|
|
339
|
+
* we want Enter + Shift to create a new p tag to initiate a line break.
|
|
340
|
+
* This section intercepts the default operation and uses a newly created `<p>` tag to achieve line breaks.
|
|
341
|
+
*/
|
|
342
|
+
event.preventDefault();
|
|
343
|
+
const editor = this._adapter.getEditor();
|
|
344
|
+
if (editor && editor.chain && editor.chain().splitBlock) {
|
|
345
|
+
editor.chain().focus().splitBlock().run();
|
|
346
|
+
} else if (editor && editor.view) {
|
|
347
|
+
const {
|
|
348
|
+
state,
|
|
349
|
+
view
|
|
350
|
+
} = editor;
|
|
351
|
+
view.dispatch(state.tr.split(state.selection.from));
|
|
352
|
+
}
|
|
353
|
+
return true;
|
|
354
|
+
}
|
|
319
355
|
if (event.key !== 'Backspace') return false;
|
|
320
356
|
return false;
|
|
321
357
|
};
|
|
@@ -4,10 +4,10 @@ export interface RichTextJSON {
|
|
|
4
4
|
[key: string]: any;
|
|
5
5
|
}
|
|
6
6
|
export interface BaseSkill {
|
|
7
|
-
icon
|
|
8
|
-
value
|
|
9
|
-
label
|
|
10
|
-
hasTemplate
|
|
7
|
+
icon?: any;
|
|
8
|
+
value?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
hasTemplate?: boolean;
|
|
11
11
|
[key: string]: any;
|
|
12
12
|
}
|
|
13
13
|
export type Suggestion = string[] | {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Attachment, Reference } from "./interface";
|
|
1
|
+
import { Attachment, BaseSkill, Reference } from "./interface";
|
|
2
2
|
export declare function getAttachmentType(item: Attachment | Reference): any;
|
|
3
3
|
export declare function isImageType(item: Attachment | Reference): any;
|
|
4
4
|
export declare function getContentType(type: string): string;
|
|
@@ -6,18 +6,27 @@ export declare function transformSelectSlot(obj: any): {
|
|
|
6
6
|
type: string;
|
|
7
7
|
text: any;
|
|
8
8
|
};
|
|
9
|
-
export declare function transformSkillSlot(obj: any):
|
|
9
|
+
export declare function transformSkillSlot(obj: any): {
|
|
10
|
+
[k: string]: any;
|
|
11
|
+
};
|
|
10
12
|
export declare function transformInputSlot(obj: any): {
|
|
11
13
|
type: string;
|
|
12
14
|
text: any;
|
|
13
15
|
};
|
|
14
|
-
export declare function transformText(obj: any):
|
|
15
|
-
|
|
16
|
+
export declare function transformText(obj: any): {
|
|
17
|
+
type: string;
|
|
18
|
+
text: any;
|
|
19
|
+
};
|
|
20
|
+
export declare const transformMap: Map<string, any>;
|
|
16
21
|
export declare function transformJSONResult(input: any, customTransformObj?: Map<string, (obj: any) => any>): any[];
|
|
17
22
|
export declare function getCustomSlotAttribute(): {
|
|
18
23
|
default: boolean;
|
|
19
24
|
parseHTML: (element: any) => boolean;
|
|
20
25
|
renderHTML: (attributes: any) => {
|
|
21
|
-
'data-custom-slot':
|
|
26
|
+
'data-custom-slot': boolean;
|
|
22
27
|
};
|
|
23
28
|
};
|
|
29
|
+
export declare function findSkillSlotInString(content: string): {
|
|
30
|
+
[k: string]: any;
|
|
31
|
+
};
|
|
32
|
+
export declare function getSkillSlotString(skill: BaseSkill): string;
|
|
@@ -54,19 +54,21 @@ export function transformSelectSlot(obj) {
|
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
56
|
export function transformSkillSlot(obj) {
|
|
57
|
-
var _a;
|
|
58
57
|
const {
|
|
59
58
|
type,
|
|
60
59
|
attrs
|
|
61
60
|
} = obj;
|
|
62
61
|
const {
|
|
63
62
|
value,
|
|
64
|
-
|
|
63
|
+
label,
|
|
64
|
+
hasTemplate
|
|
65
65
|
} = attrs;
|
|
66
|
-
return
|
|
66
|
+
return omitUndefinedFromObj({
|
|
67
67
|
type,
|
|
68
|
-
value
|
|
69
|
-
|
|
68
|
+
value,
|
|
69
|
+
label,
|
|
70
|
+
hasTemplate
|
|
71
|
+
});
|
|
70
72
|
}
|
|
71
73
|
export function transformInputSlot(obj) {
|
|
72
74
|
var _a, _b;
|
|
@@ -81,9 +83,15 @@ export function transformInputSlot(obj) {
|
|
|
81
83
|
};
|
|
82
84
|
}
|
|
83
85
|
export function transformText(obj) {
|
|
84
|
-
|
|
86
|
+
const {
|
|
87
|
+
text
|
|
88
|
+
} = obj;
|
|
89
|
+
return {
|
|
90
|
+
type: 'text',
|
|
91
|
+
text: text !== strings.ZERO_WIDTH_CHAR ? text : ''
|
|
92
|
+
};
|
|
85
93
|
}
|
|
86
|
-
export const transformMap = new Map([['text', transformText], ['selectSlot', transformSelectSlot], ['inputSlot', transformInputSlot], ['
|
|
94
|
+
export const transformMap = new Map([['text', transformText], ['selectSlot', transformSelectSlot], ['inputSlot', transformInputSlot], ['skillSlot', transformSkillSlot]]);
|
|
87
95
|
export function transformJSONResult(input) {
|
|
88
96
|
let customTransformObj = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Map();
|
|
89
97
|
const output = [];
|
|
@@ -126,6 +134,10 @@ export function transformJSONResult(input) {
|
|
|
126
134
|
const lastItem = output[output.length - 1];
|
|
127
135
|
if (lastItem && lastItem.type === 'text') {
|
|
128
136
|
lastItem.text += result.text;
|
|
137
|
+
} else if (typeof result.text === 'string') {
|
|
138
|
+
// 如果 result.text 为空字符串(比如text 节点中只有单个的零宽字符),则无需作为 output 结果
|
|
139
|
+
// if result.text is an empty string,then it does not need to be included in output result.
|
|
140
|
+
result.text.length && output.push(result);
|
|
129
141
|
} else {
|
|
130
142
|
output.push(result);
|
|
131
143
|
}
|
|
@@ -142,7 +154,42 @@ export function getCustomSlotAttribute() {
|
|
|
142
154
|
default: true,
|
|
143
155
|
parseHTML: element => true,
|
|
144
156
|
renderHTML: attributes => ({
|
|
145
|
-
'data-custom-slot': attributes.isCustomSlot ?
|
|
157
|
+
'data-custom-slot': attributes.isCustomSlot ? true : undefined
|
|
146
158
|
})
|
|
147
159
|
};
|
|
160
|
+
}
|
|
161
|
+
export function findSkillSlotInString(content) {
|
|
162
|
+
const reg = /<skill-slot\s+([^>]*)><\/skill-slot>/i;
|
|
163
|
+
const attrReg = /([\w-]+)=["']?([^"'\s>]+)["']?/g;
|
|
164
|
+
const match = reg.exec(content);
|
|
165
|
+
if (match) {
|
|
166
|
+
const attrsStr = match[1];
|
|
167
|
+
let attrMatch;
|
|
168
|
+
let attrs = {};
|
|
169
|
+
while ((attrMatch = attrReg.exec(attrsStr)) !== null) {
|
|
170
|
+
attrs[attrMatch[1]] = attrMatch[2];
|
|
171
|
+
}
|
|
172
|
+
if (attrs['data-value']) {
|
|
173
|
+
const obj = {
|
|
174
|
+
label: attrs['data-label'],
|
|
175
|
+
value: attrs['data-value'],
|
|
176
|
+
hasTemplate: attrs['data-template'] ? attrs['data-template'] === 'true' : undefined
|
|
177
|
+
};
|
|
178
|
+
return omitUndefinedFromObj(obj);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
function omitUndefinedFromObj(obj) {
|
|
184
|
+
return Object.fromEntries(Object.entries(obj).filter(_ref => {
|
|
185
|
+
let [key, value] = _ref;
|
|
186
|
+
return value !== undefined;
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
189
|
+
export function getSkillSlotString(skill) {
|
|
190
|
+
let skillParams = '';
|
|
191
|
+
skill.label && (skillParams += ` data-label=${skill.label}`);
|
|
192
|
+
skill.value && (skillParams += ` data-value=${skill.value}`);
|
|
193
|
+
typeof skill.hasTemplate === 'boolean' && (skillParams += ` data-template=${skill.hasTemplate}`);
|
|
194
|
+
return `<skill-slot ${skillParams}"></skill-slot>`;
|
|
148
195
|
}
|
|
@@ -64,6 +64,7 @@ export default class ChatFoundation<P = Record<string, any>, S = Record<string,
|
|
|
64
64
|
scrollToBottomWithAnimation: () => void;
|
|
65
65
|
containerScroll: (e: any) => void;
|
|
66
66
|
getScroll: import("lodash").DebouncedFunc<(target: any) => typeof scroll>;
|
|
67
|
+
handleScrollContainerResize: () => void;
|
|
67
68
|
clearContext: (e: any) => void;
|
|
68
69
|
onMessageSend: (input: string, attachment: any[]) => void;
|
|
69
70
|
onHintClick: (hint: string) => void;
|
|
@@ -6,6 +6,11 @@ $half_corner_width: calc($width-cropper_box_corner / 2);
|
|
|
6
6
|
.#{$module} {
|
|
7
7
|
position: relative;
|
|
8
8
|
|
|
9
|
+
& img {
|
|
10
|
+
// To avoid the `max-Width` setting of `img` to 100% in `tailwindCSS` affecting the style of img in Cropper.
|
|
11
|
+
max-width: none;
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
&-img {
|
|
10
15
|
position: absolute;
|
|
11
16
|
user-select: none;
|
package/lib/es/image/image.css
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
display: inline-block;
|
|
8
8
|
overflow: hidden;
|
|
9
9
|
}
|
|
10
|
+
.semi-image img {
|
|
11
|
+
/**
|
|
12
|
+
* In tailwind, the max-width of img/video is set to 100%,
|
|
13
|
+
* which will affect the amplification effect of the picture.
|
|
14
|
+
* So we need to set max-width to none.
|
|
15
|
+
*/
|
|
16
|
+
max-width: none;
|
|
17
|
+
}
|
|
10
18
|
.semi-image-img {
|
|
11
19
|
vertical-align: top;
|
|
12
20
|
border-radius: inherit;
|
|
@@ -177,12 +185,6 @@
|
|
|
177
185
|
transform: scale3d(1, 1, 1) var(--semi-transform-rotate-none);
|
|
178
186
|
z-index: 0;
|
|
179
187
|
user-select: none;
|
|
180
|
-
/**
|
|
181
|
-
* In tailwind, the max-width of img/video is set to 100%,
|
|
182
|
-
* which will affect the amplification effect of the picture.
|
|
183
|
-
* So we need to set max-width to none.
|
|
184
|
-
*/
|
|
185
|
-
max-width: none;
|
|
186
188
|
}
|
|
187
189
|
.semi-image-preview-image-spin {
|
|
188
190
|
position: absolute;
|
package/lib/es/image/image.scss
CHANGED
|
@@ -10,6 +10,15 @@ $module: #{$prefix}-image;
|
|
|
10
10
|
display: inline-block;
|
|
11
11
|
overflow: hidden;
|
|
12
12
|
|
|
13
|
+
img {
|
|
14
|
+
/**
|
|
15
|
+
* In tailwind, the max-width of img/video is set to 100%,
|
|
16
|
+
* which will affect the amplification effect of the picture.
|
|
17
|
+
* So we need to set max-width to none.
|
|
18
|
+
*/
|
|
19
|
+
max-width: none;
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
&-img {
|
|
14
23
|
vertical-align: top;
|
|
15
24
|
border-radius: inherit;
|
|
@@ -204,12 +213,6 @@ $module: #{$prefix}-image;
|
|
|
204
213
|
// transition: transform $transition_duration-image_preview_image_img $transition_delay-image_preview_image_img;
|
|
205
214
|
z-index: 0;
|
|
206
215
|
user-select: none;
|
|
207
|
-
/**
|
|
208
|
-
* In tailwind, the max-width of img/video is set to 100%,
|
|
209
|
-
* which will affect the amplification effect of the picture.
|
|
210
|
-
* So we need to set max-width to none.
|
|
211
|
-
*/
|
|
212
|
-
max-width: none;
|
|
213
216
|
}
|
|
214
217
|
|
|
215
218
|
&-spin {
|
package/lib/es/tag/tag.scss
CHANGED
|
@@ -139,7 +139,7 @@ $types: "ghost", "solid", "light";
|
|
|
139
139
|
&-avatar-circle.#{$module}-small,
|
|
140
140
|
&-avatar-circle.#{$module}-default {
|
|
141
141
|
// when avatarShape=circle change tag border radius
|
|
142
|
-
border-radius: $height-tag_small * 0.5 +
|
|
142
|
+
border-radius: $height-tag_small * 0.5 + 1px;
|
|
143
143
|
|
|
144
144
|
.#{$prefix}-avatar {
|
|
145
145
|
width: $width-tag_avatar_circle_small;
|
|
@@ -148,7 +148,7 @@ $types: "ghost", "solid", "light";
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
&-avatar-circle.#{$module}-large {
|
|
151
|
-
border-radius: $height-tag_large * 0.5 +
|
|
151
|
+
border-radius: $height-tag_large * 0.5 + 1px;
|
|
152
152
|
|
|
153
153
|
.#{$prefix}-avatar {
|
|
154
154
|
width: $width-tag_avatar_circle_large;
|
|
@@ -272,10 +272,10 @@ $types: "ghost", "solid", "light";
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
&-max.#{$module}-group-small {
|
|
275
|
-
height: ($height-tag_small +
|
|
275
|
+
height: ($height-tag_small + 2px);
|
|
276
276
|
}
|
|
277
277
|
&-max.#{$module}-group-large {
|
|
278
|
-
height: ($height-tag_large +
|
|
278
|
+
height: ($height-tag_large + 2px);
|
|
279
279
|
}
|
|
280
280
|
// &-small {
|
|
281
281
|
// height: ($height-tag_small + 2);
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@douyinfe/semi-foundation",
|
|
3
|
-
"version": "2.88.0
|
|
3
|
+
"version": "2.88.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build:lib": "node ./scripts/compileLib.js",
|
|
7
7
|
"prepublishOnly": "npm run build:lib"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@douyinfe/semi-animation": "2.88.0
|
|
11
|
-
"@douyinfe/semi-json-viewer-core": "2.88.0
|
|
10
|
+
"@douyinfe/semi-animation": "2.88.0",
|
|
11
|
+
"@douyinfe/semi-json-viewer-core": "2.88.0",
|
|
12
12
|
"@mdx-js/mdx": "^3.0.1",
|
|
13
13
|
"async-validator": "^3.5.0",
|
|
14
14
|
"classnames": "^2.2.6",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"*.scss",
|
|
30
30
|
"*.css"
|
|
31
31
|
],
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "dd7950d62f3dd702ea384d2df21baafd5912bbd6",
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@babel/plugin-transform-runtime": "^7.15.8",
|
|
35
35
|
"@babel/preset-env": "^7.15.8",
|
package/tag/tag.scss
CHANGED
|
@@ -139,7 +139,7 @@ $types: "ghost", "solid", "light";
|
|
|
139
139
|
&-avatar-circle.#{$module}-small,
|
|
140
140
|
&-avatar-circle.#{$module}-default {
|
|
141
141
|
// when avatarShape=circle change tag border radius
|
|
142
|
-
border-radius: $height-tag_small * 0.5 +
|
|
142
|
+
border-radius: $height-tag_small * 0.5 + 1px;
|
|
143
143
|
|
|
144
144
|
.#{$prefix}-avatar {
|
|
145
145
|
width: $width-tag_avatar_circle_small;
|
|
@@ -148,7 +148,7 @@ $types: "ghost", "solid", "light";
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
&-avatar-circle.#{$module}-large {
|
|
151
|
-
border-radius: $height-tag_large * 0.5 +
|
|
151
|
+
border-radius: $height-tag_large * 0.5 + 1px;
|
|
152
152
|
|
|
153
153
|
.#{$prefix}-avatar {
|
|
154
154
|
width: $width-tag_avatar_circle_large;
|
|
@@ -272,10 +272,10 @@ $types: "ghost", "solid", "light";
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
&-max.#{$module}-group-small {
|
|
275
|
-
height: ($height-tag_small +
|
|
275
|
+
height: ($height-tag_small + 2px);
|
|
276
276
|
}
|
|
277
277
|
&-max.#{$module}-group-large {
|
|
278
|
-
height: ($height-tag_large +
|
|
278
|
+
height: ($height-tag_large + 2px);
|
|
279
279
|
}
|
|
280
280
|
// &-small {
|
|
281
281
|
// height: ($height-tag_small + 2);
|