import React, { KeyboardEventHandler, useCallback, useRef, useState } from 'react'; import { isKeyHotkey } from 'is-hotkey'; import { Editor } from 'slate'; import { IconButton, Line, PopOut } from 'folds'; import { Icon, Icons } from '../../components/icons'; import { CustomEditor, Toolbar, EmoticonAutocomplete, AutocompletePrefix, AutocompleteQuery, getAutocompleteQuery, createEmoticonElement, moveCursor, safeFocusEditor, } from '../../components/editor'; import { EmojiBoard, EmojiBoardTab } from '../../components/emoji-board'; import { UseStateProvider } from '../../components/UseStateProvider'; import { useSetting } from '../../state/hooks/settings'; import { settingsAtom } from '../../state/settings'; import { useImagePackRooms } from '../../hooks/useImagePackRooms'; import { useAtomValue } from 'jotai'; import { roomToParentsAtom } from '../../state/room/roomToParents'; import { Room } from 'matrix-js-sdk'; import { mobileOrTablet } from '../../utils/user-agent'; import { PluginButtonSlot } from '../settings/plugins/PluginButtonSlot'; type ForumChatComposerProps = { editor: Editor; roomId: string; room: Room; placeholder?: string; onSend?: () => void; showAttachButton?: boolean; maxHeight?: string; }; /** Same chrome as {@link RoomInput} (attach, emoji, toolbar, send). */ export function ForumChatComposer({ editor, roomId, room, placeholder = 'Send a message…', onSend, showAttachButton = false, maxHeight, }: ForumChatComposerProps) { const [toolbar, setToolbar] = useSetting(settingsAtom, 'editorToolbar'); const [enterForNewline] = useSetting(settingsAtom, 'enterForNewline'); const roomToParents = useAtomValue(roomToParentsAtom); const imagePackRooms = useImagePackRooms(roomId, roomToParents); const emojiBtnRef = useRef(null); const [autocompleteQuery, setAutocompleteQuery] = useState>(); const handleKeyDown: KeyboardEventHandler = useCallback( (evt) => { if ( onSend && (isKeyHotkey('mod+enter', evt) || (!enterForNewline && isKeyHotkey('enter', evt))) ) { evt.preventDefault(); onSend(); } }, [enterForNewline, onSend] ); const handleKeyUp: KeyboardEventHandler = useCallback( (evt) => { const prevWordRange = getAutocompleteQuery(editor, evt); if (prevWordRange?.prefix === AutocompletePrefix.Emoticon) { setAutocompleteQuery({ prefix: AutocompletePrefix.Emoticon, range: prevWordRange.range }); return; } setAutocompleteQuery(undefined); }, [editor] ); const handleEmoticonSelect = (key: string, shortcode: string) => { editor.insertNode(createEmoticonElement(key, shortcode)); moveCursor(editor); }; const handleCloseAutocomplete = useCallback(() => { setAutocompleteQuery(undefined); safeFocusEditor(editor); }, [editor]); return (
{autocompleteQuery?.prefix === AutocompletePrefix.Emoticon && ( )} : undefined} after={ <> setToolbar(!toolbar)} aria-label="Formatting" > {(emojiBoardTab: EmojiBoardTab | undefined, setEmojiBoardTab) => ( { setEmojiBoardTab((t) => { if (t) { if (!mobileOrTablet()) safeFocusEditor(editor); return undefined; } return t; }); }} /> } > setEmojiBoardTab(EmojiBoardTab.Emoji)} variant="SurfaceVariant" size="300" radii="300" type="button" aria-label="Emoji" > )} {onSend && ( )} } bottom={ toolbar ? (
) : undefined } />
); }