From 16be6ff37d4ff8d0a3be2b2b271ea5c16ee2fce9 Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Mon, 9 Sep 2024 16:02:14 +0530 Subject: [PATCH 1/6] fix: svg not supported in image uploads --- packages/editor/src/core/helpers/editor-commands.ts | 2 +- packages/editor/src/core/plugins/image/utils/validate-file.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor/src/core/helpers/editor-commands.ts b/packages/editor/src/core/helpers/editor-commands.ts index db3b4d66d0e..7cf3e8d1f17 100644 --- a/packages/editor/src/core/helpers/editor-commands.ts +++ b/packages/editor/src/core/helpers/editor-commands.ts @@ -146,7 +146,7 @@ export const insertImageCommand = ( if (range) editor.chain().focus().deleteRange(range).run(); const input = document.createElement("input"); input.type = "file"; - input.accept = ".jpeg, .jpg, .png, .webp, .svg"; + input.accept = ".jpeg, .jpg, .png, .webp"; input.onchange = async () => { if (input.files?.length) { const file = input.files[0]; diff --git a/packages/editor/src/core/plugins/image/utils/validate-file.ts b/packages/editor/src/core/plugins/image/utils/validate-file.ts index a7952a0e116..97c5e9e8407 100644 --- a/packages/editor/src/core/plugins/image/utils/validate-file.ts +++ b/packages/editor/src/core/plugins/image/utils/validate-file.ts @@ -4,7 +4,7 @@ export function isFileValid(file: File): boolean { return false; } - const allowedTypes = ["image/jpeg", "image/jpg", "image/png", "image/webp", "image/svg+xml"]; + const allowedTypes = ["image/jpeg", "image/jpg", "image/png", "image/webp"]; if (!allowedTypes.includes(file.type)) { alert("Invalid file type. Please select a JPEG, JPG, PNG, WEBP, or SVG image file."); return false; From f71ca5802f31f8bccb9bfb7f6c90056c0a5ed5aa Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Mon, 9 Sep 2024 20:27:02 +0530 Subject: [PATCH 2/6] fix: svg image file error message fixed --- packages/editor/src/core/plugins/image/utils/validate-file.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/core/plugins/image/utils/validate-file.ts b/packages/editor/src/core/plugins/image/utils/validate-file.ts index 97c5e9e8407..b79ca6683e2 100644 --- a/packages/editor/src/core/plugins/image/utils/validate-file.ts +++ b/packages/editor/src/core/plugins/image/utils/validate-file.ts @@ -6,7 +6,7 @@ export function isFileValid(file: File): boolean { const allowedTypes = ["image/jpeg", "image/jpg", "image/png", "image/webp"]; if (!allowedTypes.includes(file.type)) { - alert("Invalid file type. Please select a JPEG, JPG, PNG, WEBP, or SVG image file."); + alert("Invalid file type. Please select a JPEG, JPG, PNG, or WEBP image file."); return false; } From e3a8eabe2ab06dade2334610e22d558a434545bc Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Mon, 9 Sep 2024 20:38:09 +0530 Subject: [PATCH 3/6] fix: heading not updating with realtime --- .../editor/src/core/extensions/extensions.tsx | 2 + .../editor/src/core/extensions/headers.ts | 57 +++++++++++++++++++ packages/editor/src/core/extensions/index.ts | 1 + packages/editor/src/core/hooks/use-editor.ts | 16 +++++- packages/editor/src/core/types/editor.ts | 1 + .../components/pages/editor/editor-body.tsx | 20 ++----- .../pages/editor/header/mobile-root.tsx | 3 - .../components/pages/editor/header/root.tsx | 36 ++++++------ .../components/pages/editor/page-root.tsx | 9 +-- .../pages/editor/summary/content-browser.tsx | 18 ++++-- .../pages/editor/summary/popover.tsx | 11 ++-- 11 files changed, 118 insertions(+), 56 deletions(-) create mode 100644 packages/editor/src/core/extensions/headers.ts diff --git a/packages/editor/src/core/extensions/extensions.tsx b/packages/editor/src/core/extensions/extensions.tsx index 823754a9317..0b016524fc1 100644 --- a/packages/editor/src/core/extensions/extensions.tsx +++ b/packages/editor/src/core/extensions/extensions.tsx @@ -18,6 +18,7 @@ import { CustomQuoteExtension, CustomTypographyExtension, DropHandlerExtension, + HeadingListExtension, ImageExtension, ListKeymap, Table, @@ -159,4 +160,5 @@ export const CoreEditorExtensions = ({ includeChildren: true, }), CharacterCount, + HeadingListExtension, ]; diff --git a/packages/editor/src/core/extensions/headers.ts b/packages/editor/src/core/extensions/headers.ts new file mode 100644 index 00000000000..c88b53638de --- /dev/null +++ b/packages/editor/src/core/extensions/headers.ts @@ -0,0 +1,57 @@ +import { Extension } from "@tiptap/core"; +import { Plugin, PluginKey } from "prosemirror-state"; + +export interface IMarking { + type: "heading"; + level: number; + text: string; + sequence: number; +} + +export const HeadingListExtension = Extension.create({ + name: "headingList", + + addStorage() { + return { + headings: [] as IMarking[], + }; + }, + + addProseMirrorPlugins() { + const plugin = new Plugin({ + key: new PluginKey("heading-list"), + appendTransaction: (_, __, newState) => { + const headings: IMarking[] = []; + let h1Sequence = 0; + let h2Sequence = 0; + let h3Sequence = 0; + + newState.doc.descendants((node) => { + if (node.type.name === "heading") { + const level = node.attrs.level; + const text = node.textContent; + + headings.push({ + type: "heading", + level: level, + text: text, + sequence: level === 1 ? ++h1Sequence : level === 2 ? ++h2Sequence : ++h3Sequence, + }); + } + }); + + this.storage.headings = headings; + + this.editor.emit("update", { editor: this.editor, transaction: newState.tr }); + + return null; + }, + }); + + return [plugin]; + }, + + getHeadings() { + return this.storage.headings; + }, +}); diff --git a/packages/editor/src/core/extensions/index.ts b/packages/editor/src/core/extensions/index.ts index 41f8189b0b7..cdfe018ed01 100644 --- a/packages/editor/src/core/extensions/index.ts +++ b/packages/editor/src/core/extensions/index.ts @@ -18,3 +18,4 @@ export * from "./quote"; export * from "./read-only-extensions"; export * from "./side-menu"; export * from "./slash-commands"; +export * from "./headers"; diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index e1349b9c1ec..6d3b73764be 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -153,11 +153,24 @@ export const useEditor = (props: CustomEditorProps) => { const item = getEditorMenuItem(itemName); return item ? item.isActive() : false; }, + onHeadingChange: (callback: (headings: IMarking[]) => void) => { + // Subscribe to update event emitted from headers extension + editorRef.current?.on("update", () => { + callback(editorRef.current?.storage.headingList.headings); + }); + // Return a function to unsubscribe to the continuous transactions of + // the editor on unmounting the component that has subscribed to this + // method + return () => { + editorRef.current?.off("update"); + }; + }, onStateChange: (callback: () => void) => { // Subscribe to editor state changes editorRef.current?.on("transaction", () => { callback(); }); + // Return a function to unsubscribe to the continuous transactions of // the editor on unmounting the component that has subscribed to this // method @@ -214,7 +227,6 @@ export const useEditor = (props: CustomEditorProps) => { } }); const selection = nodesArray.join(""); - console.log(selection); return selection; }, insertText: (contentHTML, insertOnNextLine) => { @@ -236,7 +248,7 @@ export const useEditor = (props: CustomEditorProps) => { words: editorRef.current?.storage?.characterCount?.words?.() ?? 0, }, }), - [editorRef, savedSelection, fileHandler.upload] + [editorRef, savedSelection, fileHandler.upload, editor] ); if (!editor) { diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 8045de945b7..6221140b42e 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -32,6 +32,7 @@ export interface EditorRefApi extends EditorReadOnlyRefApi { executeMenuItemCommand: (itemKey: TEditorCommands) => void; isMenuItemActive: (itemKey: TEditorCommands) => boolean; onStateChange: (callback: () => void) => () => void; + onHeadingChange: (callback: (headings: IMarking[]) => void) => () => void; setFocusAtPosition: (position: number) => void; isEditorReadyToDiscard: () => boolean; getSelectedText: () => string | null; diff --git a/web/core/components/pages/editor/editor-body.tsx b/web/core/components/pages/editor/editor-body.tsx index 6cd898c0079..b6480e9a75e 100644 --- a/web/core/components/pages/editor/editor-body.tsx +++ b/web/core/components/pages/editor/editor-body.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo } from "react"; +import { useCallback, useMemo } from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // document-editor @@ -38,14 +38,13 @@ const fileService = new FileService(); type Props = { editorRef: React.RefObject; + editorReady: boolean; handleConnectionStatus: (status: boolean) => void; handleEditorReady: (value: boolean) => void; handleReadOnlyEditorReady: (value: boolean) => void; - markings: IMarking[]; page: IPage; readOnlyEditorRef: React.RefObject; sidePeekVisible: boolean; - updateMarkings: (description_html: string) => void; }; export const PageEditorBody: React.FC = observer((props) => { @@ -54,11 +53,9 @@ export const PageEditorBody: React.FC = observer((props) => { handleConnectionStatus, handleEditorReady, handleReadOnlyEditorReady, - markings, page, readOnlyEditorRef, sidePeekVisible, - updateMarkings, } = props; // router const { workspaceSlug, projectId } = useParams(); @@ -70,10 +67,9 @@ export const PageEditorBody: React.FC = observer((props) => { project: { getProjectMemberIds }, } = useMember(); // derived values - const workspaceId = workspaceSlug ? (getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "") : ""; + const workspaceId = workspaceSlug ? getWorkspaceBySlug(workspaceSlug.toString())?.id ?? "" : ""; const pageId = page?.id; const pageTitle = page?.name ?? ""; - const pageDescription = page?.description_html; const { isContentEditable, updateTitle, setIsSubmitting } = page; const projectMemberIds = projectId ? getProjectMemberIds(projectId.toString()) : []; const projectMemberDetails = projectMemberIds?.map((id) => getUserDetails(id) as IUserLite); @@ -104,6 +100,7 @@ export const PageEditorBody: React.FC = observer((props) => { const handleServerConnect = useCallback(() => { handleConnectionStatus(false); }, []); + const handleServerError = useCallback(() => { handleConnectionStatus(true); }, []); @@ -116,10 +113,6 @@ export const PageEditorBody: React.FC = observer((props) => { [] ); - useEffect(() => { - updateMarkings(pageDescription ?? "

"); - }, [pageDescription, updateMarkings]); - const realtimeConfig: TRealtimeConfig = useMemo( () => ({ url: `${LIVE_URL}/collaboration`, @@ -144,10 +137,7 @@ export const PageEditorBody: React.FC = observer((props) => { })} > {!isFullWidth && ( - + )}
; handleDuplicatePage: () => void; hasConnectionFailed: boolean; - markings: IMarking[]; page: IPage; readOnlyEditorReady: boolean; readOnlyEditorRef: React.RefObject; @@ -27,7 +26,6 @@ export const PageEditorMobileHeaderRoot: React.FC = observer((props) => { editorRef, handleDuplicatePage, hasConnectionFailed, - markings, page, readOnlyEditorReady, readOnlyEditorRef, @@ -48,7 +46,6 @@ export const PageEditorMobileHeaderRoot: React.FC = observer((props) => { diff --git a/web/core/components/pages/editor/header/root.tsx b/web/core/components/pages/editor/header/root.tsx index 8fe5040650c..c8a4774dac9 100644 --- a/web/core/components/pages/editor/header/root.tsx +++ b/web/core/components/pages/editor/header/root.tsx @@ -1,5 +1,5 @@ import { observer } from "mobx-react"; -import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/editor"; +import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor"; // components import { Header, EHeaderVariant } from "@plane/ui"; import { PageEditorMobileHeaderRoot, PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages"; @@ -15,7 +15,6 @@ type Props = { editorRef: React.RefObject; handleDuplicatePage: () => void; hasConnectionFailed: boolean; - markings: IMarking[]; page: IPage; readOnlyEditorReady: boolean; readOnlyEditorRef: React.RefObject; @@ -29,7 +28,6 @@ export const PageEditorHeaderRoot: React.FC = observer((props) => { editorRef, handleDuplicatePage, hasConnectionFailed, - markings, page, readOnlyEditorReady, readOnlyEditorRef, @@ -47,22 +45,23 @@ export const PageEditorHeaderRoot: React.FC = observer((props) => { <>
-
- -
{(editorReady || readOnlyEditorReady) && isContentEditable && editorRef.current && ( - + <> +
+ +
+ + )}
= observer((props) => { readOnlyEditorRef={readOnlyEditorRef} editorReady={editorReady} readOnlyEditorReady={readOnlyEditorReady} - markings={markings} handleDuplicatePage={handleDuplicatePage} hasConnectionFailed={hasConnectionFailed} page={page} diff --git a/web/core/components/pages/editor/page-root.tsx b/web/core/components/pages/editor/page-root.tsx index dfd1854c326..c028c1f4715 100644 --- a/web/core/components/pages/editor/page-root.tsx +++ b/web/core/components/pages/editor/page-root.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from "react"; import { observer } from "mobx-react"; import { useSearchParams } from "next/navigation"; // editor -import { EditorRefApi, useEditorMarkings } from "@plane/editor"; +import { EditorRefApi } from "@plane/editor"; // types import { TPage } from "@plane/types"; // ui @@ -44,8 +44,7 @@ export const PageRoot = observer((props: TPageRootProps) => { const { createPage } = useProjectPages(); // derived values const { access, description_html, name, isContentEditable } = page; - // editor markings hook - const { markings, updateMarkings } = useEditorMarkings(); + // update query params const { updateQueryParams } = useQueryParams(); @@ -123,7 +122,6 @@ export const PageRoot = observer((props: TPageRootProps) => { editorRef={editorRef} handleDuplicatePage={handleDuplicatePage} hasConnectionFailed={hasConnectionFailed} - markings={markings} page={page} readOnlyEditorReady={readOnlyEditorReady} readOnlyEditorRef={readOnlyEditorRef} @@ -131,15 +129,14 @@ export const PageRoot = observer((props: TPageRootProps) => { sidePeekVisible={sidePeekVisible} /> setHasConnectionFailed(status)} handleEditorReady={(val) => setEditorReady(val)} handleReadOnlyEditorReady={() => setReadOnlyEditorReady(true)} - markings={markings} page={page} readOnlyEditorRef={readOnlyEditorRef} sidePeekVisible={sidePeekVisible} - updateMarkings={updateMarkings} /> ); diff --git a/web/core/components/pages/editor/summary/content-browser.tsx b/web/core/components/pages/editor/summary/content-browser.tsx index 7f7ad405327..21c6097d49c 100644 --- a/web/core/components/pages/editor/summary/content-browser.tsx +++ b/web/core/components/pages/editor/summary/content-browser.tsx @@ -1,15 +1,23 @@ // types +import { useState, useEffect } from "react"; import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/editor"; import { OutlineHeading1, OutlineHeading2, OutlineHeading3 } from "./heading-components"; type Props = { - editorRef: EditorRefApi | EditorReadOnlyRefApi | null; - markings: IMarking[]; + editorRef: EditorRefApi & EditorReadOnlyRefApi; setSidePeekVisible?: (sidePeekState: boolean) => void; }; export const PageContentBrowser: React.FC = (props) => { - const { editorRef, markings, setSidePeekVisible } = props; + const { editorRef, setSidePeekVisible } = props; + const [headings, setHeadings] = useState([]); + + useEffect(() => { + const unsubscribe = editorRef?.onHeadingChange(setHeadings); + return () => { + if (unsubscribe) unsubscribe(); + }; + }, [editorRef]); const handleOnClick = (marking: IMarking) => { editorRef?.scrollSummary(marking); @@ -27,8 +35,8 @@ export const PageContentBrowser: React.FC = (props) => { return (
- {markings.length !== 0 ? ( - markings.map((marking) => { + {headings && headings.length !== 0 ? ( + headings.map((marking) => { const Component = HeadingComponent[marking.level]; if (!Component) return null; return ( diff --git a/web/core/components/pages/editor/summary/popover.tsx b/web/core/components/pages/editor/summary/popover.tsx index ccb6b7b8c39..2bcfc053971 100644 --- a/web/core/components/pages/editor/summary/popover.tsx +++ b/web/core/components/pages/editor/summary/popover.tsx @@ -2,22 +2,21 @@ import { useState } from "react"; import { usePopper } from "react-popper"; import { List } from "lucide-react"; // document editor -import { EditorReadOnlyRefApi, EditorRefApi, IMarking } from "@plane/editor"; +import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor"; // helpers import { cn } from "@/helpers/common.helper"; // components import { PageContentBrowser } from "./content-browser"; type Props = { - editorRef: EditorRefApi | EditorReadOnlyRefApi | null; + editorRef: EditorRefApi & EditorReadOnlyRefApi; isFullWidth: boolean; - markings: IMarking[]; sidePeekVisible: boolean; setSidePeekVisible: (sidePeekState: boolean) => void; }; export const PageSummaryPopover: React.FC = (props) => { - const { editorRef, markings, sidePeekVisible, setSidePeekVisible } = props; + const { editorRef, sidePeekVisible, setSidePeekVisible } = props; // refs const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState(null); @@ -54,7 +53,7 @@ export const PageSummaryPopover: React.FC = (props) => { style={summaryPopoverStyles.popper} {...summaryPopoverAttributes.popper} > - +
)}
@@ -66,7 +65,7 @@ export const PageSummaryPopover: React.FC = (props) => { style={summaryPopoverStyles.popper} {...summaryPopoverAttributes.popper} > - +
)} From 2ae3eec9aa119afe65770d2f05bde537e8ba9473 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Thu, 12 Sep 2024 20:57:23 +0530 Subject: [PATCH 4/6] chore: add read-only editor support --- .../core/extensions/read-only-extensions.tsx | 2 ++ .../src/core/hooks/use-read-only-editor.ts | 12 +++++++ packages/editor/src/core/types/editor.ts | 2 +- .../components/pages/editor/header/root.tsx | 32 +++++++++---------- .../pages/editor/summary/content-browser.tsx | 6 ++-- .../pages/editor/summary/popover.tsx | 2 +- 6 files changed, 36 insertions(+), 20 deletions(-) diff --git a/packages/editor/src/core/extensions/read-only-extensions.tsx b/packages/editor/src/core/extensions/read-only-extensions.tsx index 68e3f7d6888..94e37ddc490 100644 --- a/packages/editor/src/core/extensions/read-only-extensions.tsx +++ b/packages/editor/src/core/extensions/read-only-extensions.tsx @@ -19,6 +19,7 @@ import { TableRow, Table, CustomMention, + HeadingListExtension, } from "@/extensions"; // helpers import { isValidHttpUrl } from "@/helpers/common"; @@ -106,4 +107,5 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: { readonly: true, }), CharacterCount, + HeadingListExtension, ]; diff --git a/packages/editor/src/core/hooks/use-read-only-editor.ts b/packages/editor/src/core/hooks/use-read-only-editor.ts index b6081a51032..27ebe5c6460 100644 --- a/packages/editor/src/core/hooks/use-read-only-editor.ts +++ b/packages/editor/src/core/hooks/use-read-only-editor.ts @@ -89,6 +89,18 @@ export const useReadOnlyEditor = ({ words: editorRef?.current?.storage?.characterCount?.words?.() ?? 0, }; }, + onHeadingChange: (callback: (headings: IMarking[]) => void) => { + // Subscribe to update event emitted from headers extension + editorRef.current?.on("update", () => { + callback(editorRef.current?.storage.headingList.headings); + }); + // Return a function to unsubscribe to the continuous transactions of + // the editor on unmounting the component that has subscribed to this + // method + return () => { + editorRef.current?.off("update"); + }; + }, })); if (!editor) { diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 453bf587025..3e317169f65 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -25,6 +25,7 @@ export type EditorReadOnlyRefApi = { paragraphs: number; words: number; }; + onHeadingChange: (callback: (headings: IMarking[]) => void) => () => void; }; export interface EditorRefApi extends EditorReadOnlyRefApi { @@ -32,7 +33,6 @@ export interface EditorRefApi extends EditorReadOnlyRefApi { executeMenuItemCommand: (itemKey: TEditorCommands) => void; isMenuItemActive: (itemKey: TEditorCommands) => boolean; onStateChange: (callback: () => void) => () => void; - onHeadingChange: (callback: (headings: IMarking[]) => void) => () => void; setFocusAtPosition: (position: number) => void; isEditorReadyToDiscard: () => boolean; getSelectedText: () => string | null; diff --git a/web/core/components/pages/editor/header/root.tsx b/web/core/components/pages/editor/header/root.tsx index c8a4774dac9..bdac23822ba 100644 --- a/web/core/components/pages/editor/header/root.tsx +++ b/web/core/components/pages/editor/header/root.tsx @@ -45,23 +45,23 @@ export const PageEditorHeaderRoot: React.FC = observer((props) => { <>
+ {(editorReady || readOnlyEditorReady) && ( +
+ +
+ )} {(editorReady || readOnlyEditorReady) && isContentEditable && editorRef.current && ( - <> -
- -
- - + )}
void; }; export const PageContentBrowser: React.FC = (props) => { const { editorRef, setSidePeekVisible } = props; + // states const [headings, setHeadings] = useState([]); useEffect(() => { diff --git a/web/core/components/pages/editor/summary/popover.tsx b/web/core/components/pages/editor/summary/popover.tsx index 2bcfc053971..5d14234f037 100644 --- a/web/core/components/pages/editor/summary/popover.tsx +++ b/web/core/components/pages/editor/summary/popover.tsx @@ -9,7 +9,7 @@ import { cn } from "@/helpers/common.helper"; import { PageContentBrowser } from "./content-browser"; type Props = { - editorRef: EditorRefApi & EditorReadOnlyRefApi; + editorRef: EditorRefApi | EditorReadOnlyRefApi | null; isFullWidth: boolean; sidePeekVisible: boolean; setSidePeekVisible: (sidePeekState: boolean) => void; From 0814beedc75b7528da0122c9524e8806ac74309d Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Thu, 19 Sep 2024 18:31:48 +0530 Subject: [PATCH 5/6] fix: headings show on initial render --- packages/editor/src/core/components/menus/menu-items.ts | 2 +- packages/editor/src/core/hooks/use-editor.ts | 3 +++ packages/editor/src/core/hooks/use-read-only-editor.ts | 3 +++ web/core/components/pages/editor/summary/content-browser.tsx | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/core/components/menus/menu-items.ts b/packages/editor/src/core/components/menus/menu-items.ts index 60db11704d4..b6f0c37db70 100644 --- a/packages/editor/src/core/components/menus/menu-items.ts +++ b/packages/editor/src/core/components/menus/menu-items.ts @@ -193,7 +193,7 @@ export const ImageItem = (editor: Editor, uploadFile: UploadImage) => ({ key: "image", name: "Image", - isActive: () => editor?.isActive("image"), + isActive: () => editor?.isActive("image") || editor?.isActive("imageComponent"), command: (savedSelection: Selection | null) => insertImageCommand(editor, uploadFile, savedSelection), icon: ImageIcon, }) as const; diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index 6623b0c1b9f..dd3dac8142e 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -165,6 +165,9 @@ export const useEditor = (props: CustomEditorProps) => { editorRef.current?.off("update"); }; }, + getHeadings: () => { + return editorRef?.current?.storage.headingList.headings; + }, onStateChange: (callback: () => void) => { // Subscribe to editor state changes editorRef.current?.on("transaction", () => { diff --git a/packages/editor/src/core/hooks/use-read-only-editor.ts b/packages/editor/src/core/hooks/use-read-only-editor.ts index 27ebe5c6460..6892848459f 100644 --- a/packages/editor/src/core/hooks/use-read-only-editor.ts +++ b/packages/editor/src/core/hooks/use-read-only-editor.ts @@ -101,6 +101,9 @@ export const useReadOnlyEditor = ({ editorRef.current?.off("update"); }; }, + getHeadings: () => { + return editorRef?.current?.storage.headingList.headings; + }, })); if (!editor) { diff --git a/web/core/components/pages/editor/summary/content-browser.tsx b/web/core/components/pages/editor/summary/content-browser.tsx index 5f40e29178e..669d2e978c8 100644 --- a/web/core/components/pages/editor/summary/content-browser.tsx +++ b/web/core/components/pages/editor/summary/content-browser.tsx @@ -16,6 +16,8 @@ export const PageContentBrowser: React.FC = (props) => { useEffect(() => { const unsubscribe = editorRef?.onHeadingChange(setHeadings); + // for initial render of this component to get the editor headings + setHeadings(editorRef?.getHeadings() ?? []); return () => { if (unsubscribe) unsubscribe(); }; From 36c096a69be408266d8d40dfb09f699fbafbae65 Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Thu, 19 Sep 2024 20:34:27 +0530 Subject: [PATCH 6/6] fix: types and imports --- packages/editor/src/core/extensions/drop.tsx | 4 ++-- packages/editor/src/core/extensions/headers.ts | 2 +- .../src/core/extensions/table/table/utilities/create-cell.ts | 2 +- .../extensions/table/table/utilities/get-table-node-types.ts | 2 +- packages/editor/src/core/types/editor.ts | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/core/extensions/drop.tsx b/packages/editor/src/core/extensions/drop.tsx index 943ab60d46f..2b616dc4c09 100644 --- a/packages/editor/src/core/extensions/drop.tsx +++ b/packages/editor/src/core/extensions/drop.tsx @@ -1,6 +1,6 @@ import { Extension } from "@tiptap/core"; -import { Plugin, PluginKey } from "prosemirror-state"; -import { EditorView } from "prosemirror-view"; +import { Plugin, PluginKey } from "@tiptap/pm/state"; +import { EditorView } from "@tiptap/pm/view"; export const DropHandlerExtension = () => Extension.create({ diff --git a/packages/editor/src/core/extensions/headers.ts b/packages/editor/src/core/extensions/headers.ts index c88b53638de..3960d5f039c 100644 --- a/packages/editor/src/core/extensions/headers.ts +++ b/packages/editor/src/core/extensions/headers.ts @@ -1,5 +1,5 @@ import { Extension } from "@tiptap/core"; -import { Plugin, PluginKey } from "prosemirror-state"; +import { Plugin, PluginKey } from "@tiptap/pm/state"; export interface IMarking { type: "heading"; diff --git a/packages/editor/src/core/extensions/table/table/utilities/create-cell.ts b/packages/editor/src/core/extensions/table/table/utilities/create-cell.ts index 5fc2b146d06..684a6d344d3 100644 --- a/packages/editor/src/core/extensions/table/table/utilities/create-cell.ts +++ b/packages/editor/src/core/extensions/table/table/utilities/create-cell.ts @@ -1,4 +1,4 @@ -import { Fragment, Node as ProsemirrorNode, NodeType } from "prosemirror-model"; +import { Fragment, Node as ProsemirrorNode, NodeType } from "@tiptap/pm/model"; export function createCell( cellType: NodeType, diff --git a/packages/editor/src/core/extensions/table/table/utilities/get-table-node-types.ts b/packages/editor/src/core/extensions/table/table/utilities/get-table-node-types.ts index 28c322a1f1f..5722c4cae2c 100644 --- a/packages/editor/src/core/extensions/table/table/utilities/get-table-node-types.ts +++ b/packages/editor/src/core/extensions/table/table/utilities/get-table-node-types.ts @@ -1,4 +1,4 @@ -import { NodeType, Schema } from "prosemirror-model"; +import { NodeType, Schema } from "@tiptap/pm/model"; export function getTableNodeTypes(schema: Schema): { [key: string]: NodeType } { if (schema.cached.tableNodeTypes) { diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 3e317169f65..c89771e1514 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -26,6 +26,7 @@ export type EditorReadOnlyRefApi = { words: number; }; onHeadingChange: (callback: (headings: IMarking[]) => void) => () => void; + getHeadings: () => IMarking[]; }; export interface EditorRefApi extends EditorReadOnlyRefApi {