Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Extensions } from "@tiptap/core";
import React from "react";
import type { Extensions } from "@tiptap/core";
import React, { useMemo } from "react";
// plane imports
import { cn } from "@plane/utils";
// components
Expand All @@ -13,27 +13,32 @@ 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<ICollaborativeDocumentEditorProps> = (props) => {
const {
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,
Expand All @@ -42,32 +47,39 @@ const CollaborativeDocumentEditor: React.FC<ICollaborativeDocumentEditorProps> =
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,
flaggedExtensions,
forwardedRef,
handleEditorReady,
id,
dragDropEnabled,
isTouchDevice,
mentionHandler,
onAssetChange,
onChange,
onEditorFocus,
onTransaction,
placeholder,
realtimeConfig,
Expand All @@ -89,6 +101,7 @@ const CollaborativeDocumentEditor: React.FC<ICollaborativeDocumentEditorProps> =
aiHandler={aiHandler}
bubbleMenuEnabled={bubbleMenuEnabled}
displayConfig={displayConfig}
documentLoaderClassName={documentLoaderClassName}
editor={editor}
editorContainerClassName={cn(editorContainerClassNames, "document-editor")}
id={id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Props = {
aiHandler?: TAIHandler;
bubbleMenuEnabled: boolean;
displayConfig: TDisplayConfig;
documentLoaderClassName?: string;
editor: Editor;
editorContainerClassName: string;
id: string;
Expand All @@ -24,6 +25,7 @@ export const PageRenderer = (props: Props) => {
aiHandler,
bubbleMenuEnabled,
displayConfig,
documentLoaderClassName,
editor,
editorContainerClassName,
id,
Expand All @@ -39,7 +41,7 @@ export const PageRenderer = (props: Props) => {
})}
>
{isLoading ? (
<DocumentContentLoader />
<DocumentContentLoader className={documentLoaderClassName} />
) : (
<EditorContainer
displayConfig={displayConfig}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const DocumentReadOnlyEditor: React.FC<IDocumentReadOnlyEditorProps> = (props) =
containerClassName,
disabledExtensions,
displayConfig = DEFAULT_DISPLAY_CONFIG,
documentLoaderClassName,
editorClassName = "",
embedHandler,
fileHandler,
Expand Down Expand Up @@ -62,6 +63,7 @@ const DocumentReadOnlyEditor: React.FC<IDocumentReadOnlyEditorProps> = (props) =
<PageRenderer
bubbleMenuEnabled={false}
displayConfig={displayConfig}
documentLoaderClassName={documentLoaderClassName}
editor={editor}
editorContainerClassName={cn(editorContainerClassName, "document-editor")}
id={id}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const EditorWrapper: React.FC<Props> = (props) => {
displayConfig = DEFAULT_DISPLAY_CONFIG,
editable,
editorClassName = "",
editorProps,
extensions,
id,
initialValue,
Expand All @@ -33,6 +34,7 @@ export const EditorWrapper: React.FC<Props> = (props) => {
forwardedRef,
mentionHandler,
onChange,
onEditorFocus,
onTransaction,
handleEditorReady,
autofocus,
Expand All @@ -45,15 +47,18 @@ export const EditorWrapper: React.FC<Props> = (props) => {
editable,
disabledExtensions,
editorClassName,
editorProps,
enableHistory: true,
extensions,
fileHandler,
flaggedExtensions,
forwardedRef,
id,
isTouchDevice,
initialValue,
mentionHandler,
onChange,
onEditorFocus,
onTransaction,
handleEditorReady,
autofocus,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const RichTextEditor: React.FC<IRichTextEditorProps> = (props) => {
];

return extensions;
}, [dragDropEnabled, disabledExtensions, externalExtensions, fileHandler, flaggedExtensions]);
}, [dragDropEnabled, disabledExtensions, externalExtensions, fileHandler, flaggedExtensions, isTouchDevice]);

return (
<EditorWrapper {...props} extensions={getExtensions()}>
Expand Down
19 changes: 18 additions & 1 deletion packages/editor/src/core/components/menus/menu-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
MinusSquare,
Palette,
AlignCenter,
LinkIcon,
} from "lucide-react";
// constants
import { CORE_EXTENSIONS } from "@/constants/extension";
Expand All @@ -30,6 +31,7 @@ import {
insertHorizontalRule,
insertImage,
insertTableCommand,
setLinkEditor,
setText,
setTextAlign,
toggleBackgroundColor,
Expand All @@ -44,6 +46,7 @@ import {
toggleTaskList,
toggleTextColor,
toggleUnderline,
unsetLinkEditor,
} from "@/helpers/editor-commands";
// types
import { TCommandWithProps, TEditorCommands } from "@/types";
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -254,6 +270,7 @@ export const getEditorMenuItems = (editor: Editor | null): EditorMenuItem<TEdito
TableItem(editor),
ImageItem(editor),
HorizontalRuleItem(editor),
LinkItem(editor),
TextColorItem(editor),
BackgroundColorItem(editor),
TextAlignItem(editor),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const CustomImageNodeView: React.FC<CustomImageNodeViewProps> = (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<string | undefined>(undefined);
const [resolvedDownloadSrc, setResolvedDownloadSrc] = useState<string | undefined>(undefined);
const [imageFromFileSystem, setImageFromFileSystem] = useState<string | undefined>(undefined);
Expand All @@ -43,13 +43,13 @@ export const CustomImageNodeView: React.FC<CustomImageNodeViewProps> = (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) {
Expand Down
16 changes: 15 additions & 1 deletion packages/editor/src/core/helpers/editor-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
};

Expand Down
5 changes: 4 additions & 1 deletion packages/editor/src/core/hooks/use-collaborative-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) =>
forwardedRef,
handleEditorReady,
id,
dragDropEnabled = true,
isTouchDevice,
mentionHandler,
onEditorFocus,
placeholder,
realtimeConfig,
serverHandler,
Expand Down Expand Up @@ -87,7 +89,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) =>
extensions: [
SideMenuExtension({
aiEnabled: !disabledExtensions?.includes("ai"),
dragDropEnabled: true,
dragDropEnabled,
}),
HeadingListExtension,
Collaboration.configure({
Expand All @@ -111,6 +113,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) =>
mentionHandler,
onAssetChange,
onChange,
onEditorFocus,
onTransaction,
placeholder,
provider,
Expand Down
Loading
Loading