diff --git a/packages/editor/src/core/extensions/extensions.tsx b/packages/editor/src/core/extensions/extensions.tsx index 0b772baf9db..bcf4b5b4a97 100644 --- a/packages/editor/src/core/extensions/extensions.tsx +++ b/packages/editor/src/core/extensions/extensions.tsx @@ -137,7 +137,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => { CustomCodeInlineExtension, Markdown.configure({ html: true, - transformCopiedText: true, + transformCopiedText: false, transformPastedText: true, breaks: true, }), diff --git a/packages/editor/src/core/extensions/mentions/extension-config.ts b/packages/editor/src/core/extensions/mentions/extension-config.ts index 827137a1df1..a8921648a0d 100644 --- a/packages/editor/src/core/extensions/mentions/extension-config.ts +++ b/packages/editor/src/core/extensions/mentions/extension-config.ts @@ -1,12 +1,15 @@ import { mergeAttributes } from "@tiptap/core"; import Mention, { MentionOptions } from "@tiptap/extension-mention"; +import { MarkdownSerializerState } from "@tiptap/pm/markdown"; +import { Node as NodeType } from "@tiptap/pm/model"; // types import { TMentionHandler } from "@/types"; // local types -import { EMentionComponentAttributeNames } from "./types"; +import { EMentionComponentAttributeNames, TMentionComponentAttributes } from "./types"; export type TMentionExtensionOptions = MentionOptions & { renderComponent: TMentionHandler["renderComponent"]; + getMentionedEntityDetails: TMentionHandler["getMentionedEntityDetails"]; }; export const CustomMentionExtensionConfig = Mention.extend({ @@ -40,9 +43,26 @@ export const CustomMentionExtensionConfig = Mention.extend { - const { searchCallback, renderComponent } = props; + const { searchCallback, renderComponent, getMentionedEntityDetails } = props; return CustomMentionExtensionConfig.extend({ addOptions(this) { return { ...this.parent?.(), renderComponent, + getMentionedEntityDetails, }; }, diff --git a/packages/editor/src/core/types/mention.ts b/packages/editor/src/core/types/mention.ts index 20f1ec0dcc6..b7a65f8b4c9 100644 --- a/packages/editor/src/core/types/mention.ts +++ b/packages/editor/src/core/types/mention.ts @@ -1,5 +1,5 @@ // plane types -import { TSearchEntities } from "@plane/types"; +import { IUserLite, TSearchEntities } from "@plane/types"; export type TMentionSuggestion = { entity_identifier: string; @@ -20,6 +20,7 @@ export type TMentionComponentProps = Pick React.ReactNode; + getMentionedEntityDetails?: (entity_identifier: string) => { display_name: string } | undefined; }; export type TMentionHandler = TReadOnlyMentionHandler & { diff --git a/space/core/components/editor/lite-text-read-only-editor.tsx b/space/core/components/editor/lite-text-read-only-editor.tsx index 5f936baec5a..e4be5693518 100644 --- a/space/core/components/editor/lite-text-read-only-editor.tsx +++ b/space/core/components/editor/lite-text-read-only-editor.tsx @@ -6,6 +6,8 @@ import { EditorMentionsRoot } from "@/components/editor"; // helpers import { cn } from "@/helpers/common.helper"; import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper"; +// store hooks +import { useMember } from "@/hooks/store"; type LiteTextReadOnlyEditorWrapperProps = Omit< ILiteTextReadOnlyEditor, @@ -15,21 +17,27 @@ type LiteTextReadOnlyEditorWrapperProps = Omit< }; export const LiteTextReadOnlyEditor = React.forwardRef( - ({ anchor, ...props }, ref) => ( - , - }} - {...props} - // overriding the customClassName to add relative class passed - containerClassName={cn(props.containerClassName, "relative p-2")} - /> - ) + ({ anchor, ...props }, ref) => { + const { getMemberById } = useMember(); + return ( + , + getMentionedEntityDetails: (id: string) => ({ + display_name: getMemberById(id)?.member__display_name ?? "", + }), + }} + {...props} + // overriding the customClassName to add relative class passed + containerClassName={cn(props.containerClassName, "relative p-2")} + /> + ); + } ); LiteTextReadOnlyEditor.displayName = "LiteTextReadOnlyEditor"; diff --git a/space/core/components/editor/rich-text-editor.tsx b/space/core/components/editor/rich-text-editor.tsx index 96f4900548c..f7f4358770c 100644 --- a/space/core/components/editor/rich-text-editor.tsx +++ b/space/core/components/editor/rich-text-editor.tsx @@ -5,6 +5,8 @@ import { EditorRefApi, IRichTextEditor, RichTextEditorWithRef } from "@plane/edi import { EditorMentionsRoot } from "@/components/editor"; // helpers import { getEditorFileHandlers } from "@/helpers/editor.helper"; +// store hooks +import { useMember } from "@/hooks/store"; interface RichTextEditorWrapperProps extends Omit { @@ -12,12 +14,17 @@ interface RichTextEditorWrapperProps } export const RichTextEditor = forwardRef((props, ref) => { + const { getMemberById } = useMember(); + const { containerClassName, uploadFile, ...rest } = props; return ( , + getMentionedEntityDetails: (id: string) => ({ + display_name: getMemberById(id)?.member__display_name ?? "", + }), }} ref={ref} disabledExtensions={[]} diff --git a/space/core/components/editor/rich-text-read-only-editor.tsx b/space/core/components/editor/rich-text-read-only-editor.tsx index 76075f29656..5bc6ccfdcc0 100644 --- a/space/core/components/editor/rich-text-read-only-editor.tsx +++ b/space/core/components/editor/rich-text-read-only-editor.tsx @@ -6,6 +6,8 @@ import { EditorMentionsRoot } from "@/components/editor"; // helpers import { cn } from "@/helpers/common.helper"; import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper"; +// store hooks +import { useMember } from "@/hooks/store"; type RichTextReadOnlyEditorWrapperProps = Omit< IRichTextReadOnlyEditor, @@ -15,21 +17,27 @@ type RichTextReadOnlyEditorWrapperProps = Omit< }; export const RichTextReadOnlyEditor = React.forwardRef( - ({ anchor, ...props }, ref) => ( - , - }} - {...props} - // overriding the customClassName to add relative class passed - containerClassName={cn("relative p-0 border-none", props.containerClassName)} - /> - ) + ({ anchor, ...props }, ref) => { + const { getMemberById } = useMember(); + return ( + , + getMentionedEntityDetails: (id: string) => ({ + display_name: getMemberById(id)?.member__display_name ?? "", + }), + }} + {...props} + // overriding the customClassName to add relative class passed + containerClassName={cn("relative p-0 border-none", props.containerClassName)} + /> + ); + } ); RichTextReadOnlyEditor.displayName = "RichTextReadOnlyEditor"; diff --git a/web/core/components/editor/lite-text-editor/lite-text-editor.tsx b/web/core/components/editor/lite-text-editor/lite-text-editor.tsx index 82cbd12257b..4456fcde80c 100644 --- a/web/core/components/editor/lite-text-editor/lite-text-editor.tsx +++ b/web/core/components/editor/lite-text-editor/lite-text-editor.tsx @@ -13,6 +13,8 @@ import { getEditorFileHandlers } from "@/helpers/editor.helper"; import { isCommentEmpty } from "@/helpers/string.helper"; // hooks import { useEditorMention } from "@/hooks/use-editor-mention"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; import { useFileSize } from "@/plane-web/hooks/use-file-size"; @@ -57,6 +59,8 @@ export const LiteTextEditor = React.forwardRef @@ -98,6 +102,7 @@ export const LiteTextEditor = React.forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} placeholder={placeholder} containerClassName={cn(containerClassName, "relative")} diff --git a/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx b/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx index 1272604e2d6..0dbe1984022 100644 --- a/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx +++ b/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx @@ -8,6 +8,8 @@ import { cn } from "@/helpers/common.helper"; import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; +// store hooks +import { useMember } from "@/hooks/store"; type LiteTextReadOnlyEditorWrapperProps = Omit< ILiteTextReadOnlyEditor, @@ -19,6 +21,9 @@ type LiteTextReadOnlyEditorWrapperProps = Omit< export const LiteTextReadOnlyEditor = React.forwardRef( ({ workspaceSlug, projectId, ...props }, ref) => { + // store hooks + const { getUserDetails } = useMember(); + // editor flaggings const { liteTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString()); @@ -32,6 +37,7 @@ export const LiteTextReadOnlyEditor = React.forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} {...props} // overriding the containerClassName to add relative class passed diff --git a/web/core/components/editor/rich-text-editor/rich-text-editor.tsx b/web/core/components/editor/rich-text-editor/rich-text-editor.tsx index e3b5aa7a313..c393b611724 100644 --- a/web/core/components/editor/rich-text-editor/rich-text-editor.tsx +++ b/web/core/components/editor/rich-text-editor/rich-text-editor.tsx @@ -13,6 +13,8 @@ import { useEditorMention } from "@/hooks/use-editor-mention"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; import { useFileSize } from "@/plane-web/hooks/use-file-size"; +// store hooks +import { useMember } from "@/hooks/store"; interface RichTextEditorWrapperProps extends Omit { @@ -26,6 +28,8 @@ interface RichTextEditorWrapperProps export const RichTextEditor = forwardRef((props, ref) => { const { containerClassName, workspaceSlug, workspaceId, projectId, searchMentionCallback, uploadFile, ...rest } = props; + // store hooks + const { getUserDetails } = useMember(); // editor flaggings const { richTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString()); // use editor mention @@ -53,6 +57,7 @@ export const RichTextEditor = forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} {...rest} containerClassName={cn("relative pl-3", containerClassName)} diff --git a/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx b/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx index a21e8b668b2..97c792775c5 100644 --- a/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx +++ b/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx @@ -6,6 +6,8 @@ import { EditorMentionsRoot } from "@/components/editor"; // helpers import { cn } from "@/helpers/common.helper"; import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; @@ -19,6 +21,9 @@ type RichTextReadOnlyEditorWrapperProps = Omit< export const RichTextReadOnlyEditor = React.forwardRef( ({ workspaceSlug, projectId, ...props }, ref) => { + // store hooks + const { getUserDetails } = useMember(); + // editor flaggings const { richTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString()); @@ -32,6 +37,7 @@ export const RichTextReadOnlyEditor = React.forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} {...props} // overriding the containerClassName to add relative class passed diff --git a/web/core/components/pages/editor/editor-body.tsx b/web/core/components/pages/editor/editor-body.tsx index 161d63c47cc..2d3b4b36ca7 100644 --- a/web/core/components/pages/editor/editor-body.tsx +++ b/web/core/components/pages/editor/editor-body.tsx @@ -21,7 +21,7 @@ import { PageContentBrowser, PageContentLoader, PageEditorTitle } from "@/compon import { cn, LIVE_BASE_PATH, LIVE_BASE_URL } from "@/helpers/common.helper"; import { generateRandomColor } from "@/helpers/string.helper"; // hooks -import { useUser } from "@/hooks/store"; +import { useMember, useUser } from "@/hooks/store"; import { useEditorMention } from "@/hooks/use-editor-mention"; import { usePageFilters } from "@/hooks/use-page-filters"; // plane web components @@ -66,6 +66,8 @@ export const PageEditorBody: React.FC = observer((props) => { } = props; // store hooks const { data: currentUser } = useUser(); + const { getUserDetails } = useMember(); + // derived values const { id: pageId, name: pageTitle, isContentEditable, updateTitle } = page; // issue-embed @@ -188,6 +190,7 @@ export const PageEditorBody: React.FC = observer((props) => { return res; }, renderComponent: (props) => , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} embedHandler={{ issue: issueEmbedProps, diff --git a/web/core/components/pages/version/editor.tsx b/web/core/components/pages/version/editor.tsx index 0beffa6f358..397b2ff029a 100644 --- a/web/core/components/pages/version/editor.tsx +++ b/web/core/components/pages/version/editor.tsx @@ -12,6 +12,8 @@ import { EditorMentionsRoot } from "@/components/editor"; import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper"; // hooks import { usePageFilters } from "@/hooks/use-page-filters"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; import { useIssueEmbed } from "@/plane-web/hooks/use-issue-embed"; @@ -25,6 +27,8 @@ export type TVersionEditorProps = { export const PagesVersionEditor: React.FC = observer((props) => { const { activeVersion, currentVersionDescription, isCurrentVersionActive, versionDetails } = props; + // store hooks + const { getUserDetails } = useMember(); // params const { workspaceSlug, projectId } = useParams(); // editor flaggings @@ -101,6 +105,7 @@ export const PagesVersionEditor: React.FC = observer((props })} mentionHandler={{ renderComponent: (props) => , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} embedHandler={{ issue: {