import { Node } from '@tiptap/core'; import { NodeViewWrapper, ReactNodeViewRenderer } from '@tiptap/react'; import type { NodeViewProps } from '@tiptap/react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { attributesFromSpec, nodeSpec } from '../spec-utils'; import { useWikilinks } from '../wikilink-context'; /** * Renders a `[[wikilink]]` (issue #46): its shown text is the explicit * `displayText` or, when none is set, the target page's current title — so * renaming the target updates the link everywhere. A missing target renders as * a dashed "phantom" with a tooltip and becomes live once the page exists * (resolution is server-side in #47). Click navigates in read mode; in edit * mode the atom just selects (no navigation). */ function WikilinkView({ node, editor }: NodeViewProps): React.JSX.Element { const { t } = useTranslation('editor'); const navigate = useNavigate(); const { resolve, pondSlug } = useWikilinks(); const slug = node.attrs.targetSlug as string; const display = node.attrs.displayText as string | null; const { title, exists } = resolve(slug); const text = display ?? title ?? slug; const editable = editor.isEditable; return ( { event.preventDefault(); // In edit mode a click should not navigate away from the editor. if (!editable) navigate(`/p/${pondSlug}/${slug}`); }} > {text} ); } const wikilinkSpec = nodeSpec('wikilink'); export const Wikilink = Node.create({ name: 'wikilink', group: wikilinkSpec.group, inline: wikilinkSpec.inline, atom: wikilinkSpec.atom, addAttributes() { return attributesFromSpec(wikilinkSpec); }, parseHTML: () => wikilinkSpec.parseDOM, renderHTML: ({ node }) => wikilinkSpec.toDOM!(node), addNodeView() { return ReactNodeViewRenderer(WikilinkView); }, });