[WIKI-466] refactor: remove rich text read only editor (#7241)
* refactor: remove rich text read only editor * fix: type imports
This commit is contained in:
parent
7d141f26ad
commit
6f27ec031d
22 changed files with 126 additions and 262 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
export * from "./embeds";
|
export * from "./embeds";
|
||||||
export * from "./lite-text-editor";
|
export * from "./lite-text-editor";
|
||||||
export * from "./lite-text-read-only-editor";
|
export * from "./lite-text-read-only-editor";
|
||||||
export * from "./rich-text-read-only-editor";
|
export * from "./rich-text-editor";
|
||||||
export * from "./toolbar";
|
export * from "./toolbar";
|
||||||
|
|
|
||||||
|
|
@ -9,18 +9,24 @@ import { getEditorFileHandlers } from "@/helpers/editor.helper";
|
||||||
// store hooks
|
// store hooks
|
||||||
import { useMember } from "@/hooks/store";
|
import { useMember } from "@/hooks/store";
|
||||||
|
|
||||||
interface RichTextEditorWrapperProps
|
type RichTextEditorWrapperProps = MakeOptional<
|
||||||
extends MakeOptional<
|
Omit<IRichTextEditorProps, "editable" | "fileHandler" | "mentionHandler">,
|
||||||
Omit<IRichTextEditorProps, "fileHandler" | "mentionHandler">,
|
|
||||||
"disabledExtensions" | "flaggedExtensions"
|
"disabledExtensions" | "flaggedExtensions"
|
||||||
> {
|
> & {
|
||||||
anchor: string;
|
anchor: string;
|
||||||
uploadFile: TFileHandler["upload"];
|
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
}
|
} & (
|
||||||
|
| {
|
||||||
|
editable: false;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
editable: true;
|
||||||
|
uploadFile: TFileHandler["upload"];
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProps>((props, ref) => {
|
export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProps>((props, ref) => {
|
||||||
const { anchor, containerClassName, uploadFile, workspaceId, disabledExtensions, flaggedExtensions, ...rest } = props;
|
const { anchor, containerClassName, editable, workspaceId, disabledExtensions, flaggedExtensions, ...rest } = props;
|
||||||
const { getMemberById } = useMember();
|
const { getMemberById } = useMember();
|
||||||
return (
|
return (
|
||||||
<RichTextEditorWithRef
|
<RichTextEditorWithRef
|
||||||
|
|
@ -32,9 +38,10 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
|
||||||
}}
|
}}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
disabledExtensions={disabledExtensions ?? []}
|
disabledExtensions={disabledExtensions ?? []}
|
||||||
|
editable={editable}
|
||||||
fileHandler={getEditorFileHandlers({
|
fileHandler={getEditorFileHandlers({
|
||||||
anchor,
|
anchor,
|
||||||
uploadFile,
|
uploadFile: editable ? props.uploadFile : async () => "",
|
||||||
workspaceId,
|
workspaceId,
|
||||||
})}
|
})}
|
||||||
flaggedExtensions={flaggedExtensions ?? []}
|
flaggedExtensions={flaggedExtensions ?? []}
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
// plane imports
|
|
||||||
import { EditorReadOnlyRefApi, IRichTextReadOnlyEditorProps, RichTextReadOnlyEditorWithRef } from "@plane/editor";
|
|
||||||
import { MakeOptional } from "@plane/types";
|
|
||||||
import { cn } from "@plane/utils";
|
|
||||||
// components
|
|
||||||
import { EditorMentionsRoot } from "@/components/editor";
|
|
||||||
// helpers
|
|
||||||
import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper";
|
|
||||||
// store hooks
|
|
||||||
import { useMember } from "@/hooks/store";
|
|
||||||
|
|
||||||
type RichTextReadOnlyEditorWrapperProps = MakeOptional<
|
|
||||||
Omit<IRichTextReadOnlyEditorProps, "fileHandler" | "mentionHandler">,
|
|
||||||
"disabledExtensions" | "flaggedExtensions"
|
|
||||||
> & {
|
|
||||||
anchor: string;
|
|
||||||
workspaceId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, RichTextReadOnlyEditorWrapperProps>(
|
|
||||||
({ anchor, workspaceId, disabledExtensions, flaggedExtensions, ...props }, ref) => {
|
|
||||||
const { getMemberById } = useMember();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RichTextReadOnlyEditorWithRef
|
|
||||||
ref={ref}
|
|
||||||
disabledExtensions={disabledExtensions ?? []}
|
|
||||||
flaggedExtensions={flaggedExtensions ?? []}
|
|
||||||
fileHandler={getReadOnlyEditorFileHandlers({
|
|
||||||
anchor,
|
|
||||||
workspaceId,
|
|
||||||
})}
|
|
||||||
mentionHandler={{
|
|
||||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
|
||||||
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";
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
// components
|
// components
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
import { IssueReactions } from "@/components/issues/peek-overview";
|
import { IssueReactions } from "@/components/issues/peek-overview";
|
||||||
import { usePublish } from "@/hooks/store";
|
import { usePublish } from "@/hooks/store";
|
||||||
// types
|
// types
|
||||||
|
|
@ -25,7 +25,8 @@ export const PeekOverviewIssueDetails: React.FC<Props> = observer((props) => {
|
||||||
</h6>
|
</h6>
|
||||||
<h4 className="break-words text-2xl font-medium">{issueDetails.name}</h4>
|
<h4 className="break-words text-2xl font-medium">{issueDetails.name}</h4>
|
||||||
{description !== "" && description !== "<p></p>" && (
|
{description !== "" && description !== "<p></p>" && (
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
|
editable={false}
|
||||||
anchor={anchor}
|
anchor={anchor}
|
||||||
id={issueDetails.id}
|
id={issueDetails.id}
|
||||||
initialValue={
|
initialValue={
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { CircleArrowUp, CornerDownRight, RefreshCcw, Sparkles } from "lucide-rea
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
// helpers
|
// helpers
|
||||||
// hooks
|
// hooks
|
||||||
import { useWorkspace } from "@/hooks/store";
|
import { useWorkspace } from "@/hooks/store";
|
||||||
|
|
@ -38,7 +38,8 @@ export const AskPiMenu: React.FC<Props> = (props) => {
|
||||||
</span>
|
</span>
|
||||||
{response ? (
|
{response ? (
|
||||||
<div>
|
<div>
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
|
editable={false}
|
||||||
displayConfig={{
|
displayConfig={{
|
||||||
fontSize: "small-font",
|
fontSize: "small-font",
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import { EditorRefApi } from "@plane/editor";
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { cn } from "@plane/utils";
|
import { cn } from "@plane/utils";
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
// helpers
|
// helpers
|
||||||
// plane web constants
|
// plane web constants
|
||||||
import { AI_EDITOR_TASKS, LOADING_TEXTS } from "@/plane-web/constants/ai";
|
import { AI_EDITOR_TASKS, LOADING_TEXTS } from "@/plane-web/constants/ai";
|
||||||
|
|
@ -208,10 +208,11 @@ export const EditorAIMenu: React.FC<Props> = (props) => {
|
||||||
</span>
|
</span>
|
||||||
{response ? (
|
{response ? (
|
||||||
<div>
|
<div>
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
displayConfig={{
|
displayConfig={{
|
||||||
fontSize: "small-font",
|
fontSize: "small-font",
|
||||||
}}
|
}}
|
||||||
|
editable={false}
|
||||||
id="editor-ai-response"
|
id="editor-ai-response"
|
||||||
initialValue={response}
|
initialValue={response}
|
||||||
containerClassName="!p-0 border-none"
|
containerClassName="!p-0 border-none"
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { useCallback, useRef } from "react";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { ChevronLeft, ChevronRight, Copy } from "lucide-react";
|
import { ChevronLeft, ChevronRight, Copy } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EditorReadOnlyRefApi } from "@plane/editor";
|
import type { EditorRefApi } from "@plane/editor";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { TDescriptionVersion } from "@plane/types";
|
import { TDescriptionVersion } from "@plane/types";
|
||||||
import {
|
import {
|
||||||
|
|
@ -19,7 +19,7 @@ import {
|
||||||
} from "@plane/ui";
|
} from "@plane/ui";
|
||||||
import { calculateTimeAgo, cn, copyTextToClipboard, getFileURL } from "@plane/utils";
|
import { calculateTimeAgo, cn, copyTextToClipboard, getFileURL } from "@plane/utils";
|
||||||
// components
|
// components
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
// hooks
|
// hooks
|
||||||
import { useMember, useWorkspace } from "@/hooks/store";
|
import { useMember, useWorkspace } from "@/hooks/store";
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ export const DescriptionVersionsModal: React.FC<Props> = observer((props) => {
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
} = props;
|
} = props;
|
||||||
// refs
|
// refs
|
||||||
const editorRef = useRef<EditorReadOnlyRefApi>(null);
|
const editorRef = useRef<EditorRefApi>(null);
|
||||||
// store hooks
|
// store hooks
|
||||||
const { getUserDetails } = useMember();
|
const { getUserDetails } = useMember();
|
||||||
const { getWorkspaceBySlug } = useWorkspace();
|
const { getWorkspaceBySlug } = useWorkspace();
|
||||||
|
|
@ -131,7 +131,8 @@ export const DescriptionVersionsModal: React.FC<Props> = observer((props) => {
|
||||||
{/* Version description */}
|
{/* Version description */}
|
||||||
<div className="mt-4 pb-4">
|
<div className="mt-4 pb-4">
|
||||||
{activeVersionDescription ? (
|
{activeVersionDescription ? (
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
|
editable={false}
|
||||||
containerClassName="p-0 !pl-0 border-none"
|
containerClassName="p-0 !pl-0 border-none"
|
||||||
editorClassName="pl-0"
|
editorClassName="pl-0"
|
||||||
id={activeVersionId ?? ""}
|
id={activeVersionId ?? ""}
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,11 @@ import { Controller, useForm } from "react-hook-form"; // services
|
||||||
import { usePopper } from "react-popper";
|
import { usePopper } from "react-popper";
|
||||||
import { AlertCircle } from "lucide-react";
|
import { AlertCircle } from "lucide-react";
|
||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
// plane editor
|
// plane imports
|
||||||
import { EditorReadOnlyRefApi } from "@plane/editor";
|
import type { EditorRefApi } from "@plane/editor";
|
||||||
// ui
|
|
||||||
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
import { Button, Input, TOAST_TYPE, setToast } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor/rich-text-editor/rich-text-read-only-editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
// services
|
// services
|
||||||
import { AIService } from "@/services/ai.service";
|
import { AIService } from "@/services/ai.service";
|
||||||
const aiService = new AIService();
|
const aiService = new AIService();
|
||||||
|
|
@ -55,8 +54,8 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
||||||
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
const [referenceElement, setReferenceElement] = useState<HTMLButtonElement | null>(null);
|
||||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
||||||
// refs
|
// refs
|
||||||
const editorRef = useRef<EditorReadOnlyRefApi>(null);
|
const editorRef = useRef<EditorRefApi>(null);
|
||||||
const responseRef = useRef<any>(null);
|
const responseRef = useRef<EditorRefApi>(null);
|
||||||
// popper
|
// popper
|
||||||
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
const { styles, attributes } = usePopper(referenceElement, popperElement, {
|
||||||
placement: placement ?? "auto",
|
placement: placement ?? "auto",
|
||||||
|
|
@ -217,7 +216,8 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
||||||
{prompt && (
|
{prompt && (
|
||||||
<div className="text-sm">
|
<div className="text-sm">
|
||||||
Content:
|
Content:
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
|
editable={false}
|
||||||
id="ai-assistant-content"
|
id="ai-assistant-content"
|
||||||
initialValue={prompt}
|
initialValue={prompt}
|
||||||
containerClassName="-m-3"
|
containerClassName="-m-3"
|
||||||
|
|
@ -231,7 +231,8 @@ export const GptAssistantPopover: React.FC<Props> = (props) => {
|
||||||
{response !== "" && (
|
{response !== "" && (
|
||||||
<div className="page-block-section max-h-[8rem] text-sm">
|
<div className="page-block-section max-h-[8rem] text-sm">
|
||||||
Response:
|
Response:
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
|
editable={false}
|
||||||
id="ai-assistant-response"
|
id="ai-assistant-response"
|
||||||
initialValue={`<p>${response}</p>`}
|
initialValue={`<p>${response}</p>`}
|
||||||
ref={responseRef}
|
ref={responseRef}
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
export * from "./rich-text-editor";
|
export * from "./rich-text-editor";
|
||||||
export * from "./rich-text-read-only-editor";
|
|
||||||
|
|
|
||||||
|
|
@ -13,26 +13,31 @@ import { useMember } from "@/hooks/store";
|
||||||
// plane web hooks
|
// plane web hooks
|
||||||
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
||||||
|
|
||||||
interface RichTextEditorWrapperProps
|
type RichTextEditorWrapperProps = MakeOptional<
|
||||||
extends MakeOptional<
|
|
||||||
Omit<IRichTextEditorProps, "fileHandler" | "mentionHandler">,
|
Omit<IRichTextEditorProps, "fileHandler" | "mentionHandler">,
|
||||||
"disabledExtensions" | "flaggedExtensions"
|
"disabledExtensions" | "editable" | "flaggedExtensions"
|
||||||
> {
|
> & {
|
||||||
searchMentionCallback: (payload: TSearchEntityRequestPayload) => Promise<TSearchResponse>;
|
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
projectId?: string;
|
projectId?: string;
|
||||||
|
} & (
|
||||||
|
| {
|
||||||
|
editable: false;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
editable: true;
|
||||||
|
searchMentionCallback: (payload: TSearchEntityRequestPayload) => Promise<TSearchResponse>;
|
||||||
uploadFile: TFileHandler["upload"];
|
uploadFile: TFileHandler["upload"];
|
||||||
}
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProps>((props, ref) => {
|
export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProps>((props, ref) => {
|
||||||
const {
|
const {
|
||||||
containerClassName,
|
containerClassName,
|
||||||
|
editable,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
projectId,
|
projectId,
|
||||||
searchMentionCallback,
|
|
||||||
uploadFile,
|
|
||||||
disabledExtensions: additionalDisabledExtensions,
|
disabledExtensions: additionalDisabledExtensions,
|
||||||
...rest
|
...rest
|
||||||
} = props;
|
} = props;
|
||||||
|
|
@ -42,7 +47,7 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
|
||||||
const { richText: richTextEditorExtensions } = useEditorFlagging(workspaceSlug?.toString());
|
const { richText: richTextEditorExtensions } = useEditorFlagging(workspaceSlug?.toString());
|
||||||
// use editor mention
|
// use editor mention
|
||||||
const { fetchMentions } = useEditorMention({
|
const { fetchMentions } = useEditorMention({
|
||||||
searchEntity: async (payload) => await searchMentionCallback(payload),
|
searchEntity: editable ? async (payload) => await props.searchMentionCallback(payload) : async () => ({}),
|
||||||
});
|
});
|
||||||
// editor config
|
// editor config
|
||||||
const { getEditorFileHandlers } = useEditorConfig();
|
const { getEditorFileHandlers } = useEditorConfig();
|
||||||
|
|
@ -51,10 +56,11 @@ export const RichTextEditor = forwardRef<EditorRefApi, RichTextEditorWrapperProp
|
||||||
<RichTextEditorWithRef
|
<RichTextEditorWithRef
|
||||||
ref={ref}
|
ref={ref}
|
||||||
disabledExtensions={[...richTextEditorExtensions.disabled, ...(additionalDisabledExtensions ?? [])]}
|
disabledExtensions={[...richTextEditorExtensions.disabled, ...(additionalDisabledExtensions ?? [])]}
|
||||||
|
editable={editable}
|
||||||
flaggedExtensions={richTextEditorExtensions.flagged}
|
flaggedExtensions={richTextEditorExtensions.flagged}
|
||||||
fileHandler={getEditorFileHandlers({
|
fileHandler={getEditorFileHandlers({
|
||||||
projectId,
|
projectId,
|
||||||
uploadFile,
|
uploadFile: editable ? props.uploadFile : async () => "",
|
||||||
workspaceId,
|
workspaceId,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
})}
|
})}
|
||||||
|
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import React from "react";
|
|
||||||
// plane imports
|
|
||||||
import { EditorReadOnlyRefApi, IRichTextReadOnlyEditorProps, RichTextReadOnlyEditorWithRef } from "@plane/editor";
|
|
||||||
import { MakeOptional } from "@plane/types";
|
|
||||||
// components
|
|
||||||
import { cn } from "@plane/utils";
|
|
||||||
import { EditorMentionsRoot } from "@/components/editor";
|
|
||||||
// helpers
|
|
||||||
// hooks
|
|
||||||
import { useEditorConfig } from "@/hooks/editor";
|
|
||||||
// store hooks
|
|
||||||
import { useMember } from "@/hooks/store";
|
|
||||||
// plane web hooks
|
|
||||||
import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging";
|
|
||||||
|
|
||||||
type RichTextReadOnlyEditorWrapperProps = MakeOptional<
|
|
||||||
Omit<IRichTextReadOnlyEditorProps, "fileHandler" | "mentionHandler">,
|
|
||||||
"disabledExtensions" | "flaggedExtensions"
|
|
||||||
> & {
|
|
||||||
workspaceId: string;
|
|
||||||
workspaceSlug: string;
|
|
||||||
projectId?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const RichTextReadOnlyEditor = React.forwardRef<EditorReadOnlyRefApi, RichTextReadOnlyEditorWrapperProps>(
|
|
||||||
({ workspaceId, workspaceSlug, projectId, disabledExtensions: additionalDisabledExtensions, ...props }, ref) => {
|
|
||||||
// store hooks
|
|
||||||
const { getUserDetails } = useMember();
|
|
||||||
|
|
||||||
// editor flaggings
|
|
||||||
const { richText: richTextEditorExtensions } = useEditorFlagging(workspaceSlug?.toString());
|
|
||||||
// editor config
|
|
||||||
const { getReadOnlyEditorFileHandlers } = useEditorConfig();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<RichTextReadOnlyEditorWithRef
|
|
||||||
ref={ref}
|
|
||||||
disabledExtensions={[...richTextEditorExtensions.disabled, ...(additionalDisabledExtensions ?? [])]}
|
|
||||||
flaggedExtensions={richTextEditorExtensions.flagged}
|
|
||||||
fileHandler={getReadOnlyEditorFileHandlers({
|
|
||||||
projectId,
|
|
||||||
workspaceId,
|
|
||||||
workspaceSlug,
|
|
||||||
})}
|
|
||||||
mentionHandler={{
|
|
||||||
renderComponent: (props) => <EditorMentionsRoot {...props} />,
|
|
||||||
getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }),
|
|
||||||
}}
|
|
||||||
{...props}
|
|
||||||
// overriding the containerClassName to add relative class passed
|
|
||||||
containerClassName={cn(props.containerClassName, "relative pl-3")}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
RichTextReadOnlyEditor.displayName = "RichTextReadOnlyEditor";
|
|
||||||
|
|
@ -62,6 +62,7 @@ export const InboxIssueDescription: FC<TInboxIssueDescription> = observer((props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
|
editable
|
||||||
id="inbox-modal-editor"
|
id="inbox-modal-editor"
|
||||||
initialValue={!data?.description_html || data?.description_html === "" ? "<p></p>" : data?.description_html}
|
initialValue={!data?.description_html || data?.description_html === "" ? "<p></p>" : data?.description_html}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@ import debounce from "lodash/debounce";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { EditorReadOnlyRefApi, EditorRefApi } from "@plane/editor";
|
import type { EditorRefApi } from "@plane/editor";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import { EFileAssetType, TIssue, TNameDescriptionLoader } from "@plane/types";
|
import { EFileAssetType, TIssue, TNameDescriptionLoader } from "@plane/types";
|
||||||
import { Loader } from "@plane/ui";
|
import { Loader } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { getDescriptionPlaceholderI18n } from "@plane/utils";
|
import { getDescriptionPlaceholderI18n } from "@plane/utils";
|
||||||
import { RichTextEditor, RichTextReadOnlyEditor } from "@/components/editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
import { TIssueOperations } from "@/components/issues/issue-detail";
|
import { TIssueOperations } from "@/components/issues/issue-detail";
|
||||||
// helpers
|
// helpers
|
||||||
// hooks
|
// hooks
|
||||||
|
|
@ -22,7 +22,6 @@ const workspaceService = new WorkspaceService();
|
||||||
|
|
||||||
export type IssueDescriptionInputProps = {
|
export type IssueDescriptionInputProps = {
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
editorReadOnlyRef?: React.RefObject<EditorReadOnlyRefApi>;
|
|
||||||
editorRef?: React.RefObject<EditorRefApi>;
|
editorRef?: React.RefObject<EditorRefApi>;
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
|
|
@ -38,7 +37,6 @@ export type IssueDescriptionInputProps = {
|
||||||
export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((props) => {
|
export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((props) => {
|
||||||
const {
|
const {
|
||||||
containerClassName,
|
containerClassName,
|
||||||
editorReadOnlyRef,
|
|
||||||
editorRef,
|
editorRef,
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
|
|
@ -109,9 +107,9 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
|
||||||
<Controller
|
<Controller
|
||||||
name="description_html"
|
name="description_html"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { onChange } }) =>
|
render={({ field: { onChange } }) => (
|
||||||
!disabled ? (
|
|
||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
|
editable={!disabled}
|
||||||
id={issueId}
|
id={issueId}
|
||||||
initialValue={localIssueDescription.description_html ?? "<p></p>"}
|
initialValue={localIssueDescription.description_html ?? "<p></p>"}
|
||||||
value={swrIssueDescription ?? null}
|
value={swrIssueDescription ?? null}
|
||||||
|
|
@ -157,18 +155,7 @@ export const IssueDescriptionInput: FC<IssueDescriptionInputProps> = observer((p
|
||||||
}}
|
}}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
/>
|
/>
|
||||||
) : (
|
)}
|
||||||
<RichTextReadOnlyEditor
|
|
||||||
id={issueId}
|
|
||||||
initialValue={localIssueDescription.description_html ?? ""}
|
|
||||||
containerClassName={containerClassName}
|
|
||||||
workspaceId={workspaceId}
|
|
||||||
workspaceSlug={workspaceSlug}
|
|
||||||
projectId={projectId}
|
|
||||||
ref={editorReadOnlyRef}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Loader>
|
<Loader>
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,9 @@ import { Control, Controller } from "react-hook-form";
|
||||||
import { Sparkle } from "lucide-react";
|
import { Sparkle } from "lucide-react";
|
||||||
// plane imports
|
// plane imports
|
||||||
import { ETabIndices } from "@plane/constants";
|
import { ETabIndices } from "@plane/constants";
|
||||||
// editor
|
import type { EditorRefApi } from "@plane/editor";
|
||||||
import { EditorRefApi } from "@plane/editor";
|
|
||||||
// i18n
|
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
// types
|
|
||||||
import { EFileAssetType, TIssue } from "@plane/types";
|
import { EFileAssetType, TIssue } from "@plane/types";
|
||||||
// ui
|
|
||||||
import { Loader, setToast, TOAST_TYPE } from "@plane/ui";
|
import { Loader, setToast, TOAST_TYPE } from "@plane/ui";
|
||||||
import { getDescriptionPlaceholderI18n, getTabIndex } from "@plane/utils";
|
import { getDescriptionPlaceholderI18n, getTabIndex } from "@plane/utils";
|
||||||
// components
|
// components
|
||||||
|
|
@ -177,6 +173,7 @@ export const IssueDescriptionEditor: React.FC<TIssueDescriptionEditorProps> = ob
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange } }) => (
|
render={({ field: { value, onChange } }) => (
|
||||||
<RichTextEditor
|
<RichTextEditor
|
||||||
|
editable
|
||||||
id="issue-modal-editor"
|
id="issue-modal-editor"
|
||||||
initialValue={value ?? ""}
|
initialValue={value ?? ""}
|
||||||
value={descriptionHtmlData}
|
value={descriptionHtmlData}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { calculateTimeAgo, getFileURL } from "@plane/utils";
|
||||||
// components
|
// components
|
||||||
import { ActivityIcon, ActivityMessage, IssueLink } from "@/components/core";
|
import { ActivityIcon, ActivityMessage, IssueLink } from "@/components/core";
|
||||||
// editor
|
// editor
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor/rich-text-editor/rich-text-read-only-editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
// ui
|
// ui
|
||||||
import { ActivitySettingsLoader } from "@/components/ui";
|
import { ActivitySettingsLoader } from "@/components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
|
|
@ -73,7 +73,8 @@ export const ActivityList: React.FC<Props> = observer((props) => {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="issue-comments-section p-0">
|
<div className="issue-comments-section p-0">
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
|
editable={false}
|
||||||
id={activityItem.id}
|
id={activityItem.id}
|
||||||
initialValue={
|
initialValue={
|
||||||
activityItem?.new_value !== ""
|
activityItem?.new_value !== ""
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import useSWR from "swr";
|
||||||
import { History, MessageSquare } from "lucide-react";
|
import { History, MessageSquare } from "lucide-react";
|
||||||
import { calculateTimeAgo, getFileURL } from "@plane/utils";
|
import { calculateTimeAgo, getFileURL } from "@plane/utils";
|
||||||
// hooks
|
// hooks
|
||||||
import { ActivityIcon, ActivityMessage, IssueLink } from "@/components/core";
|
import { ActivityIcon, ActivityMessage } from "@/components/core";
|
||||||
import { RichTextReadOnlyEditor } from "@/components/editor/rich-text-editor/rich-text-read-only-editor";
|
import { RichTextEditor } from "@/components/editor";
|
||||||
import { ActivitySettingsLoader } from "@/components/ui";
|
import { ActivitySettingsLoader } from "@/components/ui";
|
||||||
// constants
|
// constants
|
||||||
import { USER_ACTIVITY } from "@/constants/fetch-keys";
|
import { USER_ACTIVITY } from "@/constants/fetch-keys";
|
||||||
|
|
@ -96,7 +96,8 @@ export const ProfileActivityListPage: React.FC<Props> = observer((props) => {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="issue-comments-section p-0">
|
<div className="issue-comments-section p-0">
|
||||||
<RichTextReadOnlyEditor
|
<RichTextEditor
|
||||||
|
editable={false}
|
||||||
id={activityItem.id}
|
id={activityItem.id}
|
||||||
initialValue={
|
initialValue={
|
||||||
activityItem?.new_value !== "" ? activityItem.new_value : activityItem.old_value
|
activityItem?.new_value !== "" ? activityItem.new_value : activityItem.old_value
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { EditorContentWrapper } from "./editor-content";
|
||||||
|
|
||||||
type Props = IEditorProps & {
|
type Props = IEditorProps & {
|
||||||
children?: (editor: Editor) => React.ReactNode;
|
children?: (editor: Editor) => React.ReactNode;
|
||||||
|
editable: boolean;
|
||||||
extensions: Extensions;
|
extensions: Extensions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -21,6 +22,7 @@ export const EditorWrapper: React.FC<Props> = (props) => {
|
||||||
containerClassName,
|
containerClassName,
|
||||||
disabledExtensions,
|
disabledExtensions,
|
||||||
displayConfig = DEFAULT_DISPLAY_CONFIG,
|
displayConfig = DEFAULT_DISPLAY_CONFIG,
|
||||||
|
editable,
|
||||||
editorClassName = "",
|
editorClassName = "",
|
||||||
extensions,
|
extensions,
|
||||||
id,
|
id,
|
||||||
|
|
@ -39,7 +41,7 @@ export const EditorWrapper: React.FC<Props> = (props) => {
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
editable: true,
|
editable,
|
||||||
disabledExtensions,
|
disabledExtensions,
|
||||||
editorClassName,
|
editorClassName,
|
||||||
enableHistory: true,
|
enableHistory: true,
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ const LiteTextEditor: React.FC<ILiteTextEditorProps> = (props) => {
|
||||||
return resolvedExtensions;
|
return resolvedExtensions;
|
||||||
}, [externalExtensions, disabledExtensions, onEnterKeyPress]);
|
}, [externalExtensions, disabledExtensions, onEnterKeyPress]);
|
||||||
|
|
||||||
return <EditorWrapper {...props} extensions={extensions} />;
|
return <EditorWrapper {...props} editable extensions={extensions} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LiteTextEditorWithRef = forwardRef<EditorRefApi, ILiteTextEditorProps>((props, ref) => (
|
const LiteTextEditorWithRef = forwardRef<EditorRefApi, ILiteTextEditorProps>((props, ref) => (
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1 @@
|
||||||
export * from "./editor";
|
export * from "./editor";
|
||||||
export * from "./read-only-editor";
|
|
||||||
|
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
import { forwardRef, useCallback } from "react";
|
|
||||||
// plane editor extensions
|
|
||||||
import { RichTextReadOnlyEditorAdditionalExtensions } from "@/plane-editor/extensions/rich-text/read-only-extensions";
|
|
||||||
// types
|
|
||||||
import { EditorReadOnlyRefApi, IRichTextReadOnlyEditorProps } from "@/types";
|
|
||||||
// local imports
|
|
||||||
import { ReadOnlyEditorWrapper } from "../read-only-editor-wrapper";
|
|
||||||
|
|
||||||
const RichTextReadOnlyEditorWithRef = forwardRef<EditorReadOnlyRefApi, IRichTextReadOnlyEditorProps>((props, ref) => {
|
|
||||||
const { disabledExtensions, fileHandler, flaggedExtensions } = props;
|
|
||||||
|
|
||||||
const getExtensions = useCallback(() => {
|
|
||||||
const extensions = RichTextReadOnlyEditorAdditionalExtensions({
|
|
||||||
disabledExtensions,
|
|
||||||
fileHandler,
|
|
||||||
flaggedExtensions,
|
|
||||||
});
|
|
||||||
|
|
||||||
return extensions;
|
|
||||||
}, [disabledExtensions, fileHandler, flaggedExtensions]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ReadOnlyEditorWrapper
|
|
||||||
{...props}
|
|
||||||
extensions={getExtensions()}
|
|
||||||
forwardedRef={ref as React.MutableRefObject<EditorReadOnlyRefApi | null>}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
RichTextReadOnlyEditorWithRef.displayName = "RichReadOnlyEditorWithRef";
|
|
||||||
|
|
||||||
export { RichTextReadOnlyEditorWithRef };
|
|
||||||
|
|
@ -143,9 +143,11 @@ export interface IEditorProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ILiteTextEditorProps = IEditorProps;
|
export type ILiteTextEditorProps = IEditorProps;
|
||||||
export interface IRichTextEditorProps extends IEditorProps {
|
|
||||||
|
export type IRichTextEditorProps = IEditorProps & {
|
||||||
dragDropEnabled?: boolean;
|
dragDropEnabled?: boolean;
|
||||||
}
|
editable: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
export interface ICollaborativeDocumentEditorProps
|
export interface ICollaborativeDocumentEditorProps
|
||||||
extends Omit<IEditorProps, "extensions" | "initialValue" | "onEnterKeyPress" | "value"> {
|
extends Omit<IEditorProps, "extensions" | "initialValue" | "onEnterKeyPress" | "value"> {
|
||||||
|
|
@ -178,8 +180,6 @@ export interface IReadOnlyEditorProps
|
||||||
|
|
||||||
export type ILiteTextReadOnlyEditorProps = IReadOnlyEditorProps;
|
export type ILiteTextReadOnlyEditorProps = IReadOnlyEditorProps;
|
||||||
|
|
||||||
export type IRichTextReadOnlyEditorProps = IReadOnlyEditorProps;
|
|
||||||
|
|
||||||
export interface IDocumentReadOnlyEditorProps extends IReadOnlyEditorProps {
|
export interface IDocumentReadOnlyEditorProps extends IReadOnlyEditorProps {
|
||||||
embedHandler: TEmbedConfig;
|
embedHandler: TEmbedConfig;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ export {
|
||||||
LiteTextEditorWithRef,
|
LiteTextEditorWithRef,
|
||||||
LiteTextReadOnlyEditorWithRef,
|
LiteTextReadOnlyEditorWithRef,
|
||||||
RichTextEditorWithRef,
|
RichTextEditorWithRef,
|
||||||
RichTextReadOnlyEditorWithRef,
|
|
||||||
} from "@/components/editors";
|
} from "@/components/editors";
|
||||||
|
|
||||||
export { isCellSelection } from "@/extensions/table/table/utilities/is-cell-selection";
|
export { isCellSelection } from "@/extensions/table/table/utilities/is-cell-selection";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue