| import { NodeViewWrapper } from "@tiptap/react"; |
| import { useState, useRef, useCallback } from "react"; |
| import type { NodeViewProps } from "@tiptap/react"; |
|
|
| export function GlossaryView({ node, editor, getPos }: NodeViewProps) { |
| const term = node.attrs.term as string; |
| const definition = node.attrs.definition as string; |
| const [showTooltip, setShowTooltip] = useState(false); |
| const tooltipTimer = useRef<ReturnType<typeof setTimeout>>(); |
|
|
| const handleMouseEnter = useCallback(() => { |
| tooltipTimer.current = setTimeout(() => setShowTooltip(true), 300); |
| }, []); |
|
|
| const handleMouseLeave = useCallback(() => { |
| clearTimeout(tooltipTimer.current); |
| setShowTooltip(false); |
| }, []); |
|
|
| const remove = useCallback(() => { |
| const pos = getPos(); |
| if (typeof pos === "number") { |
| editor.chain().focus().deleteRange({ from: pos, to: pos + 1 }).run(); |
| } |
| setShowTooltip(false); |
| }, [editor, getPos]); |
|
|
| return ( |
| <NodeViewWrapper |
| as="span" |
| className="glossary-node" |
| onMouseEnter={handleMouseEnter} |
| onMouseLeave={handleMouseLeave} |
| > |
| {term || "term"} |
| {showTooltip && ( |
| <div className="glossary-tooltip"> |
| <div className="glossary-tooltip-term">{term}</div> |
| <div className="glossary-tooltip-def">{definition || "No definition yet."}</div> |
| <button |
| className="glossary-tooltip-remove" |
| onMouseDown={(e) => { |
| e.preventDefault(); |
| e.stopPropagation(); |
| remove(); |
| }} |
| > |
| Remove |
| </button> |
| </div> |
| )} |
| </NodeViewWrapper> |
| ); |
| } |
|
|