carbon-tokenization / frontend /src /editor /CitationView.tsx
tfrere's picture
tfrere HF Staff
feat(frontend): editor refresh (embed studio, comment popover, shiki, top bar, hooks, styles)
76fc93a
Raw
History Blame Contribute Delete
2.25 kB
import { NodeViewWrapper } from "@tiptap/react";
import { useState, useRef, useCallback } from "react";
import type { NodeViewProps } from "@tiptap/react";
export function CitationView({ node, editor, getPos }: NodeViewProps) {
const key = node.attrs.key as string;
const label = (node.attrs.label as string) || `[${key}]`;
const [showTooltip, setShowTooltip] = useState(false);
const tooltipTimer = useRef<ReturnType<typeof setTimeout>>();
const wrapperRef = useRef<HTMLSpanElement>(null);
const getEntry = useCallback(() => {
return (editor.storage.citation as any)?.citationsMap?.get(key) ?? null;
}, [editor, key]);
const handleMouseEnter = useCallback(() => {
tooltipTimer.current = setTimeout(() => setShowTooltip(true), 300);
}, []);
const handleMouseLeave = useCallback(() => {
clearTimeout(tooltipTimer.current);
setShowTooltip(false);
}, []);
const removeCitation = useCallback(() => {
const pos = getPos();
if (typeof pos === "number") {
editor.chain().focus().deleteRange({ from: pos, to: pos + 1 }).run();
}
setShowTooltip(false);
}, [editor, getPos]);
const entry = showTooltip ? getEntry() : null;
return (
<NodeViewWrapper
as="span"
className="citation-node"
ref={wrapperRef}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{label}
{showTooltip && entry && (
<div className="citation-tooltip">
<div className="citation-tooltip-title">{entry.title || key}</div>
{entry["container-title"] && (
<div className="citation-tooltip-journal">
{entry["container-title"]}
{entry.volume ? `, ${entry.volume}` : ""}
{entry.page ? `, ${entry.page}` : ""}
</div>
)}
{entry.DOI && (
<div className="citation-tooltip-doi">doi: {entry.DOI}</div>
)}
<button
className="citation-tooltip-remove"
onMouseDown={(e) => {
e.preventDefault();
e.stopPropagation();
removeCitation();
}}
>
Remove
</button>
</div>
)}
</NodeViewWrapper>
);
}