🚜 refactor: added a common place for all LiteTextEditor and it's read only instances

This commit is contained in:
Palanikannan1437 2024-01-11 17:42:15 +05:30
parent ae9c729fc7
commit ce987833b7
17 changed files with 136 additions and 89 deletions

View File

@ -1,3 +1,4 @@
export { LiteTextEditor, LiteTextEditorWithRef } from "src/ui";
export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "src/ui/read-only";
export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-core";
export type { LiteTextEditorProps, ILiteTextEditor } from "src/ui";
export type { LiteTextEditorReadOnlyProps, ILiteReadOnlyEditor } from "src/ui/read-only";

View File

@ -12,12 +12,11 @@ import {
import { FixedMenu } from "src/ui/menus/fixed-menu";
import { LiteTextEditorExtensions } from "src/ui/extensions";
interface ILiteTextEditor {
export type ILiteTextEditor = {
value: string;
uploadFile: UploadImage;
deleteFile: DeleteImage;
restoreFile: RestoreImage;
noBorder?: boolean;
borderOnFocus?: boolean;
customClassName?: string;
@ -42,9 +41,9 @@ interface ILiteTextEditor {
mentionHighlights?: string[];
mentionSuggestions?: IMentionSuggestion[];
submitButton?: React.ReactNode;
}
};
interface LiteTextEditorProps extends ILiteTextEditor {
export interface LiteTextEditorProps extends ILiteTextEditor {
forwardedRef?: React.Ref<EditorHandle>;
}

View File

@ -1,16 +1,16 @@
import * as React from "react";
import { EditorContainer, EditorContentWrapper, getEditorClassNames, useReadOnlyEditor } from "@plane/editor-core";
interface ICoreReadOnlyEditor {
export type ILiteReadOnlyEditor = {
value: string;
editorContentCustomClassNames?: string;
noBorder?: boolean;
borderOnFocus?: boolean;
customClassName?: string;
mentionHighlights: string[];
}
};
interface EditorCoreProps extends ICoreReadOnlyEditor {
export interface LiteTextEditorReadOnlyProps extends ILiteReadOnlyEditor {
forwardedRef?: React.Ref<EditorHandle>;
}
@ -27,7 +27,7 @@ const LiteReadOnlyEditor = ({
value,
forwardedRef,
mentionHighlights,
}: EditorCoreProps) => {
}: LiteTextEditorReadOnlyProps) => {
const editor = useReadOnlyEditor({
value,
forwardedRef,
@ -51,7 +51,7 @@ const LiteReadOnlyEditor = ({
);
};
const LiteReadOnlyEditorWithRef = React.forwardRef<EditorHandle, ICoreReadOnlyEditor>((props, ref) => (
const LiteReadOnlyEditorWithRef = React.forwardRef<EditorHandle, ILiteReadOnlyEditor>((props, ref) => (
<LiteReadOnlyEditor {...props} forwardedRef={ref} />
));

View File

@ -1,4 +1,3 @@
export { RichTextEditor, RichTextEditorWithRef } from "src/ui";
export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "src/ui/read-only";
export type { RichTextEditorProps, IRichTextEditor } from "src/ui";
export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-core";

View File

@ -0,0 +1,41 @@
import React from "react";
import { LiteTextEditorWithRef, ILiteTextEditor } from "@plane/lite-text-editor";
import { useMention } from "hooks/store";
import { FileService } from "services/file.service";
interface EditorHandle {
clearEditor: () => void;
setEditorValue: (content: string) => void;
}
interface LiteTextEditorWrapperProps
extends Omit<
ILiteTextEditor,
"uploadFile" | "deleteFile" | "restoreFile" | "mentionSuggestions" | "mentionHighlights"
> {
workspaceSlug: string;
}
const fileService = new FileService();
export const LiteTextEditor = React.forwardRef<EditorHandle, LiteTextEditorWrapperProps>(
({ workspaceSlug, ...props }, ref) => {
const editorSuggestions = useMention();
return (
<LiteTextEditorWithRef
ref={ref}
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
deleteFile={fileService.deleteImage}
restoreFile={fileService.restoreImage}
mentionSuggestions={editorSuggestions.mentionSuggestions}
mentionHighlights={editorSuggestions.mentionHighlights}
{...props}
/>
);
}
);
LiteTextEditor.displayName = "LiteTextEditor";

View File

@ -0,0 +1,21 @@
import React from "react";
import { ILiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
import { useMention } from "hooks/store";
interface EditorHandle {
clearEditor: () => void;
setEditorValue: (content: string) => void;
}
interface LiteTextReadOnlyEditorWrapperProps extends Omit<ILiteReadOnlyEditor, "mentionHighlights"> {}
export const LiteTextReadOnlyEditor = React.forwardRef<EditorHandle, LiteTextReadOnlyEditorWrapperProps>(
({ ...props }, ref) => {
const editorSuggestions = useMention();
return <LiteReadOnlyEditorWithRef ref={ref} mentionHighlights={editorSuggestions.mentionHighlights} {...props} />;
}
);
LiteTextReadOnlyEditor.displayName = "LiteTextReadOnlyEditor";

View File

@ -0,0 +1,41 @@
import React from "react";
import { RichTextEditorWithRef, IRichTextEditor } from "@plane/rich-text-editor";
import { useMention } from "hooks/store";
import { FileService } from "services/file.service";
interface EditorHandle {
clearEditor: () => void;
setEditorValue: (content: string) => void;
}
interface RichTextEditorWrapperProps
extends Omit<
IRichTextEditor,
"uploadFile" | "deleteFile" | "restoreFile" | "mentionSuggestions" | "mentionHighlights"
> {
workspaceSlug: string;
}
const fileService = new FileService();
export const RichTextEditor = React.forwardRef<EditorHandle, RichTextEditorWrapperProps>(
({ workspaceSlug, ...props }, ref) => {
const editorSuggestions = useMention();
return (
<RichTextEditorWithRef
ref={ref}
uploadFile={fileService.getUploadFileFunction(workspaceSlug)}
deleteFile={fileService.deleteImage}
restoreFile={fileService.restoreImage}
mentionSuggestions={editorSuggestions.mentionSuggestions}
mentionHighlights={editorSuggestions.mentionHighlights}
{...props}
/>
);
}
);
RichTextEditor.displayName = "RichTextEditor";

View File

@ -12,7 +12,7 @@ import { AIService } from "services/ai.service";
// components
import { GptAssistantPopover } from "components/core";
import { PriorityDropdown } from "components/dropdowns";
import { RichTextEditor } from "components/editor/rich-text-wrapper";
import { RichTextEditor } from "components/editor/rich-text-editor";
// ui
import { Button, Input, ToggleSwitch } from "@plane/ui";
// types

View File

@ -1,12 +1,8 @@
import React from "react";
import { useRouter } from "next/router";
import { useForm, Controller } from "react-hook-form";
// hooks
import { useMention } from "hooks/store";
// services
import { FileService } from "services/file.service";
// components
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
import { LiteTextEditor } from "components/editor/lite-text-editor";
// ui
import { Button } from "@plane/ui";
import { Globe2, Lock } from "lucide-react";
@ -42,17 +38,12 @@ const commentAccess: commentAccessType[] = [
},
];
// services
const fileService = new FileService();
export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAccessSpecifier = false }) => {
// refs
const editorRef = React.useRef<any>(null);
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// store hooks
const { mentionHighlights, mentionSuggestions } = useMention();
// form info
const {
control,
@ -82,25 +73,19 @@ export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit, showAc
name="comment_html"
control={control}
render={({ field: { onChange: onCommentChange, value: commentValue } }) => (
<LiteTextEditorWithRef
<LiteTextEditor
workspaceSlug={workspaceSlug as string}
onEnterKeyPress={handleSubmit(handleAddComment)}
cancelUploadImage={fileService.cancelUpload}
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
deleteFile={fileService.deleteImage}
restoreFile={fileService.restoreImage}
ref={editorRef}
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
customClassName="p-2 h-full"
editorContentCustomClassNames="min-h-[35px]"
debouncedUpdatesEnabled={false}
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
commentAccessSpecifier={
showAccessSpecifier
? { accessValue: accessValue ?? "INTERNAL", onAccessChange, showAccessSpecifier, commentAccess }
: undefined
}
mentionSuggestions={mentionSuggestions}
mentionHighlights={mentionHighlights}
submitButton={
<Button
variant="primary"

View File

@ -2,23 +2,20 @@ import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { observer } from "mobx-react-lite";
// hooks
import { useMention, useUser } from "hooks/store";
// services
import { FileService } from "services/file.service";
import { useUser } from "hooks/store";
// icons
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
// ui
import { CustomMenu } from "@plane/ui";
import { CommentReaction } from "components/issues";
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
// components
import { LiteTextEditor } from "components/editor/lite-text-editor";
import { LiteTextReadOnlyEditor } from "components/editor/lite-text-read-only-editor";
// helpers
import { calculateTimeAgo } from "helpers/date-time.helper";
// types
import type { IIssueActivity } from "@plane/types";
// services
const fileService = new FileService();
type Props = {
comment: IIssueActivity;
handleCommentDeletion: (comment: string) => void;
@ -36,7 +33,6 @@ export const CommentCard: React.FC<Props> = observer((props) => {
const showEditorRef = React.useRef<any>(null);
// store hooks
const { currentUser } = useUser();
const { mentionHighlights, mentionSuggestions } = useMention();
// form info
const {
formState: { isSubmitting },
@ -97,19 +93,14 @@ export const CommentCard: React.FC<Props> = observer((props) => {
<div className="issue-comments-section p-0">
<form className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}>
<div>
<LiteTextEditorWithRef
<LiteTextEditor
workspaceSlug={workspaceSlug}
onEnterKeyPress={handleSubmit(onEnter)}
cancelUploadImage={fileService.cancelUpload}
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
deleteFile={fileService.deleteImage}
restoreFile={fileService.restoreImage}
ref={editorRef}
value={watch("comment_html") ?? ""}
debouncedUpdatesEnabled={false}
customClassName="min-h-[50px] p-3 shadow-sm"
onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)}
mentionSuggestions={mentionSuggestions}
mentionHighlights={mentionHighlights}
/>
</div>
<div className="flex gap-1 self-end">
@ -136,11 +127,10 @@ export const CommentCard: React.FC<Props> = observer((props) => {
{comment.access === "INTERNAL" ? <Lock className="h-3 w-3" /> : <Globe2 className="h-3 w-3" />}
</div>
)}
<LiteReadOnlyEditorWithRef
<LiteTextReadOnlyEditor
ref={showEditorRef}
value={comment.comment_html ?? ""}
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
mentionHighlights={mentionHighlights}
/>
<CommentReaction projectId={comment.project} commentId={comment.id} />
</div>

View File

@ -5,7 +5,7 @@ import useReloadConfirmations from "hooks/use-reload-confirmation";
import debounce from "lodash/debounce";
// components
import { TextArea } from "@plane/ui";
import { RichTextEditor } from "components/editor/rich-text-wrapper";
import { RichTextEditor } from "components/editor/rich-text-editor";
// types
import { TIssue } from "@plane/types";
import { TIssueOperations } from "./issue-detail";

View File

@ -25,7 +25,7 @@ import { ParentIssuesListModal } from "components/issues";
import { IssueLabelSelect } from "components/issues/select";
import { CreateLabelModal } from "components/labels";
import { CreateStateModal } from "components/states";
import { RichTextEditor } from "components/editor/rich-text-wrapper";
import { RichTextEditor } from "components/editor/rich-text-editor";
// ui
import { Button, CustomMenu, Input, ToggleSwitch } from "@plane/ui";
// helpers

View File

@ -9,7 +9,7 @@ import useToast from "hooks/use-toast";
// services
import { AIService } from "services/ai.service";
// components
import { RichTextEditor } from "components/editor/rich-text-wrapper";
import { RichTextEditor } from "components/editor/rich-text-editor";
import { GptAssistantPopover } from "components/core";
import {
CycleDropdown,

View File

@ -1,23 +1,17 @@
import React, { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { Check, Globe2, Lock, MessageSquare, Pencil, Trash2, X } from "lucide-react";
// hooks
import { useMention } from "hooks/store";
// services
import { FileService } from "services/file.service";
// ui
import { CustomMenu } from "@plane/ui";
import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor";
// components
import { IssueCommentReaction } from "./comment-reaction";
import { LiteTextReadOnlyEditor } from "components/editor/lite-text-read-only-editor";
import { LiteTextEditor } from "components/editor/lite-text-editor";
// helpers
import { calculateTimeAgo } from "helpers/date-time.helper";
// types
import type { IIssueActivity, IUser } from "@plane/types";
// services
const fileService = new FileService();
type IIssueCommentCard = {
comment: IIssueActivity;
handleCommentDeletion: (comment: string) => void;
@ -49,8 +43,6 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
// refs
const editorRef = React.useRef<any>(null);
const showEditorRef = React.useRef<any>(null);
// store hooks
const { mentionHighlights, mentionSuggestions } = useMention();
// form info
const {
formState: { isSubmitting },
@ -113,19 +105,14 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
<div className="issue-comments-section p-0">
<div className={`flex-col gap-2 ${isEditing ? "flex" : "hidden"}`}>
<div>
<LiteTextEditorWithRef
<LiteTextEditor
workspaceSlug={workspaceSlug}
onEnterKeyPress={handleSubmit(formSubmit)}
cancelUploadImage={fileService.cancelUpload}
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
deleteFile={fileService.deleteImage}
restoreFile={fileService.restoreImage}
ref={editorRef}
value={watch("comment_html") ?? ""}
debouncedUpdatesEnabled={false}
customClassName="min-h-[50px] p-3 shadow-sm"
onChange={(comment_json: Object, comment_html: string) => setValue("comment_html", comment_html)}
mentionSuggestions={mentionSuggestions}
mentionHighlights={mentionHighlights}
/>
</div>
<div className="flex gap-1 self-end">
@ -154,13 +141,11 @@ export const IssueCommentCard: React.FC<IIssueCommentCard> = (props) => {
{comment.access === "INTERNAL" ? <Lock className="h-3 w-3" /> : <Globe2 className="h-3 w-3" />}
</div>
)}
<LiteReadOnlyEditorWithRef
<LiteTextReadOnlyEditor
ref={showEditorRef}
value={comment.comment_html ?? ""}
customClassName="text-xs border border-custom-border-200 bg-custom-background-100"
mentionHighlights={mentionHighlights}
/>
<div className="mt-1">
<IssueCommentReaction
workspaceSlug={workspaceSlug}

View File

@ -2,12 +2,8 @@ import React from "react";
import { useRouter } from "next/router";
import { useForm, Controller } from "react-hook-form";
import { Globe2, Lock } from "lucide-react";
// hooks
import { useMention } from "hooks/store";
// services
import { FileService } from "services/file.service";
// components
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
import { LiteTextEditor } from "components/editor/lite-text-editor";
// ui
import { Button } from "@plane/ui";
// types
@ -42,9 +38,6 @@ const commentAccess: commentAccessType[] = [
},
];
// services
const fileService = new FileService();
export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
const { disabled = false, onSubmit, showAccessSpecifier = false } = props;
// refs
@ -52,8 +45,6 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// store hooks
const { mentionHighlights, mentionSuggestions } = useMention();
// form info
const {
control,
@ -83,19 +74,13 @@ export const IssueCommentEditor: React.FC<IIssueCommentEditor> = (props) => {
name="comment_html"
control={control}
render={({ field: { onChange: onCommentChange, value: commentValue } }) => (
<LiteTextEditorWithRef
<LiteTextEditor
workspaceSlug={workspaceSlug as string}
onEnterKeyPress={handleSubmit(handleAddComment)}
cancelUploadImage={fileService.cancelUpload}
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
deleteFile={fileService.deleteImage}
restoreFile={fileService.restoreImage}
ref={editorRef}
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
customClassName="p-2 h-full"
editorContentCustomClassNames="min-h-[35px]"
debouncedUpdatesEnabled={false}
mentionSuggestions={mentionSuggestions}
mentionHighlights={mentionHighlights}
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
commentAccessSpecifier={
showAccessSpecifier

View File

@ -5,7 +5,7 @@ import { Controller, useForm } from "react-hook-form";
import { useProject, useUser } from "hooks/store";
import useReloadConfirmations from "hooks/use-reload-confirmation";
// components
import { RichTextEditor } from "components/editor/rich-text-wrapper";
import { RichTextEditor } from "components/editor/rich-text-editor";
import { IssuePeekOverviewReactions } from "components/issues";
// ui
import { TextArea } from "@plane/ui";