import { useId, useImperativeHandle, useRef, type Ref } from "react"; import { FloatingPortal } from "@floating-ui/react"; import type { EmojiItem } from "@tiptap/extension-emoji"; import { useMenuNavigation } from "../menu/navigation"; import { preserveEditorSelectionOnMouseDown, useEditorRectPopover } from "../menu/popover"; export interface EmojiSuggestionPanelProps { items: EmojiItem[]; command: (item: EmojiItem) => void; clientRect: (() => DOMRect | null) | null; contextElement?: HTMLElement | null; onClose?: () => void; ref?: Ref; } export interface EmojiSuggestionPanelHandle { onKeyDown: (event: KeyboardEvent) => boolean; } export function EmojiSuggestionPanel({ items, command, clientRect, contextElement, onClose, ref, }: EmojiSuggestionPanelProps) { const panelRef = useRef(null); const listboxId = useId(); const navigation = useMenuNavigation({ items, listRef: panelRef, onSelect: command, }); const { floatingStyles, setFloating } = useEditorRectPopover({ open: true, onClose, getAnchorRect: () => clientRect?.() ?? null, contextElement, maxHeight: true, deferOutsidePress: true, }); useImperativeHandle(ref, () => ({ onKeyDown: (event: KeyboardEvent) => navigation.onKeyDown(event), })); return (
{ setFloating(node); panelRef.current = node; }} className="tiptap-slash-menu" style={{ ...floatingStyles, zIndex: 80 }} onMouseDownCapture={(event) => preserveEditorSelectionOnMouseDown(event)} >
Emoji
{items.length === 0 ? (
🙂 No emoji found
) : ( items.map((item, index) => ( )) )}
); }