76 lines
1.7 KiB
TypeScript
76 lines
1.7 KiB
TypeScript
import { Node, mergeAttributes, ReactNodeViewRenderer, NodeViewWrapper } from "@tiptap/react";
|
|
import type { NodeViewProps } from "@tiptap/react";
|
|
import { FileText } from "lucide-react";
|
|
import { usePageTitle } from "./PageTitleContext";
|
|
|
|
declare module "@tiptap/react" {
|
|
interface Commands<ReturnType> {
|
|
pageLink: {
|
|
insertPageLink: (attrs: { pageId: string }) => ReturnType;
|
|
};
|
|
}
|
|
}
|
|
|
|
function PageLinkNodeView({ node }: NodeViewProps) {
|
|
const title = usePageTitle(node.attrs.pageId);
|
|
|
|
const handleClick = (e: React.MouseEvent) => {
|
|
(e.currentTarget as HTMLElement).dispatchEvent(
|
|
new CustomEvent("page-link-click", {
|
|
bubbles: true,
|
|
detail: { pageId: node.attrs.pageId },
|
|
}),
|
|
);
|
|
};
|
|
|
|
return (
|
|
<NodeViewWrapper className="page-link-block" data-page-link={node.attrs.pageId} onClick={handleClick}>
|
|
<FileText className="h-5 w-5 shrink-0" />
|
|
<span>{title}</span>
|
|
</NodeViewWrapper>
|
|
);
|
|
}
|
|
|
|
export const PageLinkExtension = Node.create({
|
|
name: "pageLink",
|
|
group: "block",
|
|
atom: true,
|
|
|
|
addAttributes() {
|
|
return {
|
|
pageId: { default: null },
|
|
};
|
|
},
|
|
|
|
parseHTML() {
|
|
return [
|
|
{ tag: 'div[data-page-link]' },
|
|
{ tag: 'span[data-page-link]' },
|
|
];
|
|
},
|
|
|
|
renderHTML({ HTMLAttributes }) {
|
|
return [
|
|
"div",
|
|
mergeAttributes(HTMLAttributes, {
|
|
"data-page-link": HTMLAttributes.pageId,
|
|
class: "page-link-block",
|
|
}),
|
|
];
|
|
},
|
|
|
|
addCommands() {
|
|
return {
|
|
insertPageLink:
|
|
(attrs) =>
|
|
({ chain }) => {
|
|
return chain().insertContent({ type: this.name, attrs }).run();
|
|
},
|
|
};
|
|
},
|
|
|
|
addNodeView() {
|
|
return ReactNodeViewRenderer(PageLinkNodeView);
|
|
},
|
|
});
|