import "@/features/editor/styles/index.css"; import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react"; import { Editor, EditorProvider } from "@tiptap/react"; import { mainExtensions } from "@/features/editor/extensions/extensions"; import { Document } from "@tiptap/extension-document"; import { Heading, UniqueID } from "@docmost/editor-ext"; import { Text } from "@tiptap/extension-text"; import { Placeholder } from "@tiptap/extension-placeholder"; import { useAtom } from "jotai"; import { lightboxRequestAtom, readOnlyEditorAtom, } from "@/features/editor/atoms/editor-atoms.ts"; import { useEditorScroll } from "./hooks/use-editor-scroll"; import { TransclusionLookupProvider } from "@/features/editor/components/transclusion/transclusion-lookup-context"; import LightboxView, { getLightboxClickRequest, } from "@/features/editor/components/common/lightbox-view"; interface PageEditorProps { title: string; content: any; pageId?: string; printMode?: boolean; /** * When rendering inside a public share, pass the share's id (or key). Lookups * for transclusion content then resolve against the share graph instead of * the viewer's personal permissions, so a share never leaks source content * that isn't itself shared. */ shareId?: string; } export default function ReadonlyPageEditor({ title, content, pageId, printMode = false, shareId, }: PageEditorProps) { const [, setReadOnlyEditor] = useAtom(readOnlyEditorAtom); const [lightboxRequest, setLightboxRequest] = useAtom(lightboxRequestAtom); const [contentEditor, setContentEditor] = useState(null); const isComponentMounted = useRef(false); const editorCreated = useRef(false); const canScroll = useCallback( () => isComponentMounted.current && editorCreated.current, [isComponentMounted, editorCreated], ); const initialScrollTo = window.location.hash ? window.location.hash.slice(1) : ""; const { handleScrollTo } = useEditorScroll({ canScroll, initialScrollTo }); useEffect(() => { isComponentMounted.current = true; }, []); useEffect(() => { if (!shareId) return; setLightboxRequest(null); }, [pageId, shareId]); const extensions = useMemo(() => { const excludedExtensions = new Set([ "uniqueID", ...(printMode ? ["tableHeaderPin", "tableReadonlySort"] : []), ]); const filteredExtensions = mainExtensions.filter( (ext) => !excludedExtensions.has(ext.name), ); return [ ...filteredExtensions, UniqueID.configure({ types: ["heading", "paragraph"], updateDocument: false, }), ]; }, [printMode]); const titleExtensions = [ Document.extend({ content: "heading", }), Heading, Text, Placeholder.configure({ placeholder: "Untitled", showOnlyWhenEditable: false, }), ]; return (
{ const request = getLightboxClickRequest(node); if (!request) return false; setLightboxRequest(request); return true; }, } : undefined } onCreate={({ editor }) => { if (editor) { if (pageId) { // @ts-ignore editor.storage.pageId = pageId; } // @ts-ignore setReadOnlyEditor(editor); setContentEditor(editor); handleScrollTo(editor); editorCreated.current = true; } }} > {shareId && contentEditor && ( setLightboxRequest(null)} /> )}
); }