import { Button } from '@heroui/button'; import type { Range } from 'quill'; import 'quill/dist/quill.core.css'; import { useRef } from 'react'; import toast from 'react-hot-toast'; import { useCustomQuill } from '@/hooks/use_custom_quill'; import useShowStructuredMessage from '@/hooks/use_show_strcuted_message'; import { quillToMessage } from '@/utils/onebot'; import type { OB11Segment } from '@/types/onebot'; import AudioInsert from './components/audio_insert'; import DiceInsert from './components/dice_insert'; import EmojiPicker from './components/emoji_picker'; import FileInsert from './components/file_insert'; import ImageInsert from './components/image_insert'; import MusicInsert from './components/music_insert'; import ReplyInsert from './components/reply_insert'; import RPSInsert from './components/rps_insert'; import VideoInsert from './components/video_insert'; import EmojiBlot from './formats/emoji_blot'; import type { EmojiValue } from './formats/emoji_blot'; import ImageBlot from './formats/image_blot'; import ReplyBlock from './formats/reply_blot'; const ChatInput = () => { const memorizedRange = useRef(null); const showStructuredMessage = useShowStructuredMessage(); const formats: string[] = ['image', 'emoji', 'reply']; const modules = { toolbar: '#toolbar', }; const { quillRef, quill, Quill } = useCustomQuill({ modules, formats, placeholder: '请输入消息', }); if (Quill && !quill) { Quill.register('formats/emoji', EmojiBlot); Quill.register('formats/image', ImageBlot, true); Quill.register('formats/reply', ReplyBlock); } if (quill) { quill.on('selection-change', (range) => { if (range) { const editorContent = quill.getContents(); const firstOp = editorContent.ops[0]; if ( typeof firstOp?.insert !== 'string' && firstOp?.insert?.reply && range.index === 0 && range.length !== quill.getLength() ) { quill.setSelection(1, Quill.sources.SILENT); } } }); quill.on('text-change', () => { const editorContent = quill.getContents(); const firstOp = editorContent.ops[0]; if ( firstOp && typeof firstOp.insert !== 'string' && firstOp.insert?.reply && quill.getLength() === 1 ) { quill.insertText(1, '\n', Quill.sources.SILENT); } }); quill.on('editor-change', (eventName: string) => { if (eventName === 'text-change') { const editorContent = quill.getContents(); const firstOp = editorContent.ops[0]; if ( firstOp && typeof firstOp.insert !== 'string' && firstOp.insert?.reply && quill.getLength() === 1 ) { quill.insertText(1, '\n', Quill.sources.SILENT); } } }); quill.root.addEventListener('compositionstart', () => { const editorContent = quill.getContents(); const firstOp = editorContent.ops[0]; if ( firstOp && typeof firstOp.insert !== 'string' && firstOp.insert?.reply && quill.getLength() === 1 ) { quill.insertText(1, '\n', Quill.sources.SILENT); } }); } const onOpenChange = (open: boolean) => { if (open) { const selection = quill?.getSelection(); if (selection) memorizedRange.current = selection; } }; const insertImage = (url: string) => { const selection = memorizedRange.current || quill?.getSelection(); quill?.deleteText(selection?.index || 0, selection?.length || 0); quill?.insertEmbed(selection?.index || 0, 'image', { src: url, alt: '图片', }); quill?.setSelection((selection?.index || 0) + 1, 0); }; function insertReplyBlock (messageId: string) { const isNumberReg = /^(?:0|(?:-?[1-9]\d*))$/; if (!isNumberReg.test(messageId)) { toast.error('请输入正确的消息ID'); return; } const editorContent = quill?.getContents(); const firstOp = editorContent?.ops[0]; const currentSelection = quill?.getSelection(); if ( firstOp && typeof firstOp.insert !== 'string' && firstOp.insert?.reply ) { const delta = quill?.getContents(); if (delta) { delta.ops[0] = { insert: { reply: { messageId } }, }; quill?.setContents(delta, Quill.sources.USER); } } else { quill?.insertEmbed(0, 'reply', { messageId }, Quill.sources.USER); } quill?.setSelection((currentSelection?.index || 0) + 1, 0); quill?.blur(); } const onInsertEmoji = (emoji: EmojiValue) => { const selection = memorizedRange.current || quill?.getSelection(); quill?.deleteText(selection?.index || 0, selection?.length || 0); quill?.insertEmbed(selection?.index || 0, 'emoji', { alt: emoji.alt, src: emoji.src, id: emoji.id, }); quill?.setSelection((selection?.index || 0) + 1, 0); }; const getChatMessage = () => { const delta = quill?.getContents(); const ops = delta?.ops?.filter((op) => { return op.insert !== '\n'; }) ?? []; const messages: OB11Segment[] = ops.map((op) => { return quillToMessage(op); }); return messages; }; return (
); }; export default ChatInput;