@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.
Files changed (35) hide show
  1. package/aiChatDialogue/dataAdapter/chatInputToChatCompletion.ts +7 -4
  2. package/aiChatInput/foundation.ts +40 -9
  3. package/aiChatInput/interface.ts +4 -4
  4. package/aiChatInput/utils.ts +53 -11
  5. package/chat/foundation.ts +4 -0
  6. package/cropper/cropper.scss +5 -0
  7. package/image/image.scss +9 -6
  8. package/lib/cjs/aiChatDialogue/dataAdapter/chatInputToChatCompletion.js +7 -4
  9. package/lib/cjs/aiChatInput/foundation.d.ts +1 -0
  10. package/lib/cjs/aiChatInput/foundation.js +44 -8
  11. package/lib/cjs/aiChatInput/interface.d.ts +4 -4
  12. package/lib/cjs/aiChatInput/utils.d.ts +14 -5
  13. package/lib/cjs/aiChatInput/utils.js +57 -8
  14. package/lib/cjs/chat/foundation.d.ts +1 -0
  15. package/lib/cjs/chat/foundation.js +3 -0
  16. package/lib/cjs/cropper/cropper.css +3 -0
  17. package/lib/cjs/cropper/cropper.scss +5 -0
  18. package/lib/cjs/image/image.css +8 -6
  19. package/lib/cjs/image/image.scss +9 -6
  20. package/lib/cjs/tag/tag.scss +4 -4
  21. package/lib/es/aiChatDialogue/dataAdapter/chatInputToChatCompletion.js +7 -4
  22. package/lib/es/aiChatInput/foundation.d.ts +1 -0
  23. package/lib/es/aiChatInput/foundation.js +45 -9
  24. package/lib/es/aiChatInput/interface.d.ts +4 -4
  25. package/lib/es/aiChatInput/utils.d.ts +14 -5
  26. package/lib/es/aiChatInput/utils.js +55 -8
  27. package/lib/es/chat/foundation.d.ts +1 -0
  28. package/lib/es/chat/foundation.js +3 -0
  29. package/lib/es/cropper/cropper.css +3 -0
  30. package/lib/es/cropper/cropper.scss +5 -0
  31. package/lib/es/image/image.css +8 -6
  32. package/lib/es/image/image.scss +9 -6
  33. package/lib/es/tag/tag.scss +4 -4
  34. package/package.json +4 -4
  35. 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
- content: inputs,
43
- // createdAt: created_at, // todo: 产生消息时给 createdat 还是发送时?
44
- // model: model, // todo: inputContent 中未包含 model 信息
45
- references
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.setContent(`<skill-slot data-value="${skill.label}"></skill-slot>`);
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 (content === '' && Object.keys(skill).length && !html.includes('</skill-slot>')) {
205
+ if (skill && !html.includes('</skill-slot>')) {
207
206
  this.setState({
208
- skill: {} as BaseSkill,
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
  }
@@ -6,10 +6,10 @@ export interface RichTextJSON {
6
6
  }
7
7
 
8
8
  export interface BaseSkill {
9
- icon: any;
10
- value: string;
11
- label: string;
12
- hasTemplate: boolean;
9
+ icon?: any;
10
+ value?: string;
11
+ label?: string;
12
+ hasTemplate?: boolean;
13
13
  [key: string]: any
14
14
  }
15
15
 
@@ -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, info } = attrs;
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
- return { ...obj };
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
- ['toolSlot', transformSkillSlot],
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 ? 'true' : undefined,
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
  }
@@ -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) {
@@ -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
- content: inputs,
53
- // createdAt: created_at, // todo: 产生消息时给 createdat 还是发送时?
54
- // model: model, // todo: inputContent 中未包含 model 信息
55
- references
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.setContent(`<skill-slot data-value="${skill.label}"></skill-slot>`);
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 (content === '' && Object.keys(skill).length && !html.includes('</skill-slot>')) {
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: any;
8
- value: string;
9
- label: string;
10
- hasTemplate: boolean;
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): 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): any;
15
- export declare const transformMap: Map<string, typeof transformText>;
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': string;
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
- info
80
+ label,
81
+ hasTemplate
80
82
  } = attrs;
81
- return Object.assign({
83
+ return omitUndefinedFromObj({
82
84
  type,
83
- value
84
- }, (_a = JSON.parse(info)) !== null && _a !== void 0 ? _a : {});
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
- return Object.assign({}, obj);
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], ['toolSlot', transformSkillSlot]]);
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 ? 'true' : undefined
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;
@@ -90,6 +90,9 @@ class ChatFoundation extends _foundation.default {
90
90
  }
91
91
  return scroll;
92
92
  }, 100);
93
+ this.handleScrollContainerResize = () => {
94
+ this.getScroll(this._adapter.getContainerRef());
95
+ };
93
96
  this.clearContext = e => {
94
97
  const {
95
98
  chats
@@ -4,6 +4,9 @@
4
4
  .semi-cropper {
5
5
  position: relative;
6
6
  }
7
+ .semi-cropper img {
8
+ max-width: none;
9
+ }
7
10
  .semi-cropper-img {
8
11
  position: absolute;
9
12
  user-select: none;
@@ -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;
@@ -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;
@@ -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 {
@@ -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 + 1;
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 + 1;
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 + 2);
275
+ height: ($height-tag_small + 2px);
276
276
  }
277
277
  &-max.#{$module}-group-large {
278
- height: ($height-tag_large + 2);
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
- content: inputs,
47
- // createdAt: created_at, // todo: 产生消息时给 createdat 还是发送时?
48
- // model: model, // todo: inputContent 中未包含 model 信息
49
- references
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.setContent(`<skill-slot data-value="${skill.label}"></skill-slot>`);
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 (content === '' && Object.keys(skill).length && !html.includes('</skill-slot>')) {
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: any;
8
- value: string;
9
- label: string;
10
- hasTemplate: boolean;
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): 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): any;
15
- export declare const transformMap: Map<string, typeof transformText>;
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': string;
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
- info
63
+ label,
64
+ hasTemplate
65
65
  } = attrs;
66
- return Object.assign({
66
+ return omitUndefinedFromObj({
67
67
  type,
68
- value
69
- }, (_a = JSON.parse(info)) !== null && _a !== void 0 ? _a : {});
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
- return Object.assign({}, obj);
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], ['toolSlot', transformSkillSlot]]);
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 ? 'true' : undefined
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;
@@ -83,6 +83,9 @@ export default class ChatFoundation extends BaseFoundation {
83
83
  }
84
84
  return scroll;
85
85
  }, 100);
86
+ this.handleScrollContainerResize = () => {
87
+ this.getScroll(this._adapter.getContainerRef());
88
+ };
86
89
  this.clearContext = e => {
87
90
  const {
88
91
  chats
@@ -4,6 +4,9 @@
4
4
  .semi-cropper {
5
5
  position: relative;
6
6
  }
7
+ .semi-cropper img {
8
+ max-width: none;
9
+ }
7
10
  .semi-cropper-img {
8
11
  position: absolute;
9
12
  user-select: none;
@@ -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;
@@ -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;
@@ -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 {
@@ -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 + 1;
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 + 1;
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 + 2);
275
+ height: ($height-tag_small + 2px);
276
276
  }
277
277
  &-max.#{$module}-group-large {
278
- height: ($height-tag_large + 2);
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-beta.1",
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-beta.1",
11
- "@douyinfe/semi-json-viewer-core": "2.88.0-beta.1",
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": "535d287af36ed4082c64fe4e8c65f7f2df316dad",
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 + 1;
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 + 1;
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 + 2);
275
+ height: ($height-tag_small + 2px);
276
276
  }
277
277
  &-max.#{$module}-group-large {
278
- height: ($height-tag_large + 2);
278
+ height: ($height-tag_large + 2px);
279
279
  }
280
280
  // &-small {
281
281
  // height: ($height-tag_small + 2);