浏览代码

fix: [Chat] Changes made to accommodate other frameworks (#2383)

* fix: [Chat] Changes made to accommodate other frameworks, such as vue

* fix: Use arrow functions to prevent this object errors

---------

Co-authored-by: zhangyumei.0319 <[email protected]>
rashagu 1 年之前
父节点
当前提交
535ae11042
共有 2 个文件被更改,包括 46 次插入44 次删除
  1. 18 23
      packages/semi-foundation/chat/foundation.ts
  2. 28 21
      packages/semi-ui/chat/index.tsx

+ 18 - 23
packages/semi-foundation/chat/foundation.ts

@@ -5,14 +5,14 @@ import { debounce } from "lodash";
 import { getUuidv4 } from "../utils/uuid";
 import { handlePrevent } from "../utils/a11y";
 
-const { PIC_PREFIX, PIC_SUFFIX_ARRAY, ROLE, 
+const { PIC_PREFIX, PIC_SUFFIX_ARRAY, ROLE,
     SCROLL_ANIMATION_TIME, SHOW_SCROLL_GAP
 } = strings;
 
 export interface Content {
     type: 'text' | 'image_url' | 'file_url';
     text?: string;
-    image_url?: { 
+    image_url?: {
         url: string;
         [x: string]: any
     };
@@ -37,7 +37,7 @@ export interface Message {
 }
 
 export interface ChatAdapter<P = Record<string, any>, S = Record<string, any>> extends DefaultAdapter<P, S> {
-    getContainerRef: () => React.RefObject<HTMLDivElement>;
+    getContainerRef: () => HTMLDivElement;
     setWheelScroll: (flag: boolean) => void;
     notifyChatsChange: (chats: Message[]) => void;
     notifyLikeMessage: (message: Message) => void;
@@ -80,17 +80,15 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
     }
 
     scrollToBottomImmediately = () => {
-        const containerRef = this._adapter.getContainerRef();
-        const element = containerRef?.current;
+        const element = this._adapter.getContainerRef();
         if (element) {
             element.scrollTop = element.scrollHeight;
-        } 
+        }
     }
 
     scrollToBottomWithAnimation = () => {
         const duration = SCROLL_ANIMATION_TIME;
-        const containerRef = this._adapter.getContainerRef();
-        const element = containerRef?.current;
+        const element = this._adapter.getContainerRef();
         if (!element) {
             return;
         }
@@ -106,18 +104,15 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
                 easing: 'easeInOutCubic'
             }
         );
-    
+
         this.animation.on('frame', ({ scrollTop }: { scrollTop: number }) => {
             element.scrollTop = scrollTop;
         });
-    
+
         this.animation.start();
     }
 
     containerScroll = (e: any) => {
-        if (e.target !== e.currentTarget) {
-            return;
-        }
         e.persist();
         const update = () => {
             this.getScroll(e.target);
@@ -155,7 +150,7 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
         const newChats = [...chats, dividerMessage];
         this._adapter.notifyChatsChange(newChats);
         this._adapter.notifyClearContext();
-    } 
+    }
 
     onMessageSend = (input: string, attachment: any[]) => {
         let content;
@@ -169,13 +164,13 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
                 const suffix = name.split('.').pop();
                 const isImg = fileInstance?.type?.startsWith(PIC_PREFIX) || PIC_SUFFIX_ARRAY.includes(suffix);
                 if (isImg) {
-                    content.push({ 
-                        type: 'image_url', 
-                        image_url: { url: url } 
+                    content.push({
+                        type: 'image_url',
+                        image_url: { url: url }
                     });
                 } else {
-                    content.push({ 
-                        type: 'file_url', 
+                    content.push({
+                        type: 'file_url',
                         file_url: {
                             url: url,
                             name: name,
@@ -238,7 +233,7 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
         newChats.splice(index, 1, newChat);
         this._adapter.notifyChatsChange(newChats);
     }
-  
+
     dislikeMessage = (message: Message) => {
         const { chats } = this.getStates();
         this._adapter.notifyDislikeMessage(message);
@@ -252,7 +247,7 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
         newChats.splice(index, 1, newChat);
         this._adapter.notifyChatsChange(newChats);
     }
-  
+
     resetMessage = (message: Message) => {
         const { chats } = this.getStates();
         const lastMessage = chats[chats.length - 1];
@@ -284,7 +279,7 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
         //Disable the default implementation, preventing files from being opened
         handlePrevent(e);
     }
-    
+
     handleContainerDragLeave = (e: any) => {
         handlePrevent(e);
         // 鼠标移动至 container 的子元素,则不做任何操作
@@ -295,7 +290,7 @@ export default class ChatFoundation <P = Record<string, any>, S = Record<string,
         }
         /**
          * 延迟隐藏 container ,防止父元素的 mouseOver 被触发,导致 container 无法隐藏
-         * Delay hiding of the container to prevent the parent element's mouseOver from being triggered, 
+         * Delay hiding of the container to prevent the parent element's mouseOver from being triggered,
          * causing the container to be unable to be hidden.
         */
         setTimeout(() => {

+ 28 - 21
packages/semi-ui/chat/index.tsx

@@ -22,7 +22,7 @@ const { CHAT_ALIGN, MODE, SEND_HOT_KEY } = strings;
 class Chat extends BaseComponent<ChatProps, ChatState> {
 
     static __SemiComponentName__ = "Chat";
-  
+
     containerRef: React.RefObject<HTMLDivElement>;
     animation: any;
     wheelEventHandler: any;
@@ -93,7 +93,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
     get adapter(): ChatAdapter {
         return {
             ...super.adapter,
-            getContainerRef: () => this.containerRef,
+            getContainerRef: () => this.containerRef?.current,
             setWheelScroll: (flag: boolean) => {
                 this.setState({
                     wheelScroll: flag,
@@ -150,7 +150,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
                     this.adapter.setWheelScroll(true);
                     this.adapter.unRegisterWheelEvent();
                 };
-        
+
                 containerElement.addEventListener('wheel', this.wheelEventHandler);
             },
             unRegisterWheelEvent: () => {
@@ -183,7 +183,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
             },
             getDropAreaElement: () => {
                 return this.dropAreaRef?.current;
-            } 
+            }
         };
     }
 
@@ -203,7 +203,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
     }
 
     componentDidMount(): void {
-        this.foundation.init();    
+        this.foundation.init();
     }
 
     componentDidUpdate(prevProps: Readonly<ChatProps>, prevState: Readonly<ChatState>, snapshot?: any): void {
@@ -241,15 +241,15 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
         this.foundation.destroy();
     }
 
-    resetMessage() {
+    resetMessage = () => {
         this.foundation.resetMessage(null);
     }
 
-    clearContext() {
+    clearContext = () => {
         this.foundation.clearContext(null);
     }
 
-    scrollToBottom(animation: boolean) {
+    scrollToBottom = (animation: boolean) => {
         if (animation) {
             this.foundation.scrollToBottomWithAnimation();
         } else {
@@ -257,10 +257,17 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
         }
     }
 
-    sendMessage(content: string, attachment: FileItem[]) {
+    sendMessage = (content: string, attachment: FileItem[]) => {
         this.foundation.onMessageSend(content, attachment);
     }
 
+    containerScroll = (e: React.UIEvent<HTMLDivElement>) => {
+        if (e.target !== e.currentTarget) {
+            return;
+        }
+        this.foundation.containerScroll(e);
+    }
+
     render() {
         const { topSlot, bottomSlot, roleConfig, hints,
             onChatsChange, onMessageCopy, renderInputArea,
@@ -282,12 +289,12 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
         }
         return (
             <div
-                className={cls(`${prefixCls}`, className)} 
+                className={cls(`${prefixCls}`, className)}
                 style={style}
                 onDragOver={this.foundation.handleDragOver}
             >
                 {uploadAreaVisible && <div
-                    ref={this.dropAreaRef} 
+                    ref={this.dropAreaRef}
                     className={`${prefixCls}-dropArea`}
                     onDragOver={this.foundation.handleContainerDragOver}
                     onDrop={this.foundation.handleContainerDrop}
@@ -297,24 +304,24 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
                         <LocaleConsumer<Locale["Chat"]> componentName="Chat" >
                             {(locale: Locale["Chat"]) => locale['dropAreaText']}
                         </LocaleConsumer>
-                    </span>  
+                    </span>
                 </div>}
                 <div className={`${prefixCls}-inner`}>
                     {/* top slot */}
                     {topSlot}
                     {/* chat area */}
                     <div className={`${prefixCls}-content`}>
-                        <div 
+                        <div
                             className={cls(`${prefixCls}-container`, {
                                 'semi-chat-container-scroll-hidden': !wheelScroll
                             })}
-                            onScroll={this.foundation.containerScroll}
+                            onScroll={this.containerScroll}
                             ref={this.containerRef}
                         >
-                            <ChatContent 
+                            <ChatContent
                                 align={align}
                                 mode={mode}
-                                chats={chats}  
+                                chats={chats}
                                 roleConfig={roleConfig}
                                 customMarkDownComponents={customMarkDownComponents}
                                 onMessageDelete={this.foundation.deleteMessage}
@@ -326,10 +333,10 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
                                 chatBoxRenderConfig={chatBoxRenderConfig}
                             />
                             {/* hint area */}
-                            {!!hints?.length && <Hint 
+                            {!!hints?.length && <Hint
                                 className={hintCls}
                                 style={hintStyle}
-                                value={hints} 
+                                value={hints}
                                 onHintClick={this.foundation.onHintClick}
                                 renderHintBox={renderHintBox}
                             />}
@@ -337,7 +344,7 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
                     </div>
                     {backBottomVisible && !showStopGenerateFlag && (<span className={`${prefixCls}-action`}>
                         <Button
-                            className={`${prefixCls}-action-content ${prefixCls}-action-backBottom`} 
+                            className={`${prefixCls}-action-content ${prefixCls}-action-backBottom`}
                             icon={<IconChevronDown size="extra-large"/>}
                             type="tertiary"
                             onClick={this.foundation.scrollToBottomWithAnimation}
@@ -345,10 +352,10 @@ class Chat extends BaseComponent<ChatProps, ChatState> {
                     </span>)}
                     {showStopGenerateFlag && (<span className={`${prefixCls}-action`}>
                         <Button
-                            className={`${prefixCls}-action-content ${prefixCls}-action-stop`} 
+                            className={`${prefixCls}-action-content ${prefixCls}-action-stop`}
                             icon={<IconDisc size="extra-large" />}
                             type="tertiary"
-                            onClick={this.foundation.stopGenerate} 
+                            onClick={this.foundation.stopGenerate}
                         >
                             <LocaleConsumer<Locale["Chat"]> componentName="Chat" >
                                 {(locale: Locale["Chat"]) => locale['stop']}