import { Popover } from 'antd'; import React, { FC, useMemo, useState } from 'react'; import { useRecoilValue } from 'recoil'; import { Transforms, createEditor, BaseEditor, Text, Descendant, Editor } from 'slate'; import { Slate, Editable, withReact, ReactEditor, useSelected, useFocused } from 'slate-react'; import dynamic from 'next/dynamic'; import classNames from 'classnames'; import WebsocketService from '../../../services/websocket-service'; import { websocketServiceAtom } from '../../stores/ClientConfigStore'; import { MessageType } from '../../../interfaces/socket-events'; import styles from './ChatTextField.module.scss'; // Lazy loaded components const EmojiPicker = dynamic(() => import('./EmojiPicker').then(mod => mod.EmojiPicker), { ssr: false, }); const SendOutlined = dynamic(() => import('@ant-design/icons/SendOutlined'), { ssr: false, }); const SmileOutlined = dynamic(() => import('@ant-design/icons/SmileOutlined'), { ssr: false, }); type CustomElement = { type: 'paragraph' | 'span'; children: CustomText[] } | ImageNode; type CustomText = { text: string }; type EmptyText = { text: string; }; type ImageNode = { type: 'image'; alt: string; src: string; name: string; children: EmptyText[]; }; declare module 'slate' { interface CustomTypes { Editor: BaseEditor & ReactEditor; Element: CustomElement; Text: CustomText; } } const Image = p => { const { attributes, element, children } = p; const selected = useSelected(); const focused = useFocused(); return ( {children} ); }; const withImages = editor => { const { isVoid } = editor; // eslint-disable-next-line no-param-reassign editor.isVoid = element => (element.type === 'image' ? true : isVoid(element)); // eslint-disable-next-line no-param-reassign editor.isInline = element => element.type === 'image'; return editor; }; const serialize = node => { if (Text.isText(node)) { const string = node.text; return string; } let children; if (node.children.length === 0) { children = [{ text: '' }]; } else { children = node.children?.map(n => serialize(n)).join(''); } switch (node.type) { case 'paragraph': return `
${children}
`; case 'image': return ``; default: return children; } }; const getCharacterCount = node => { if (Text.isText(node)) { return node.text.length; } if (node.type === 'image') { return 5; } let count = 0; node.children.forEach(child => { count += getCharacterCount(child); }); return count; }; export type ChatTextFieldProps = { defaultText?: string; enabled: boolean; }; const characterLimit = 300; export const ChatTextField: FC