From 0fe7da62655d58dfe66512d2394ce996cd6ed334 Mon Sep 17 00:00:00 2001 From: Vipin Chaudhary Date: Tue, 26 Aug 2025 02:23:50 +0530 Subject: [PATCH] [WIKI-345] chore: pass disabled and flagged extensions to block menu (#7152) * chore: refactor editor * sync changes * feat: api service update * refactor : update sync * fix : package sync * fix: requested changes * fix : embedhandler type * fix : remove commands * refactor : space * refactor : rich lite editors * refactor : minor ce changes * chore : minor ui fix * package: tldjs * refactor : remove tldjs * refactor: flagged * refactor: flagged * chore : remove disbaled check in menu * refactor: fix space * refactor: NodeViewProps * refactor: type * refactor : update community types * refactor : remove external embed CE * remove : external embed config from ce * refactor : update disabled * chore: pass disabled * chore : update utils --- apps/live/src/core/services/api.service.ts | 1 + apps/space/helpers/string.helper.ts | 2 +- apps/web/core/components/editor/lite-text/editor.tsx | 4 ++-- .../core/components/editor/sticky-editor/editor.tsx | 1 - apps/web/next.config.js | 2 +- .../editors/document/collaborative-editor.tsx | 2 ++ .../src/core/components/editors/document/editor.tsx | 3 +++ .../components/editors/document/page-renderer.tsx | 12 ++++++++++-- .../src/core/components/editors/editor-wrapper.tsx | 2 ++ .../core/components/editors/link-view-container.tsx | 6 +++++- .../editor/src/core/components/menus/block-menu.tsx | 3 +++ .../src/core/extensions/custom-link/extension.tsx | 1 + packages/editor/src/core/extensions/extensions.ts | 6 +++++- .../src/core/hooks/use-collaborative-editor.ts | 1 + packages/editor/src/core/hooks/use-editor.ts | 2 ++ packages/editor/src/core/plugins/drag-handle.ts | 6 ++++++ packages/editor/src/core/types/editor.ts | 7 ++++++- packages/editor/src/core/types/hook.ts | 1 + packages/utils/src/string.ts | 2 +- 19 files changed, 53 insertions(+), 11 deletions(-) diff --git a/apps/live/src/core/services/api.service.ts b/apps/live/src/core/services/api.service.ts index abc53c111..dbef2ae17 100644 --- a/apps/live/src/core/services/api.service.ts +++ b/apps/live/src/core/services/api.service.ts @@ -14,6 +14,7 @@ export abstract class APIService { this.axiosInstance = axios.create({ baseURL, withCredentials: true, + timeout: 20000, }); } diff --git a/apps/space/helpers/string.helper.ts b/apps/space/helpers/string.helper.ts index 2f4e48ab0..cd086300c 100644 --- a/apps/space/helpers/string.helper.ts +++ b/apps/space/helpers/string.helper.ts @@ -71,7 +71,7 @@ export const isCommentEmpty = (comment: string | undefined): boolean => { return ( comment?.trim() === "" || comment === "

" || - isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component"]) + isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component", "embed-component"]) ); }; diff --git a/apps/web/core/components/editor/lite-text/editor.tsx b/apps/web/core/components/editor/lite-text/editor.tsx index 5f4d28203..feb99ea6e 100644 --- a/apps/web/core/components/editor/lite-text/editor.tsx +++ b/apps/web/core/components/editor/lite-text/editor.tsx @@ -1,6 +1,7 @@ import React, { useState } from "react"; -// plane imports +// plane constants import { EIssueCommentAccessSpecifier } from "@plane/constants"; +// plane imports import { type EditorRefApi, type ILiteTextEditorProps, LiteTextEditorWithRef, type TFileHandler } from "@plane/editor"; import { useTranslation } from "@plane/i18n"; import type { MakeOptional } from "@plane/types"; @@ -87,7 +88,6 @@ export const LiteTextEditor = React.forwardRef(ref) ? ref.current : null; - return (
(ref) ? ref.current : null; - return (
= isTouchDevice={!!isTouchDevice} isLoading={!hasServerSynced && !hasServerConnectionFailed} tabIndex={tabIndex} + flaggedExtensions={flaggedExtensions} + disabledExtensions={disabledExtensions} /> ); }; diff --git a/packages/editor/src/core/components/editors/document/editor.tsx b/packages/editor/src/core/components/editors/document/editor.tsx index bf27c48e3..85285adea 100644 --- a/packages/editor/src/core/components/editors/document/editor.tsx +++ b/packages/editor/src/core/components/editors/document/editor.tsx @@ -82,6 +82,7 @@ const DocumentEditor = (props: IDocumentEditorProps) => { initialValue: value, mentionHandler, onChange, + embedHandler, }); const editorContainerClassName = getEditorClassNames({ @@ -98,6 +99,8 @@ const DocumentEditor = (props: IDocumentEditorProps) => { editorContainerClassName={cn(editorContainerClassName, "document-editor")} id={id} isTouchDevice={!!isTouchDevice} + flaggedExtensions={flaggedExtensions} + disabledExtensions={disabledExtensions} /> ); }; 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 266476788..7a628b3b2 100644 --- a/packages/editor/src/core/components/editors/document/page-renderer.tsx +++ b/packages/editor/src/core/components/editors/document/page-renderer.tsx @@ -5,7 +5,7 @@ import { cn } from "@plane/utils"; import { DocumentContentLoader, EditorContainer, EditorContentWrapper } from "@/components/editors"; import { AIFeaturesMenu, BlockMenu, EditorBubbleMenu } from "@/components/menus"; // types -import { TAIHandler, TDisplayConfig } from "@/types"; +import { IEditorProps, TAIHandler, TDisplayConfig } from "@/types"; type Props = { aiHandler?: TAIHandler; @@ -18,6 +18,8 @@ type Props = { isLoading?: boolean; isTouchDevice: boolean; tabIndex?: number; + flaggedExtensions?: IEditorProps["flaggedExtensions"]; + disabledExtensions?: IEditorProps["disabledExtensions"]; }; export const PageRenderer = (props: Props) => { @@ -32,6 +34,8 @@ export const PageRenderer = (props: Props) => { isLoading, isTouchDevice, tabIndex, + flaggedExtensions, + disabledExtensions, } = props; return ( @@ -54,7 +58,11 @@ export const PageRenderer = (props: Props) => { {editor.isEditable && !isTouchDevice && (
{bubbleMenuEnabled && } - +
)} diff --git a/packages/editor/src/core/components/editors/editor-wrapper.tsx b/packages/editor/src/core/components/editors/editor-wrapper.tsx index 51c3ea156..7de71bf6f 100644 --- a/packages/editor/src/core/components/editors/editor-wrapper.tsx +++ b/packages/editor/src/core/components/editors/editor-wrapper.tsx @@ -41,6 +41,7 @@ export const EditorWrapper: React.FC = (props) => { placeholder, tabIndex, value, + embedHandler, } = props; const editor = useEditor({ @@ -65,6 +66,7 @@ export const EditorWrapper: React.FC = (props) => { placeholder, tabIndex, value, + embedHandler, }); const editorContainerClassName = getEditorClassNames({ diff --git a/packages/editor/src/core/components/editors/link-view-container.tsx b/packages/editor/src/core/components/editors/link-view-container.tsx index c686c33ab..5e839830e 100644 --- a/packages/editor/src/core/components/editors/link-view-container.tsx +++ b/packages/editor/src/core/components/editors/link-view-container.tsx @@ -1,8 +1,12 @@ import { autoUpdate, flip, hide, shift, useDismiss, useFloating, useInteractions } from "@floating-ui/react"; import { Editor, useEditorState } from "@tiptap/react"; import { FC, useCallback, useEffect, useRef, useState } from "react"; + // components import { LinkView, LinkViewProps } from "@/components/links"; +import { CORE_EXTENSIONS } from "@/constants/extension"; +// components +import { getExtensionStorage } from "@/helpers/get-extension-storage"; type Props = { editor: Editor; @@ -18,7 +22,7 @@ export const LinkViewContainer: FC = ({ editor, containerRef }) => { const editorState = useEditorState({ editor, selector: ({ editor }: { editor: Editor }) => ({ - linkExtensionStorage: editor.storage.link, + linkExtensionStorage: getExtensionStorage(editor, CORE_EXTENSIONS.CUSTOM_LINK), }), }); diff --git a/packages/editor/src/core/components/menus/block-menu.tsx b/packages/editor/src/core/components/menus/block-menu.tsx index 4f4fb64ac..43c0193c7 100644 --- a/packages/editor/src/core/components/menus/block-menu.tsx +++ b/packages/editor/src/core/components/menus/block-menu.tsx @@ -4,9 +4,12 @@ import { useCallback, useEffect, useRef } from "react"; import tippy, { Instance } from "tippy.js"; // constants import { CORE_EXTENSIONS } from "@/constants/extension"; +import { IEditorProps } from "@/types"; type Props = { editor: Editor; + flaggedExtensions?: IEditorProps["flaggedExtensions"]; + disabledExtensions?: IEditorProps["disabledExtensions"]; }; export const BlockMenu = (props: Props) => { diff --git a/packages/editor/src/core/extensions/custom-link/extension.tsx b/packages/editor/src/core/extensions/custom-link/extension.tsx index 39c227b60..f9ae0d561 100644 --- a/packages/editor/src/core/extensions/custom-link/extension.tsx +++ b/packages/editor/src/core/extensions/custom-link/extension.tsx @@ -81,6 +81,7 @@ declare module "@tiptap/core" { export type CustomLinkStorage = { isPreviewOpen: boolean; posToInsert: { from: number; to: number }; + isBubbleMenuOpen: boolean; }; export const CustomLinkExtension = Mark.create({ diff --git a/packages/editor/src/core/extensions/extensions.ts b/packages/editor/src/core/extensions/extensions.ts index 9ca8f06ed..eda64824f 100644 --- a/packages/editor/src/core/extensions/extensions.ts +++ b/packages/editor/src/core/extensions/extensions.ts @@ -29,7 +29,7 @@ import { // plane editor extensions import { CoreEditorAdditionalExtensions } from "@/plane-editor/extensions"; // types -import type { IEditorProps } from "@/types"; +import type { IEditorProps, TEmbedConfig } from "@/types"; // local imports import { CustomImageExtension } from "./custom-image/extension"; import { EmojiExtension } from "./emoji/extension"; @@ -45,9 +45,11 @@ type TArguments = Pick< | "mentionHandler" | "placeholder" | "tabIndex" + | "embedHandler" > & { enableHistory: boolean; editable: boolean; + embedHandler?: TEmbedConfig; }; export const CoreEditorExtensions = (args: TArguments): Extensions => { @@ -60,6 +62,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => { mentionHandler, placeholder, tabIndex, + embedHandler, editable, } = args; @@ -115,6 +118,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => { disabledExtensions, flaggedExtensions, fileHandler, + embedHandler, }), ]; diff --git a/packages/editor/src/core/hooks/use-collaborative-editor.ts b/packages/editor/src/core/hooks/use-collaborative-editor.ts index cd08f5cbd..46f7c4d82 100644 --- a/packages/editor/src/core/hooks/use-collaborative-editor.ts +++ b/packages/editor/src/core/hooks/use-collaborative-editor.ts @@ -80,6 +80,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) => ); const editor = useEditor({ + embedHandler, disabledExtensions, id, editable, diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index b5c6383cd..22ca31143 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -32,6 +32,7 @@ export const useEditor = (props: TEditorHookProps) => { onAssetChange, onChange, onEditorFocus, + embedHandler, onTransaction, placeholder, provider, @@ -63,6 +64,7 @@ export const useEditor = (props: TEditorHookProps) => { mentionHandler, placeholder, tabIndex, + embedHandler, }), ...extensions, ], diff --git a/packages/editor/src/core/plugins/drag-handle.ts b/packages/editor/src/core/plugins/drag-handle.ts index b525759d9..bf04ba45a 100644 --- a/packages/editor/src/core/plugins/drag-handle.ts +++ b/packages/editor/src/core/plugins/drag-handle.ts @@ -21,6 +21,7 @@ const generalSelectors = [ ".image-component", ".image-upload-component", ".editor-callout-component", + ".editor-embed-component", ].join(", "); const maxScrollSpeed = 20; @@ -103,6 +104,11 @@ export const nodeDOMAtCoords = (coords: { x: number; y: number }) => { continue; } + // Skip elements inside .editor-embed-component + if (elem.closest(".editor-embed-component") && !elem.matches(".editor-embed-component")) { + continue; + } + // apply general selector if (elem.matches(generalSelectors)) { return elem; diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 2d04b9677..ed26bbbda 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -2,6 +2,7 @@ import type { Content, 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"; +import type { NodeViewProps as TNodeViewProps } from "@tiptap/react"; // extension types import type { TTextAlign } from "@/extensions"; // types @@ -48,7 +49,8 @@ export type TEditorCommands = | "text-align" | "callout" | "attachment" - | "emoji"; + | "emoji" + | "external-embed"; export type TCommandExtraProps = { image: { @@ -138,6 +140,7 @@ export type IEditorProps = { editorClassName?: string; editorProps?: EditorProps; extensions?: Extensions; + embedHandler?: TEmbedConfig; flaggedExtensions: TExtensions[]; fileHandler: TFileHandler; forwardedRef?: React.MutableRefObject; @@ -191,3 +194,5 @@ export type EditorEvents = { destroy: never; ready: { height: number }; }; + +export type NodeViewProps = TNodeViewProps; diff --git a/packages/editor/src/core/types/hook.ts b/packages/editor/src/core/types/hook.ts index 6e8dd1ee2..0376fc14d 100644 --- a/packages/editor/src/core/types/hook.ts +++ b/packages/editor/src/core/types/hook.ts @@ -13,6 +13,7 @@ type TCoreHookProps = Pick< | "handleEditorReady" | "isTouchDevice" | "onEditorFocus" + | "embedHandler" >; export type TEditorHookProps = TCoreHookProps & diff --git a/packages/utils/src/string.ts b/packages/utils/src/string.ts index 6ffb4ea04..062a162ab 100644 --- a/packages/utils/src/string.ts +++ b/packages/utils/src/string.ts @@ -174,7 +174,7 @@ export const isCommentEmpty = (comment: string | undefined): boolean => { return ( comment?.trim() === "" || comment === "

" || - isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component"]) + isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component", "embed-component"]) ); };