import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'; import { useCallback, useEffect, useState } from 'react'; import { FORMAT_TEXT_COMMAND, $getSelection, $isRangeSelection, TextFormatType } from 'lexical'; import { TextBoldIcon, TextItalicIcon, TextStrikethroughIcon, MagicWand01Icon, PaintBucketIcon } from 'hugeicons-react'; import { $patchStyleText, $getSelectionStyleValueForProperty } from '@lexical/selection'; export default function HoverToolbar() { const [editor] = useLexicalComposerContext(); const [isBold, setIsBold] = useState(false); const [isItalic, setIsItalic] = useState(false); const [isStrikethrough, setIsStrikethrough] = useState(false); const [position, setPosition] = useState({ top: -10000, left: -10000, visible: false }); const [showColorPicker, setShowColorPicker] = useState(false); const colors = [ '#000000', '#FF0000', '#00FF00', '#0000FF', '#FFA500', '#800080', '#008080', '#FF69B4' ]; const updateToolbar = useCallback(() => { editor.getEditorState().read(() => { const selection = $getSelection(); if ($isRangeSelection(selection) && !selection.isCollapsed()) { const nativeSelection = window.getSelection(); if (nativeSelection && nativeSelection.rangeCount > 0) { const domRange = nativeSelection.getRangeAt(0); const rect = domRange.getBoundingClientRect(); setPosition({ top: rect.top - 40, left: rect.left + (rect.width / 2) - 80, visible: true }); setIsBold(selection.hasFormat('bold')); setIsItalic(selection.hasFormat('italic')); setIsStrikethrough(selection.hasFormat('strikethrough')); } } else { setPosition(p => ({ ...p, visible: false })); } }); }, [editor]); useEffect(() => { const unregister = editor.registerUpdateListener(() => { updateToolbar(); }); document.addEventListener('selectionchange', updateToolbar); return () => { unregister(); document.removeEventListener('selectionchange', updateToolbar); }; }, [editor, updateToolbar]); const applyFormat = (format: TextFormatType) => { editor.dispatchCommand(FORMAT_TEXT_COMMAND, format); }; const applyPixelize = () => { editor.update(() => { const selection = $getSelection(); if ($isRangeSelection(selection)) { const currentFilter = $getSelectionStyleValueForProperty(selection, 'filter'); if (currentFilter === 'blur(3px)') { $patchStyleText(selection, { 'filter': '' }); } else { $patchStyleText(selection, { 'filter': 'blur(3px)' }); } } }); }; const applyColor = (color: string) => { editor.update(() => { const selection = $getSelection(); if ($isRangeSelection(selection)) { $patchStyleText(selection, { 'color': color }); } }); setShowColorPicker(false); }; if (!position.visible) return null; return (