// imports import clsx from 'clsx'; import { Combobox } from '@headlessui/react'; import { Transforms } from 'slate'; import React, { useRef, useEffect } from 'react'; import { useSelected, useFocused, ReactEditor } from 'slate-react'; // Component for rendering individual mentions const Mention = ({ attributes, children, element }) => { // Check if the mention is selected or focused const selected = useSelected(); const focused = useFocused(); // Render the mention with appropriate styling return ( @{element.member?.user?.name || element.member?.user?.email || ''} {children} ); }; // Function to serialize mentions export const serializeMention = ({ member }) => { return `` }; // Component for rendering the mention combobox export const MentionCombobox = ({ items, onSelect, targetRange, editor, editorRef, selectedIndex }) => { // Reference to the combobox DOM element const ref = useRef(null); // Position the combobox based on the current selection useEffect(() => { if (targetRange && items.length > 0) { const el = ref.current; const domRange = ReactEditor.toDOMRange(editor, targetRange); const rect = domRange.getBoundingClientRect(); const editorRect = editorRef.current.getBoundingClientRect(); // Calculate the height of the combobox const comboboxHeight = el.offsetHeight; // Position the combobox above the text el.style.top = `${rect.top - editorRect.top - comboboxHeight}px`; el.style.left = `${rect.left - editorRect.left}px`; } }, [items.length, editor, targetRange, editorRef]); // Render the combobox return (
onSelect(items.find((i) => i.id === id))}>
{items.map((item, index) => ( @{item.user?.name || item.user?.email} ))}
); }; // Function to insert a mention at the current selection export const insertMention = (editor, member) => { const mention = { type: 'mention', member, children: [{ text: '' }], }; Transforms.insertNodes(editor, mention); Transforms.move(editor); }; // Custom plugin to handle mentions in the editor export const withMentions = editor => { const { isInline, isVoid } = editor; // Override isInline to treat mentions as inline elements editor.isInline = element => { return element.type === 'mention' ? true : isInline(element); }; // Override isVoid to treat mentions as void elements editor.isVoid = element => { return element.type === 'mention' ? true : isVoid(element); }; return editor; }; /** * export default mention */ export default Mention;