From f9d6ae9ea4c2f00a415fb86c4110da0be8c59a87 Mon Sep 17 00:00:00 2001 From: Lakhan Baheti Date: Tue, 22 Jul 2025 16:38:56 +0530 Subject: [PATCH 1/5] chore: misc editor updated and utility functions --- .../editors/document/collaborative-editor.tsx | 31 ++++++++---- .../editors/document/page-renderer.tsx | 4 +- .../editors/document/read-only-editor.tsx | 2 + .../components/editors/rich-text/editor.tsx | 2 +- .../src/core/components/menus/menu-items.ts | 19 +++++++- .../custom-image/components/node-view.tsx | 6 +-- .../src/core/helpers/editor-commands.ts | 16 ++++++- .../core/hooks/use-collaborative-editor.ts | 5 +- packages/editor/src/core/hooks/use-editor.ts | 47 ++++++++++++++++++- packages/editor/src/core/types/config.ts | 4 +- packages/editor/src/core/types/editor.ts | 34 ++++++++++++-- packages/editor/src/core/types/hook.ts | 16 ++++--- packages/editor/src/styles/variables.css | 43 +++++++++++++++++ 13 files changed, 199 insertions(+), 30 deletions(-) diff --git a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx index 1d099fe3f74..c71219bf45b 100644 --- a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx +++ b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx @@ -1,5 +1,5 @@ import { Extensions } from "@tiptap/core"; -import React from "react"; +import React, { useMemo } from "react"; // plane imports import { cn } from "@plane/utils"; // components @@ -20,20 +20,25 @@ const CollaborativeDocumentEditor: React.FC = aiHandler, bubbleMenuEnabled = true, containerClassName, + documentLoaderClassName, + extensions: externalExtensions = [], disabledExtensions, displayConfig = DEFAULT_DISPLAY_CONFIG, editable, editorClassName = "", + editorProps, embedHandler, fileHandler, flaggedExtensions, forwardedRef, handleEditorReady, id, + dragDropEnabled = true, isTouchDevice, mentionHandler, onAssetChange, onChange, + onEditorFocus, onTransaction, placeholder, realtimeConfig, @@ -42,21 +47,26 @@ const CollaborativeDocumentEditor: React.FC = user, } = props; - const extensions: Extensions = []; + const extensions: Extensions = useMemo(() => { + const allExtensions = externalExtensions; - if (embedHandler?.issue) { - extensions.push( - WorkItemEmbedExtension({ - widgetCallback: embedHandler.issue.widgetCallback, - }) - ); - } + if (embedHandler?.issue) { + allExtensions.push( + WorkItemEmbedExtension({ + widgetCallback: embedHandler.issue.widgetCallback, + }) + ); + } + + return allExtensions; + }, [externalExtensions, embedHandler.issue]); // use document editor const { editor, hasServerConnectionFailed, hasServerSynced } = useCollaborativeEditor({ disabledExtensions, editable, editorClassName, + editorProps, embedHandler, extensions, fileHandler, @@ -64,10 +74,12 @@ const CollaborativeDocumentEditor: React.FC = forwardedRef, handleEditorReady, id, + dragDropEnabled, isTouchDevice, mentionHandler, onAssetChange, onChange, + onEditorFocus, onTransaction, placeholder, realtimeConfig, @@ -89,6 +101,7 @@ const CollaborativeDocumentEditor: React.FC = aiHandler={aiHandler} bubbleMenuEnabled={bubbleMenuEnabled} displayConfig={displayConfig} + documentLoaderClassName={documentLoaderClassName} editor={editor} editorContainerClassName={cn(editorContainerClassNames, "document-editor")} id={id} diff --git a/packages/editor/src/core/components/editors/document/page-renderer.tsx b/packages/editor/src/core/components/editors/document/page-renderer.tsx index 8a82ebaf99a..266476788c1 100644 --- a/packages/editor/src/core/components/editors/document/page-renderer.tsx +++ b/packages/editor/src/core/components/editors/document/page-renderer.tsx @@ -11,6 +11,7 @@ type Props = { aiHandler?: TAIHandler; bubbleMenuEnabled: boolean; displayConfig: TDisplayConfig; + documentLoaderClassName?: string; editor: Editor; editorContainerClassName: string; id: string; @@ -24,6 +25,7 @@ export const PageRenderer = (props: Props) => { aiHandler, bubbleMenuEnabled, displayConfig, + documentLoaderClassName, editor, editorContainerClassName, id, @@ -39,7 +41,7 @@ export const PageRenderer = (props: Props) => { })} > {isLoading ? ( - + ) : ( = (props) = containerClassName, disabledExtensions, displayConfig = DEFAULT_DISPLAY_CONFIG, + documentLoaderClassName, editorClassName = "", embedHandler, fileHandler, @@ -62,6 +63,7 @@ const DocumentReadOnlyEditor: React.FC = (props) = = (props) => { ]; return extensions; - }, [dragDropEnabled, disabledExtensions, externalExtensions, fileHandler, flaggedExtensions]); + }, [dragDropEnabled, disabledExtensions, externalExtensions, fileHandler, flaggedExtensions, isTouchDevice]); return ( diff --git a/packages/editor/src/core/components/menus/menu-items.ts b/packages/editor/src/core/components/menus/menu-items.ts index c3aa4d414a7..cfa1213c1a1 100644 --- a/packages/editor/src/core/components/menus/menu-items.ts +++ b/packages/editor/src/core/components/menus/menu-items.ts @@ -22,6 +22,7 @@ import { MinusSquare, Palette, AlignCenter, + LinkIcon, } from "lucide-react"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; @@ -30,6 +31,7 @@ import { insertHorizontalRule, insertImage, insertTableCommand, + setLinkEditor, setText, setTextAlign, toggleBackgroundColor, @@ -44,6 +46,7 @@ import { toggleTaskList, toggleTextColor, toggleUnderline, + unsetLinkEditor, } from "@/helpers/editor-commands"; // types import { TCommandWithProps, TEditorCommands } from "@/types"; @@ -189,7 +192,7 @@ export const ImageItem = (editor: Editor): EditorMenuItem<"image"> => ({ icon: ImageIcon, }); -export const HorizontalRuleItem = (editor: Editor) => +export const HorizontalRuleItem = (editor: Editor): EditorMenuItem<"divider"> => ({ key: "divider", name: "Divider", @@ -198,6 +201,19 @@ export const HorizontalRuleItem = (editor: Editor) => icon: MinusSquare, }) as const; +export const LinkItem = (editor: Editor): EditorMenuItem<"link"> => + ({ + key: "link", + name: "Link", + isActive: () => editor?.isActive("link"), + command: (props) => { + if (!props) return; + if (props.url) setLinkEditor(editor, props.url, props.text); + else unsetLinkEditor(editor); + }, + icon: LinkIcon, + }) as const; + export const TextColorItem = (editor: Editor): EditorMenuItem<"text-color"> => ({ key: "text-color", name: "Color", @@ -254,6 +270,7 @@ export const getEditorMenuItems = (editor: Editor | null): EditorMenuItem = (props) = const { editor, extension, node } = props; const { src: imgNodeSrc } = node.attrs; - const [isUploaded, setIsUploaded] = useState(false); + const [isUploaded, setIsUploaded] = useState(!!imgNodeSrc); const [resolvedSrc, setResolvedSrc] = useState(undefined); const [resolvedDownloadSrc, setResolvedDownloadSrc] = useState(undefined); const [imageFromFileSystem, setImageFromFileSystem] = useState(undefined); @@ -43,13 +43,13 @@ export const CustomImageNodeView: React.FC = (props) = // the image is already uploaded if the image-component node has src attribute // and we need to remove the blob from our file system useEffect(() => { - if (resolvedSrc) { + if (resolvedSrc || imgNodeSrc) { setIsUploaded(true); setImageFromFileSystem(undefined); } else { setIsUploaded(false); } - }, [resolvedSrc]); + }, [resolvedSrc, imgNodeSrc]); useEffect(() => { if (!imgNodeSrc) { diff --git a/packages/editor/src/core/helpers/editor-commands.ts b/packages/editor/src/core/helpers/editor-commands.ts index 43543d57539..6afe772def3 100644 --- a/packages/editor/src/core/helpers/editor-commands.ts +++ b/packages/editor/src/core/helpers/editor-commands.ts @@ -138,7 +138,21 @@ export const unsetLinkEditor = (editor: Editor) => { editor.chain().focus().unsetLink().run(); }; -export const setLinkEditor = (editor: Editor, url: string) => { +export const setLinkEditor = (editor: Editor, url: string, text?: string) => { + const { selection } = editor.state; + const previousSelection = { from: selection.from, to: selection.to }; + if (text) { + editor + .chain() + .focus() + .deleteRange({ from: selection.from, to: selection.to }) + .insertContentAt(previousSelection.from, text) + .run(); + // Extracting the new selection start point. + const previousFrom = previousSelection.from; + + editor.commands.setTextSelection({ from: previousFrom, to: previousFrom + text.length }); + } editor.chain().focus().setLink({ href: url }).run(); }; diff --git a/packages/editor/src/core/hooks/use-collaborative-editor.ts b/packages/editor/src/core/hooks/use-collaborative-editor.ts index 369e89f6791..2c0274f349b 100644 --- a/packages/editor/src/core/hooks/use-collaborative-editor.ts +++ b/packages/editor/src/core/hooks/use-collaborative-editor.ts @@ -27,8 +27,10 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) => forwardedRef, handleEditorReady, id, + dragDropEnabled = true, isTouchDevice, mentionHandler, + onEditorFocus, placeholder, realtimeConfig, serverHandler, @@ -87,7 +89,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) => extensions: [ SideMenuExtension({ aiEnabled: !disabledExtensions?.includes("ai"), - dragDropEnabled: true, + dragDropEnabled: dragDropEnabled, }), HeadingListExtension, Collaboration.configure({ @@ -112,6 +114,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) => mentionHandler, onAssetChange, onChange, + onEditorFocus, onTransaction, placeholder, provider, diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index 377c07013a6..d35b53ca855 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -38,6 +38,7 @@ export const useEditor = (props: TEditorHookProps) => { mentionHandler, onAssetChange, onChange, + onEditorFocus, onTransaction, placeholder, provider, @@ -79,6 +80,7 @@ export const useEditor = (props: TEditorHookProps) => { }, onUpdate: ({ editor }) => onChange?.(editor.getJSON(), editor.getHTML()), onDestroy: () => handleEditorReady?.(false), + onFocus: onEditorFocus, }, [editable] ); @@ -131,6 +133,39 @@ export const useEditor = (props: TEditorHookProps) => { () => ({ ...getEditorRefHelpers({ editor, provider }), blur: () => editor?.commands.blur(), + createSelectionAtCursorPosition: () => { + if (!editor) return; + const { empty } = editor.state.selection; + + // if (empty) return null; + if (empty) { + // Get the text content and position info + const { $from } = editor.state.selection; + const textContent = $from.parent.textContent; + const posInNode = $from.parentOffset; + + // Find word boundaries + let start = posInNode; + let end = posInNode; + + // Move start position backwards until we hit a word boundary + while (start > 0 && /\w/.test(textContent[start - 1])) { + start--; + } + + // Move end position forwards until we hit a word boundary + while (end < textContent.length && /\w/.test(textContent[end])) { + end++; + } + + // If we found a word, select it using editor commands + if (start !== end) { + const from = $from.start() + start; + const to = $from.start() + end; + editor.commands.setTextSelection({ from, to }); + } + } + }, emitRealTimeUpdate: (message) => provider?.sendStateless(message), executeMenuItemCommand: (props) => { const { itemKey } = props; @@ -145,7 +180,15 @@ export const useEditor = (props: TEditorHookProps) => { console.warn(`No command found for item: ${itemKey}`); } }, + focus: ({ position = "start", scrollIntoView = false }) => editor?.commands.focus(position, { scrollIntoView }), + getCordsFromPos: (pos?: number) => editor?.view.coordsAtPos(pos ?? editor.state.selection.from), getCurrentCursorPosition: () => editor?.state.selection.from, + getSelectedNodeAttributes: (attribute) => { + if (!editor) return; + editor.commands.extendMarkRange("link"); + return editor.getAttributes(attribute); + }, + getSelectedText: () => { if (!editor) return null; @@ -240,7 +283,8 @@ export const useEditor = (props: TEditorHookProps) => { editor?.off("transaction", callback); }; }, - scrollToNodeViaDOMCoordinates(behavior, pos) { + redo: () => editor?.commands.redo(), + scrollToNodeViaDOMCoordinates({ pos, behavior = "smooth" }) { const resolvedPos = pos ?? editor?.state.selection.from; if (!editor || !resolvedPos) return; scrollToNodeViaDOMCoordinates(editor, resolvedPos, behavior); @@ -272,6 +316,7 @@ export const useEditor = (props: TEditorHookProps) => { if (!document) return; Y.applyUpdate(document, value); }, + undo: () => editor?.commands.undo(), }), [editor] ); diff --git a/packages/editor/src/core/types/config.ts b/packages/editor/src/core/types/config.ts index 7ef685ad02d..f94f9dbffba 100644 --- a/packages/editor/src/core/types/config.ts +++ b/packages/editor/src/core/types/config.ts @@ -24,9 +24,9 @@ export type TFileHandler = TReadOnlyFileHandler & { export type TEditorFontStyle = "sans-serif" | "serif" | "monospace"; -export type TEditorFontSize = "small-font" | "large-font"; +export type TEditorFontSize = "small-font" | "large-font" | "mobile-font"; -export type TEditorLineSpacing = "regular" | "small"; +export type TEditorLineSpacing = "regular" | "small" | "mobile-regular"; export type TDisplayConfig = { fontStyle?: TEditorFontStyle; diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 994b80bfb34..290a95ed4c4 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -1,5 +1,7 @@ -import { Extensions, JSONContent } from "@tiptap/core"; +import { Extensions, FocusPosition, JSONContent } from "@tiptap/core"; +import { MarkType, NodeType } from "@tiptap/pm/model"; import { Selection } from "@tiptap/pm/state"; +import { EditorProps } from "@tiptap/pm/view"; // extension types import type { TTextAlign } from "@/extensions"; // helpers @@ -42,6 +44,7 @@ export type TEditorCommands = | "table" | "image" | "divider" + | "link" | "issue-embed" | "text-color" | "background-color" @@ -60,6 +63,10 @@ export type TCommandExtraProps = { "text-color": { color: string | undefined; }; + link: { + url: string; + text?: string; + }; "background-color": { color: string | undefined; }; @@ -100,9 +107,20 @@ export type EditorReadOnlyRefApi = { export interface EditorRefApi extends EditorReadOnlyRefApi { blur: () => void; + createSelectionAtCursorPosition: () => void; emitRealTimeUpdate: (action: TDocumentEventsServer) => void; executeMenuItemCommand: (props: TCommandWithPropsWithItemKey) => void; + focus: ({ position, scrollIntoView }: { position?: FocusPosition; scrollIntoView?: boolean }) => void; + getCordsFromPos: (pos?: number) => + | { + left: number; + right: number; + bottom: number; + top: number; + } + | undefined; getCurrentCursorPosition: () => number | undefined; + getSelectedNodeAttributes: (attribute: string | NodeType | MarkType) => Record | undefined; getSelectedText: () => string | null; insertText: (contentHTML: string, insertOnNextLine?: boolean) => void; isEditorReadyToDiscard: () => boolean; @@ -111,11 +129,13 @@ export interface EditorRefApi extends EditorReadOnlyRefApi { onDocumentInfoChange: (callback: (documentInfo: TDocumentInfo) => void) => () => void; onHeadingChange: (callback: (headings: IMarking[]) => void) => () => void; onStateChange: (callback: () => void) => () => void; + redo: () => void; // eslint-disable-next-line no-undef - scrollToNodeViaDOMCoordinates: (behavior?: ScrollBehavior, position?: number) => void; + scrollToNodeViaDOMCoordinates: ({ pos, behavior }: { pos?: number; behavior?: ScrollBehavior }) => void; setEditorValueAtCursorPosition: (content: string) => void; setFocusAtPosition: (position: number) => void; setProviderDocument: (value: Uint8Array) => void; + undo: () => void; } // editor props @@ -126,6 +146,7 @@ export interface IEditorProps { displayConfig?: TDisplayConfig; disabledExtensions: TExtensions[]; editorClassName?: string; + editorProps?: EditorProps; extensions?: Extensions; flaggedExtensions: TExtensions[]; fileHandler: TFileHandler; @@ -136,6 +157,7 @@ export interface IEditorProps { isTouchDevice?: boolean; mentionHandler: TMentionHandler; onAssetChange?: (assets: TEditorAsset[]) => void; + onEditorFocus?: () => void; onChange?: (json: object, html: string) => void; onEnterKeyPress?: (e?: any) => void; onTransaction?: () => void; @@ -152,8 +174,10 @@ export type IRichTextEditorProps = IEditorProps & { }; export interface ICollaborativeDocumentEditorProps - extends Omit { + extends Omit { aiHandler?: TAIHandler; + documentLoaderClassName?: string; + dragDropEnabled?: boolean; editable: boolean; embedHandler: TEmbedConfig; realtimeConfig: TRealtimeConfig; @@ -183,7 +207,9 @@ export interface IReadOnlyEditorProps export type ILiteTextReadOnlyEditorProps = IReadOnlyEditorProps; -export interface IDocumentReadOnlyEditorProps extends IReadOnlyEditorProps { +export interface IDocumentReadOnlyEditorProps + extends IReadOnlyEditorProps, + Pick { embedHandler: TEmbedConfig; } diff --git a/packages/editor/src/core/types/hook.ts b/packages/editor/src/core/types/hook.ts index 568ae5b0e25..e74de406f7c 100644 --- a/packages/editor/src/core/types/hook.ts +++ b/packages/editor/src/core/types/hook.ts @@ -1,14 +1,18 @@ import type { HocuspocusProvider } from "@hocuspocus/provider"; -import type { EditorProps } from "@tiptap/pm/view"; // local imports import type { ICollaborativeDocumentEditorProps, IEditorProps, IReadOnlyEditorProps } from "./editor"; type TCoreHookProps = Pick< IEditorProps, - "disabledExtensions" | "editorClassName" | "extensions" | "flaggedExtensions" | "handleEditorReady" | "isTouchDevice" -> & { - editorProps?: EditorProps; -}; + | "disabledExtensions" + | "editorClassName" + | "editorProps" + | "extensions" + | "flaggedExtensions" + | "handleEditorReady" + | "isTouchDevice" + | "onEditorFocus" +>; export type TEditorHookProps = TCoreHookProps & Pick< @@ -45,7 +49,7 @@ export type TCollaborativeEditorHookProps = TCoreHookProps & | "placeholder" | "tabIndex" > & - Pick; + Pick; export type TReadOnlyEditorHookProps = TCoreHookProps & Pick & diff --git a/packages/editor/src/styles/variables.css b/packages/editor/src/styles/variables.css index f03808c1a15..c7726ce2d37 100644 --- a/packages/editor/src/styles/variables.css +++ b/packages/editor/src/styles/variables.css @@ -88,6 +88,28 @@ --line-height-code: 1.2rem; --line-height-list: var(--line-height-regular); } + + &.mobile-font { + --font-size-h1: 1.75rem; + --font-size-h2: 1.5rem; + --font-size-h3: 1.375rem; + --font-size-h4: 1.25rem; + --font-size-h5: 1.125rem; + --font-size-h6: 1rem; + --font-size-regular: 0.95rem; + --font-size-code: 0.85rem; + --font-size-list: var(--font-size-regular); + + --line-height-h1: 2.25rem; + --line-height-h2: 2rem; + --line-height-h3: 1.75rem; + --line-height-h4: 1.5rem; + --line-height-h5: 1.5rem; + --line-height-h6: 1.5rem; + --line-height-regular: 1.5rem; + --line-height-code: 1.5rem; + --line-height-list: var(--line-height-regular); + } /* end font sizes and line heights */ /* font styles */ @@ -146,6 +168,27 @@ --divider-padding-top: 0px; --divider-padding-bottom: 4px; } + + &.line-spacing-mobile-regular { + --heading-1-padding-top: 16px; + --heading-1-padding-bottom: 4px; + --heading-2-padding-top: 16px; + --heading-2-padding-bottom: 4px; + --heading-3-padding-top: 16px; + --heading-3-padding-bottom: 4px; + --heading-4-padding-top: 16px; + --heading-4-padding-bottom: 4px; + --heading-5-padding-top: 12px; + --heading-5-padding-bottom: 4px; + --heading-6-padding-top: 12px; + --heading-6-padding-bottom: 4px; + --paragraph-padding-top: 2px; + --paragraph-padding-bottom: 2px; + --paragraph-padding-between: 4px; + --list-spacing-y: 0px; + --divider-padding-top: 0px; + --divider-padding-bottom: 4px; + } /* end spacing */ } /* end font size and style */ From 852a6ab5ea72ebb59fc41baccd55dea20f5c3cbf Mon Sep 17 00:00:00 2001 From: Lakhan Baheti Date: Tue, 22 Jul 2025 17:58:13 +0530 Subject: [PATCH 2/5] fix: code review --- packages/editor/src/core/hooks/use-editor.ts | 5 ++--- packages/editor/src/core/types/editor.ts | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index d35b53ca855..0542f47dc9d 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -183,12 +183,11 @@ export const useEditor = (props: TEditorHookProps) => { focus: ({ position = "start", scrollIntoView = false }) => editor?.commands.focus(position, { scrollIntoView }), getCordsFromPos: (pos?: number) => editor?.view.coordsAtPos(pos ?? editor.state.selection.from), getCurrentCursorPosition: () => editor?.state.selection.from, - getSelectedNodeAttributes: (attribute) => { + getAttributesWithExtendedMark: (mark, attribute) => { if (!editor) return; - editor.commands.extendMarkRange("link"); + editor.commands.extendMarkRange(mark); return editor.getAttributes(attribute); }, - getSelectedText: () => { if (!editor) return null; diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 290a95ed4c4..41363554c89 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -120,7 +120,10 @@ export interface EditorRefApi extends EditorReadOnlyRefApi { } | undefined; getCurrentCursorPosition: () => number | undefined; - getSelectedNodeAttributes: (attribute: string | NodeType | MarkType) => Record | undefined; + getAttributesWithExtendedMark: ( + mark: string | MarkType, + attribute: string | NodeType | MarkType + ) => Record | undefined; getSelectedText: () => string | null; insertText: (contentHTML: string, insertOnNextLine?: boolean) => void; isEditorReadyToDiscard: () => boolean; From 706219bde5f41fe2ae04501e9a9c1eb97628fb88 Mon Sep 17 00:00:00 2001 From: Lakhan Baheti Date: Tue, 22 Jul 2025 20:46:19 +0530 Subject: [PATCH 3/5] passed isTouchDevice prop to editor-wrapper --- packages/editor/src/core/components/editors/editor-wrapper.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/editor/src/core/components/editors/editor-wrapper.tsx b/packages/editor/src/core/components/editors/editor-wrapper.tsx index c564883b826..10cfac3a08e 100644 --- a/packages/editor/src/core/components/editors/editor-wrapper.tsx +++ b/packages/editor/src/core/components/editors/editor-wrapper.tsx @@ -51,6 +51,7 @@ export const EditorWrapper: React.FC = (props) => { flaggedExtensions, forwardedRef, id, + isTouchDevice, initialValue, mentionHandler, onChange, From 1b7e99a6c4e5d4cb0b2706463c2633f1f4350b12 Mon Sep 17 00:00:00 2001 From: Lakhan Baheti Date: Wed, 23 Jul 2025 15:46:34 +0530 Subject: [PATCH 4/5] added more props to editor-wrapper. --- .../editor/src/core/components/editors/editor-wrapper.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/editor/src/core/components/editors/editor-wrapper.tsx b/packages/editor/src/core/components/editors/editor-wrapper.tsx index 10cfac3a08e..51c3ea156dd 100644 --- a/packages/editor/src/core/components/editors/editor-wrapper.tsx +++ b/packages/editor/src/core/components/editors/editor-wrapper.tsx @@ -24,6 +24,7 @@ export const EditorWrapper: React.FC = (props) => { displayConfig = DEFAULT_DISPLAY_CONFIG, editable, editorClassName = "", + editorProps, extensions, id, initialValue, @@ -33,6 +34,7 @@ export const EditorWrapper: React.FC = (props) => { forwardedRef, mentionHandler, onChange, + onEditorFocus, onTransaction, handleEditorReady, autofocus, @@ -45,6 +47,7 @@ export const EditorWrapper: React.FC = (props) => { editable, disabledExtensions, editorClassName, + editorProps, enableHistory: true, extensions, fileHandler, @@ -55,6 +58,7 @@ export const EditorWrapper: React.FC = (props) => { initialValue, mentionHandler, onChange, + onEditorFocus, onTransaction, handleEditorReady, autofocus, From 66da1a1a855401f3f1cd8c9ee913e20f7243c10f Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Tue, 29 Jul 2025 13:23:47 +0530 Subject: [PATCH 5/5] chore: update types --- .../editors/document/collaborative-editor.tsx | 4 ++-- .../core/hooks/use-collaborative-editor.ts | 2 +- packages/editor/src/core/hooks/use-editor.ts | 4 ++-- packages/editor/src/core/types/editor.ts | 21 +++++++------------ 4 files changed, 12 insertions(+), 19 deletions(-) diff --git a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx index c71219bf45b..8b67bf824b2 100644 --- a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx +++ b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx @@ -1,4 +1,4 @@ -import { Extensions } from "@tiptap/core"; +import type { Extensions } from "@tiptap/core"; import React, { useMemo } from "react"; // plane imports import { cn } from "@plane/utils"; @@ -13,7 +13,7 @@ import { getEditorClassNames } from "@/helpers/common"; // hooks import { useCollaborativeEditor } from "@/hooks/use-collaborative-editor"; // types -import { EditorRefApi, ICollaborativeDocumentEditorProps } from "@/types"; +import type { EditorRefApi, ICollaborativeDocumentEditorProps } from "@/types"; const CollaborativeDocumentEditor: React.FC = (props) => { const { diff --git a/packages/editor/src/core/hooks/use-collaborative-editor.ts b/packages/editor/src/core/hooks/use-collaborative-editor.ts index fbae7aaa0ec..55c1fa3727d 100644 --- a/packages/editor/src/core/hooks/use-collaborative-editor.ts +++ b/packages/editor/src/core/hooks/use-collaborative-editor.ts @@ -89,7 +89,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) => extensions: [ SideMenuExtension({ aiEnabled: !disabledExtensions?.includes("ai"), - dragDropEnabled: dragDropEnabled, + dragDropEnabled, }), HeadingListExtension, Collaboration.configure({ diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index 0542f47dc9d..b3da950ea7c 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -180,8 +180,8 @@ export const useEditor = (props: TEditorHookProps) => { console.warn(`No command found for item: ${itemKey}`); } }, - focus: ({ position = "start", scrollIntoView = false }) => editor?.commands.focus(position, { scrollIntoView }), - getCordsFromPos: (pos?: number) => editor?.view.coordsAtPos(pos ?? editor.state.selection.from), + focus: (args) => editor?.commands.focus(args), + getCoordsFromPos: (pos) => editor?.view.coordsAtPos(pos ?? editor.state.selection.from), getCurrentCursorPosition: () => editor?.state.selection.from, getAttributesWithExtendedMark: (mark, attribute) => { if (!editor) return; diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 41363554c89..0461dd4b807 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -1,7 +1,7 @@ -import { Extensions, FocusPosition, JSONContent } from "@tiptap/core"; -import { MarkType, NodeType } from "@tiptap/pm/model"; -import { Selection } from "@tiptap/pm/state"; -import { EditorProps } from "@tiptap/pm/view"; +import type { Extensions, JSONContent, RawCommands } from "@tiptap/core"; +import type { MarkType, NodeType } from "@tiptap/pm/model"; +import type { Selection } from "@tiptap/pm/state"; +import type { EditorProps, EditorView } from "@tiptap/pm/view"; // extension types import type { TTextAlign } from "@/extensions"; // helpers @@ -110,20 +110,13 @@ export interface EditorRefApi extends EditorReadOnlyRefApi { createSelectionAtCursorPosition: () => void; emitRealTimeUpdate: (action: TDocumentEventsServer) => void; executeMenuItemCommand: (props: TCommandWithPropsWithItemKey) => void; - focus: ({ position, scrollIntoView }: { position?: FocusPosition; scrollIntoView?: boolean }) => void; - getCordsFromPos: (pos?: number) => - | { - left: number; - right: number; - bottom: number; - top: number; - } - | undefined; - getCurrentCursorPosition: () => number | undefined; + focus: (args: Parameters[0]) => void; getAttributesWithExtendedMark: ( mark: string | MarkType, attribute: string | NodeType | MarkType ) => Record | undefined; + getCoordsFromPos: (pos?: number) => ReturnType | undefined; + getCurrentCursorPosition: () => number | undefined; getSelectedText: () => string | null; insertText: (contentHTML: string, insertOnNextLine?: boolean) => void; isEditorReadyToDiscard: () => boolean;