You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tailchat/web/src/components/ChatBox/ChatInputBox/index.tsx

84 lines
2.6 KiB
TypeScript

import { closeModal, openModal } from '@/components/Modal';
import { ImageUploadPreviewer } from '@/components/modals/ImageUploadPreviewer';
import { fileToDataUrl } from '@/utils/file-helper';
import { isEnterHotkey } from '@/utils/hot-key';
import { Input } from 'antd';
import React, { useCallback, useRef, useState } from 'react';
import { t, uploadFile } from 'tailchat-shared';
import { ChatInputAddon } from './Addon';
import { ClipboardHelper } from './clipboard-helper';
import { ChatInputActionContext } from './context';
interface ChatInputBoxProps {
onSendMsg: (msg: string) => void;
}
export const ChatInputBox: React.FC<ChatInputBoxProps> = React.memo((props) => {
const inputRef = useRef<Input>(null);
const [message, setMessage] = useState('');
const handleSendMsg = useCallback(() => {
props.onSendMsg(message);
setMessage('');
inputRef.current?.focus();
}, [message]);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (isEnterHotkey(e.nativeEvent)) {
e.preventDefault();
handleSendMsg();
}
},
[handleSendMsg]
);
const handlePaste = useCallback(
(e: React.ClipboardEvent<HTMLDivElement>) => {
const helper = new ClipboardHelper(e);
const image = helper.hasImage();
if (image) {
// 上传图片
e.preventDefault();
fileToDataUrl(image).then((imageLocalUrl) => {
const key = openModal(
<ImageUploadPreviewer
imageUrl={imageLocalUrl}
onConfirm={async () => {
const fileInfo = await uploadFile(image);
const imageRemoteUrl = fileInfo.url;
// TODO: not good
props.onSendMsg(`[img]${imageRemoteUrl}[/img]`);
closeModal(key);
}}
/>
);
});
}
},
[props.onSendMsg]
);
return (
<ChatInputActionContext.Provider value={{ sendMsg: props.onSendMsg }}>
<div className="px-4 py-2">
<div className="bg-white dark:bg-gray-600 flex rounded-md items-center">
<Input
ref={inputRef}
className="outline-none shadow-none border-0 py-2.5 px-4 flex-1"
placeholder={t('输入一些什么')}
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
onPaste={handlePaste}
/>
<div className="px-2">
<ChatInputAddon />
</div>
</div>
</div>
</ChatInputActionContext.Provider>
);
});
ChatInputBox.displayName = 'ChatInputBox';