From 3ec123dc5ac884bd3eb8aff6f39e67a9c0a043a8 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Thu, 25 Jul 2024 18:15:21 +0530 Subject: [PATCH 1/3] fix: image resizer error --- .../components/editors/document/editor.tsx | 3 +- .../editors/document/page-renderer.tsx | 8 +- .../editors/document/read-only-editor.tsx | 6 +- .../components/editors/editor-container.tsx | 7 +- .../components/editors/editor-content.tsx | 7 +- .../components/editors/editor-wrapper.tsx | 7 +- .../editors/read-only-editor-wrapper.tsx | 6 +- .../core/extensions/image/image-resize.tsx | 136 ++++++++++-------- .../core/extensions/mentions/extension.tsx | 3 +- .../src/core/extensions/slash-commands.tsx | 3 +- packages/editor/src/core/types/editor.ts | 3 +- .../peek-overview/comment/add-comment.tsx | 1 + .../comment/comment-detail-card.tsx | 3 +- .../issues/peek-overview/issue-details.tsx | 1 + .../core/modals/gpt-assistant-popover.tsx | 13 +- .../create-edit-modal/issue-description.tsx | 1 + .../components/issues/description-input.tsx | 1 + .../issue-activity/comments/comment-card.tsx | 3 +- .../components/issues/issue-modal/form.tsx | 1 + .../profile/activity/activity-list.tsx | 1 + .../activity/profile-activity-list.tsx | 1 + 21 files changed, 128 insertions(+), 87 deletions(-) diff --git a/packages/editor/src/core/components/editors/document/editor.tsx b/packages/editor/src/core/components/editors/document/editor.tsx index d39f1b99fc3..6576dacba7e 100644 --- a/packages/editor/src/core/components/editors/document/editor.tsx +++ b/packages/editor/src/core/components/editors/document/editor.tsx @@ -78,10 +78,11 @@ const DocumentEditor = (props: IDocumentEditor) => { return ( ); }; 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 5e1d1ef8a20..9254d52c654 100644 --- a/packages/editor/src/core/components/editors/document/page-renderer.tsx +++ b/packages/editor/src/core/components/editors/document/page-renderer.tsx @@ -21,11 +21,12 @@ type IPageRenderer = { editor: Editor; editorContainerClassName: string; hideDragHandle?: () => void; + id: string; tabIndex?: number; }; export const PageRenderer = (props: IPageRenderer) => { - const { tabIndex, editor, hideDragHandle, editorContainerClassName } = props; + const { editor, editorContainerClassName, hideDragHandle, id, tabIndex } = props; // states const [linkViewProps, setLinkViewProps] = useState(); const [isOpen, setIsOpen] = useState(false); @@ -130,10 +131,11 @@ export const PageRenderer = (props: IPageRenderer) => {
- + {editor && editor.isEditable && }
diff --git a/packages/editor/src/core/components/editors/document/read-only-editor.tsx b/packages/editor/src/core/components/editors/document/read-only-editor.tsx index 9b91d9782e0..b259574e437 100644 --- a/packages/editor/src/core/components/editors/document/read-only-editor.tsx +++ b/packages/editor/src/core/components/editors/document/read-only-editor.tsx @@ -13,6 +13,7 @@ import { TEmbedConfig } from "@/plane-editor/types"; import { EditorReadOnlyRefApi, IMentionHighlight } from "@/types"; interface IDocumentReadOnlyEditor { + id: string; initialValue: string; containerClassName: string; editorClassName?: string; @@ -30,6 +31,7 @@ const DocumentReadOnlyEditor = (props: IDocumentReadOnlyEditor) => { containerClassName, editorClassName = "", embedHandler, + id, initialValue, forwardedRef, tabIndex, @@ -58,7 +60,9 @@ const DocumentReadOnlyEditor = (props: IDocumentReadOnlyEditor) => { containerClassName, }); - return ; + return ( + + ); }; const DocumentReadOnlyEditorWithRef = forwardRef((props, ref) => ( diff --git a/packages/editor/src/core/components/editors/editor-container.tsx b/packages/editor/src/core/components/editors/editor-container.tsx index 7e515766b97..5c09f42e56f 100644 --- a/packages/editor/src/core/components/editors/editor-container.tsx +++ b/packages/editor/src/core/components/editors/editor-container.tsx @@ -4,14 +4,15 @@ import { Editor } from "@tiptap/react"; import { cn } from "@/helpers/common"; interface EditorContainerProps { + children: ReactNode; editor: Editor | null; editorContainerClassName: string; - children: ReactNode; hideDragHandle?: () => void; + id: string; } export const EditorContainer: FC = (props) => { - const { editor, editorContainerClassName, hideDragHandle, children } = props; + const { children, editor, editorContainerClassName, hideDragHandle, id } = props; const handleContainerClick = () => { if (!editor) return; @@ -54,7 +55,7 @@ export const EditorContainer: FC = (props) => { return (
= (props) => { - const { editor, tabIndex, children } = props; + const { editor, children, id, tabIndex } = props; return (
editor?.chain().focus(undefined, { scrollIntoView: false }).run()}> - {editor?.isActive("image") && editor?.isEditable && } + {editor?.isActive("image") && editor?.isEditable && } {children}
); diff --git a/packages/editor/src/core/components/editors/editor-wrapper.tsx b/packages/editor/src/core/components/editors/editor-wrapper.tsx index e5142eeba4c..e9d38432ccd 100644 --- a/packages/editor/src/core/components/editors/editor-wrapper.tsx +++ b/packages/editor/src/core/components/editors/editor-wrapper.tsx @@ -21,7 +21,7 @@ export const EditorWrapper: React.FC = (props) => { editorClassName = "", extensions, hideDragHandleOnMouseLeave, - id = "", + id, initialValue, fileHandler, forwardedRef, @@ -57,13 +57,14 @@ export const EditorWrapper: React.FC = (props) => { return ( {children?.(editor)}
- +
); diff --git a/packages/editor/src/core/components/editors/read-only-editor-wrapper.tsx b/packages/editor/src/core/components/editors/read-only-editor-wrapper.tsx index 25da4d9afb8..d75a5d53045 100644 --- a/packages/editor/src/core/components/editors/read-only-editor-wrapper.tsx +++ b/packages/editor/src/core/components/editors/read-only-editor-wrapper.tsx @@ -8,7 +8,7 @@ import { useReadOnlyEditor } from "@/hooks/use-read-only-editor"; import { IReadOnlyEditorProps } from "@/types"; export const ReadOnlyEditorWrapper = (props: IReadOnlyEditorProps) => { - const { containerClassName, editorClassName = "", initialValue, forwardedRef, mentionHandler } = props; + const { containerClassName, editorClassName = "", id, initialValue, forwardedRef, mentionHandler } = props; const editor = useReadOnlyEditor({ initialValue, @@ -24,9 +24,9 @@ export const ReadOnlyEditorWrapper = (props: IReadOnlyEditorProps) => { if (!editor) return null; return ( - +
- +
); diff --git a/packages/editor/src/core/extensions/image/image-resize.tsx b/packages/editor/src/core/extensions/image/image-resize.tsx index 6be8214d72e..25d5f70a4c7 100644 --- a/packages/editor/src/core/extensions/image/image-resize.tsx +++ b/packages/editor/src/core/extensions/image/image-resize.tsx @@ -2,75 +2,85 @@ import { useState } from "react"; import { Editor } from "@tiptap/react"; import Moveable from "react-moveable"; -export const ImageResizer = ({ editor }: { editor: Editor }) => { +type Props = { + editor: Editor; + id: string; +}; + +export const ImageResizer = (props: Props) => { + const { editor, id } = props; + // states + const [aspectRatio, setAspectRatio] = useState(1); + const updateMediaSize = () => { - const imageInfo = document.querySelector(".ProseMirror-selectednode") as HTMLImageElement; - if (imageInfo) { - const selection = editor.state.selection; + const imageElement = document.querySelector( + `#editor-container-${id}.active-editor .ProseMirror-seclectednode` + ) as HTMLImageElement; - // Use the style width/height if available, otherwise fall back to the element's natural width/height - const width = imageInfo.style.width - ? Number(imageInfo.style.width.replace("px", "")) - : imageInfo.getAttribute("width"); - const height = imageInfo.style.height - ? Number(imageInfo.style.height.replace("px", "")) - : imageInfo.getAttribute("height"); + if (!imageElement) return; - editor.commands.setImage({ - src: imageInfo.src, - width: width, - height: height, - } as any); - editor.commands.setNodeSelection(selection.from); - } - }; + const selection = editor.state.selection; - const [aspectRatio, setAspectRatio] = useState(1); + // Use the style width/height if available, otherwise fall back to the element's natural width/height + const width = imageElement.style.width + ? Number(imageElement.style.width.replace("px", "")) + : imageElement.getAttribute("width"); + const height = imageElement.style.height + ? Number(imageElement.style.height.replace("px", "")) + : imageElement.getAttribute("height"); + + editor.commands.setImage({ + src: imageElement.src, + width: width, + height: height, + } as any); + editor.commands.setNodeSelection(selection.from); + }; return ( - <> - { - const imageInfo = document.querySelector(".ProseMirror-selectednode") as HTMLImageElement; - if (imageInfo) { - const originalWidth = Number(imageInfo.width); - const originalHeight = Number(imageInfo.height); - setAspectRatio(originalWidth / originalHeight); - } - }} - onResize={({ target, width, height, delta }) => { - if (delta[0] || delta[1]) { - let newWidth, newHeight; - if (delta[0]) { - // Width change detected - newWidth = Math.max(width, 100); - newHeight = newWidth / aspectRatio; - } else if (delta[1]) { - // Height change detected - newHeight = Math.max(height, 100); - newWidth = newHeight * aspectRatio; - } - target.style.width = `${newWidth}px`; - target.style.height = `${newHeight}px`; + { + const imageElement = document.querySelector( + `#editor-container-${id}.active-editor .ProseMirror-selectednode` + ) as HTMLImageElement; + if (imageElement) { + const originalWidth = Number(imageElement.width); + const originalHeight = Number(imageElement.height); + setAspectRatio(originalWidth / originalHeight); + } + }} + onResize={({ target, width, height, delta }) => { + if (delta[0] || delta[1]) { + let newWidth, newHeight; + if (delta[0]) { + // Width change detected + newWidth = Math.max(width, 100); + newHeight = newWidth / aspectRatio; + } else if (delta[1]) { + // Height change detected + newHeight = Math.max(height, 100); + newWidth = newHeight * aspectRatio; } - }} - onResizeEnd={() => { - updateMediaSize(); - }} - scalable - renderDirections={["se"]} - onScale={({ target, transform }) => { - target.style.transform = transform; - }} - /> - + target.style.width = `${newWidth}px`; + target.style.height = `${newHeight}px`; + } + }} + onResizeEnd={() => { + updateMediaSize(); + }} + scalable + renderDirections={["se"]} + onScale={({ target, transform }) => { + target.style.transform = transform; + }} + /> ); }; diff --git a/packages/editor/src/core/extensions/mentions/extension.tsx b/packages/editor/src/core/extensions/mentions/extension.tsx index e5a447c7fe3..93453f625e6 100644 --- a/packages/editor/src/core/extensions/mentions/extension.tsx +++ b/packages/editor/src/core/extensions/mentions/extension.tsx @@ -91,7 +91,8 @@ export const CustomMention = ({ // @ts-expect-error - Tippy types are incorrect popup = tippy("body", { getReferenceClientRect: props.clientRect, - appendTo: () => document.querySelector(".active-editor") ?? document.querySelector("#editor-container"), + appendTo: () => + document.querySelector(".active-editor") ?? document.querySelector('[id^="editor-container"]'), content: component.element, showOnCreate: true, interactive: true, diff --git a/packages/editor/src/core/extensions/slash-commands.tsx b/packages/editor/src/core/extensions/slash-commands.tsx index a84ff5d1627..a61198db2bd 100644 --- a/packages/editor/src/core/extensions/slash-commands.tsx +++ b/packages/editor/src/core/extensions/slash-commands.tsx @@ -374,7 +374,8 @@ const renderItems = () => { editor: props.editor, }); - const tippyContainer = document.querySelector(".active-editor") ?? document.querySelector("#editor-container"); + const tippyContainer = + document.querySelector(".active-editor") ?? document.querySelector('[id^="editor-container"]'); // @ts-expect-error Tippy overloads are messed up popup = tippy("body", { diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 6fa243f8ab7..695082c11fc 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -29,7 +29,7 @@ export interface IEditorProps { editorClassName?: string; fileHandler: TFileHandler; forwardedRef?: React.MutableRefObject; - id?: string; + id: string; initialValue: string; mentionHandler: { highlights: () => Promise; @@ -52,6 +52,7 @@ export interface IReadOnlyEditorProps { containerClassName?: string; editorClassName?: string; forwardedRef?: React.MutableRefObject; + id: string; initialValue: string; mentionHandler: { highlights: () => Promise; diff --git a/space/core/components/issues/peek-overview/comment/add-comment.tsx b/space/core/components/issues/peek-overview/comment/add-comment.tsx index 60db5631487..a602538e00e 100644 --- a/space/core/components/issues/peek-overview/comment/add-comment.tsx +++ b/space/core/components/issues/peek-overview/comment/add-comment.tsx @@ -72,6 +72,7 @@ export const AddComment: React.FC = observer((props) => { workspaceId={workspaceID?.toString() ?? ""} workspaceSlug={workspaceSlug?.toString() ?? ""} ref={editorRef} + id="peek-overview-add-comment" initialValue={ !value || value === "" || (typeof value === "object" && Object.keys(value).length === 0) ? watch("comment_html") diff --git a/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx b/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx index 4f36cb55fbc..67738b524da 100644 --- a/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx +++ b/space/core/components/issues/peek-overview/comment/comment-detail-card.tsx @@ -105,6 +105,7 @@ export const CommentCard: React.FC = observer((props) => { workspaceSlug={workspaceSlug?.toString() ?? ""} onEnterKeyPress={() => handleSubmit(handleCommentUpdate)()} ref={editorRef} + id={comment.id} initialValue={value} value={null} onChange={(comment_json, comment_html) => onChange(comment_html)} @@ -132,7 +133,7 @@ export const CommentCard: React.FC = observer((props) => {
- +
diff --git a/space/core/components/issues/peek-overview/issue-details.tsx b/space/core/components/issues/peek-overview/issue-details.tsx index 8c24ad6441a..b47bfad68cb 100644 --- a/space/core/components/issues/peek-overview/issue-details.tsx +++ b/space/core/components/issues/peek-overview/issue-details.tsx @@ -26,6 +26,7 @@ export const PeekOverviewIssueDetails: React.FC = observer((props) => {

{issueDetails.name}

{description !== "" && description !== "

" && ( = (props) => { {prompt && (
Content: - +
)} {response !== "" && (
Response: - ${response}

`} ref={responseRef} /> + ${response}

`} + ref={responseRef} + />
)} {invalidResponse && ( diff --git a/web/core/components/inbox/modals/create-edit-modal/issue-description.tsx b/web/core/components/inbox/modals/create-edit-modal/issue-description.tsx index 7b9ef674972..18cd40944b1 100644 --- a/web/core/components/inbox/modals/create-edit-modal/issue-description.tsx +++ b/web/core/components/inbox/modals/create-edit-modal/issue-description.tsx @@ -42,6 +42,7 @@ export const InboxIssueDescription: FC = observer((props return (

" : data?.description_html} ref={editorRef} workspaceSlug={workspaceSlug} diff --git a/web/core/components/issues/description-input.tsx b/web/core/components/issues/description-input.tsx index f78bce8536d..b78f0b91f61 100644 --- a/web/core/components/issues/description-input.tsx +++ b/web/core/components/issues/description-input.tsx @@ -118,6 +118,7 @@ export const IssueDescriptionInput: FC = observer((p /> ) : ( diff --git a/web/core/components/issues/issue-detail/issue-activity/comments/comment-card.tsx b/web/core/components/issues/issue-detail/issue-activity/comments/comment-card.tsx index 8779e2cc95c..0ea9e8f15b2 100644 --- a/web/core/components/issues/issue-detail/issue-activity/comments/comment-card.tsx +++ b/web/core/components/issues/issue-detail/issue-activity/comments/comment-card.tsx @@ -143,6 +143,7 @@ export const IssueCommentCard: FC = observer((props) => { projectId={projectId} workspaceSlug={workspaceSlug} ref={editorRef} + id={comment.id} initialValue={watch("comment_html") ?? ""} value={null} onChange={(comment_json, comment_html) => setValue("comment_html", comment_html)} @@ -190,7 +191,7 @@ export const IssueCommentCard: FC = observer((props) => { )} )} - + = observer((props) => { control={control} render={({ field: { value, onChange } }) => ( = observer((props) => {
= observer((props) => {
Date: Thu, 25 Jul 2024 18:20:59 +0530 Subject: [PATCH 2/3] refactor: created common function to get the active image element --- .../src/core/extensions/image/image-resize.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/editor/src/core/extensions/image/image-resize.tsx b/packages/editor/src/core/extensions/image/image-resize.tsx index 25d5f70a4c7..c50e3189660 100644 --- a/packages/editor/src/core/extensions/image/image-resize.tsx +++ b/packages/editor/src/core/extensions/image/image-resize.tsx @@ -7,15 +7,16 @@ type Props = { id: string; }; +const getImageElement = (editorId: string): HTMLImageElement | null => + document.querySelector(`#editor-container-${editorId}.active-editor .ProseMirror-selectednode`); + export const ImageResizer = (props: Props) => { const { editor, id } = props; // states const [aspectRatio, setAspectRatio] = useState(1); const updateMediaSize = () => { - const imageElement = document.querySelector( - `#editor-container-${id}.active-editor .ProseMirror-seclectednode` - ) as HTMLImageElement; + const imageElement = getImageElement(id); if (!imageElement) return; @@ -39,7 +40,7 @@ export const ImageResizer = (props: Props) => { return ( { resizable throttleResize={0} onResizeStart={() => { - const imageElement = document.querySelector( - `#editor-container-${id}.active-editor .ProseMirror-selectednode` - ) as HTMLImageElement; + const imageElement = getImageElement(id); if (imageElement) { const originalWidth = Number(imageElement.width); const originalHeight = Number(imageElement.height); From 3a47173265a8d2007ef8b34f5859cd15ab055f0d Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Tue, 30 Jul 2024 14:16:32 +0530 Subject: [PATCH 3/3] fix: build errors --- web/core/components/pages/editor/editor-body.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/web/core/components/pages/editor/editor-body.tsx b/web/core/components/pages/editor/editor-body.tsx index 6bc1b2e7bcd..d142800ff88 100644 --- a/web/core/components/pages/editor/editor-body.tsx +++ b/web/core/components/pages/editor/editor-body.tsx @@ -153,6 +153,7 @@ export const PageEditorBody: React.FC = observer((props) => { ) : (

"} handleEditorReady={handleReadOnlyEditorReady} containerClassName="p-0 pb-64 border-none"