From abce0ed946f4eec7574aa0e4df15e83e7859e92f Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Mon, 15 Apr 2024 20:00:02 +0530 Subject: [PATCH] [WEB-735] chore: added a custom placeholder prop to all the editors (#4194) * chore: added a custom placeholder prop to all the editors * chore: inbox issue create modal placeholder --- packages/editor/core/package.json | 3 +- packages/editor/core/src/hooks/use-editor.tsx | 17 +++++--- .../editor/core/src/ui/extensions/index.tsx | 39 ++++++++++++++++--- packages/editor/document-editor/package.json | 1 - .../src/ui/extensions/index.tsx | 25 +++--------- .../editor/document-editor/src/ui/index.tsx | 8 +++- .../editor/lite-text-editor/src/ui/index.tsx | 3 ++ packages/editor/rich-text-editor/package.json | 1 - .../src/ui/extensions/index.tsx | 27 ++++--------- .../editor/rich-text-editor/src/ui/index.tsx | 9 ++++- .../create-edit-modal/issue-description.tsx | 6 ++- web/components/issues/description-input.tsx | 10 +++++ web/components/issues/issue-modal/form.tsx | 4 ++ yarn.lock | 29 ++++---------- 14 files changed, 102 insertions(+), 80 deletions(-) diff --git a/packages/editor/core/package.json b/packages/editor/core/package.json index 2657d1c7a..8c3056e00 100644 --- a/packages/editor/core/package.json +++ b/packages/editor/core/package.json @@ -36,11 +36,11 @@ "@tiptap/extension-image": "^2.1.13", "@tiptap/extension-list-item": "^2.1.13", "@tiptap/extension-mention": "^2.1.13", + "@tiptap/extension-placeholder": "^2.3.0", "@tiptap/extension-task-item": "^2.1.13", "@tiptap/extension-task-list": "^2.1.13", "@tiptap/extension-text-style": "^2.1.13", "@tiptap/extension-underline": "^2.1.13", - "prosemirror-codemark": "^0.4.2", "@tiptap/pm": "^2.1.13", "@tiptap/react": "^2.1.13", "@tiptap/starter-kit": "^2.1.13", @@ -52,6 +52,7 @@ "linkifyjs": "^4.1.3", "lowlight": "^3.0.0", "lucide-react": "^0.294.0", + "prosemirror-codemark": "^0.4.2", "react-moveable": "^0.54.2", "tailwind-merge": "^1.14.0", "tippy.js": "^6.3.7", diff --git a/packages/editor/core/src/hooks/use-editor.tsx b/packages/editor/core/src/hooks/use-editor.tsx index 493071a36..e3ef76483 100644 --- a/packages/editor/core/src/hooks/use-editor.tsx +++ b/packages/editor/core/src/hooks/use-editor.tsx @@ -34,6 +34,7 @@ interface CustomEditorProps { suggestions?: () => Promise; }; handleEditorReady?: (value: boolean) => void; + placeholder?: string | ((isFocused: boolean) => string); } export const useEditor = ({ @@ -51,6 +52,7 @@ export const useEditor = ({ restoreFile, handleEditorReady, mentionHandler, + placeholder, }: CustomEditorProps) => { const editor = useCustomEditor({ editorProps: { @@ -58,15 +60,18 @@ export const useEditor = ({ ...editorProps, }, extensions: [ - ...CoreEditorExtensions( - { + ...CoreEditorExtensions({ + mentionConfig: { mentionSuggestions: mentionHandler.suggestions ?? (() => Promise.resolve([])), mentionHighlights: mentionHandler.highlights ?? [], }, - deleteFile, - restoreFile, - cancelUploadImage - ), + fileConfig: { + deleteFile, + restoreFile, + cancelUploadImage, + }, + placeholder, + }), ...extensions, ], content: typeof initialValue === "string" && initialValue.trim() !== "" ? initialValue : "

", diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index bf7f36067..0a9dd34ed 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -2,6 +2,7 @@ import TaskItem from "@tiptap/extension-task-item"; import TaskList from "@tiptap/extension-task-list"; import TextStyle from "@tiptap/extension-text-style"; import TiptapUnderline from "@tiptap/extension-underline"; +import Placeholder from "@tiptap/extension-placeholder"; import StarterKit from "@tiptap/starter-kit"; import { Markdown } from "tiptap-markdown"; @@ -29,15 +30,24 @@ import { CustomTypographyExtension } from "src/ui/extensions/typography"; import { CustomHorizontalRule } from "src/ui/extensions/horizontal-rule/horizontal-rule"; import { CustomCodeMarkPlugin } from "./custom-code-inline/inline-code-plugin"; -export const CoreEditorExtensions = ( +type TArguments = { mentionConfig: { mentionSuggestions?: () => Promise; mentionHighlights?: () => Promise; - }, - deleteFile: DeleteImage, - restoreFile: RestoreImage, - cancelUploadImage?: () => any -) => [ + }; + fileConfig: { + deleteFile: DeleteImage; + restoreFile: RestoreImage; + cancelUploadImage?: () => any; + }; + placeholder?: string | ((isFocused: boolean) => string); +}; + +export const CoreEditorExtensions = ({ + mentionConfig, + fileConfig: { deleteFile, restoreFile, cancelUploadImage }, + placeholder, +}: TArguments) => [ StarterKit.configure({ bulletList: { HTMLAttributes: { @@ -124,4 +134,21 @@ export const CoreEditorExtensions = ( mentionHighlights: mentionConfig.mentionHighlights, readonly: false, }), + Placeholder.configure({ + placeholder: ({ editor, node }) => { + if (node.type.name === "heading") return `Heading ${node.attrs.level}`; + + const shouldHidePlaceholder = + editor.isActive("table") || editor.isActive("codeBlock") || editor.isActive("image"); + if (shouldHidePlaceholder) return ""; + + if (placeholder) { + if (typeof placeholder === "string") return placeholder; + else return placeholder(editor.isFocused); + } + + return "Press '/' for commands..."; + }, + includeChildren: true, + }), ]; diff --git a/packages/editor/document-editor/package.json b/packages/editor/document-editor/package.json index be00fcce4..1443a124c 100644 --- a/packages/editor/document-editor/package.json +++ b/packages/editor/document-editor/package.json @@ -34,7 +34,6 @@ "@plane/ui": "*", "@tippyjs/react": "^4.2.6", "@tiptap/core": "^2.1.13", - "@tiptap/extension-placeholder": "^2.1.13", "@tiptap/pm": "^2.1.13", "@tiptap/suggestion": "^2.1.13", "lucide-react": "^0.309.0", diff --git a/packages/editor/document-editor/src/ui/extensions/index.tsx b/packages/editor/document-editor/src/ui/extensions/index.tsx index 6c106176b..b2816974e 100644 --- a/packages/editor/document-editor/src/ui/extensions/index.tsx +++ b/packages/editor/document-editor/src/ui/extensions/index.tsx @@ -1,28 +1,15 @@ -import Placeholder from "@tiptap/extension-placeholder"; import { IssueWidgetPlaceholder } from "src/ui/extensions/widgets/issue-embed-widget"; import { SlashCommand, DragAndDrop } from "@plane/editor-extensions"; import { UploadImage } from "@plane/editor-core"; -export const DocumentEditorExtensions = ( - uploadFile: UploadImage, - setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void -) => [ +type TArguments = { + uploadFile: UploadImage; + setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void; +}; + +export const DocumentEditorExtensions = ({ uploadFile, setHideDragHandle }: TArguments) => [ SlashCommand(uploadFile), DragAndDrop(setHideDragHandle), - Placeholder.configure({ - placeholder: ({ editor, node }) => { - if (node.type.name === "heading") { - return `Heading ${node.attrs.level}`; - } - - if (editor.isActive("table") || editor.isActive("codeBlock") || editor.isActive("image")) { - return ""; - } - - return "Press '/' for commands..."; - }, - includeChildren: true, - }), IssueWidgetPlaceholder(), ]; diff --git a/packages/editor/document-editor/src/ui/index.tsx b/packages/editor/document-editor/src/ui/index.tsx index 24e712d67..718127484 100644 --- a/packages/editor/document-editor/src/ui/index.tsx +++ b/packages/editor/document-editor/src/ui/index.tsx @@ -31,6 +31,7 @@ interface IDocumentEditor { suggestions: () => Promise; }; tabIndex?: number; + placeholder?: string | ((isFocused: boolean) => string); } const DocumentEditor = (props: IDocumentEditor) => { @@ -45,6 +46,7 @@ const DocumentEditor = (props: IDocumentEditor) => { handleEditorReady, forwardedRef, tabIndex, + placeholder, } = props; // states const [hideDragHandleOnMouseLeave, setHideDragHandleOnMouseLeave] = useState<() => void>(() => {}); @@ -69,7 +71,11 @@ const DocumentEditor = (props: IDocumentEditor) => { handleEditorReady, forwardedRef, mentionHandler, - extensions: DocumentEditorExtensions(fileHandler.upload, setHideDragHandleFunction), + extensions: DocumentEditorExtensions({ + uploadFile: fileHandler.upload, + setHideDragHandle: setHideDragHandleFunction, + }), + placeholder, }); const editorContainerClassNames = getEditorClassNames({ diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx index e610d071e..859bd4c9e 100644 --- a/packages/editor/lite-text-editor/src/ui/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -32,6 +32,7 @@ export interface ILiteTextEditor { suggestions?: () => Promise; }; tabIndex?: number; + placeholder?: string | ((isFocused: boolean) => string); } const LiteTextEditor = (props: ILiteTextEditor) => { @@ -46,6 +47,7 @@ const LiteTextEditor = (props: ILiteTextEditor) => { onEnterKeyPress, tabIndex, mentionHandler, + placeholder = "Add comment...", } = props; const editor = useEditor({ @@ -60,6 +62,7 @@ const LiteTextEditor = (props: ILiteTextEditor) => { forwardedRef, extensions: LiteTextEditorExtensions(onEnterKeyPress), mentionHandler, + placeholder, }); const editorContainerClassName = getEditorClassNames({ diff --git a/packages/editor/rich-text-editor/package.json b/packages/editor/rich-text-editor/package.json index 117cf5c41..ce4479600 100644 --- a/packages/editor/rich-text-editor/package.json +++ b/packages/editor/rich-text-editor/package.json @@ -32,7 +32,6 @@ "@plane/editor-core": "*", "@plane/editor-extensions": "*", "@tiptap/core": "^2.1.13", - "@tiptap/extension-placeholder": "^2.1.13", "lucide-react": "^0.294.0" }, "devDependencies": { diff --git a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx index 57d2e0d41..406fb677f 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx @@ -1,26 +1,13 @@ import { UploadImage } from "@plane/editor-core"; import { DragAndDrop, SlashCommand } from "@plane/editor-extensions"; -import Placeholder from "@tiptap/extension-placeholder"; -export const RichTextEditorExtensions = ( - uploadFile: UploadImage, - dragDropEnabled?: boolean, - setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void -) => [ +type TArguments = { + uploadFile: UploadImage; + dragDropEnabled?: boolean; + setHideDragHandle?: (hideDragHandlerFromDragDrop: () => void) => void; +}; + +export const RichTextEditorExtensions = ({ uploadFile, dragDropEnabled, setHideDragHandle }: TArguments) => [ SlashCommand(uploadFile), dragDropEnabled === true && DragAndDrop(setHideDragHandle), - Placeholder.configure({ - placeholder: ({ editor, node }) => { - if (node.type.name === "heading") { - return `Heading ${node.attrs.level}`; - } - - if (editor.isActive("table") || editor.isActive("codeBlock") || editor.isActive("image")) { - return ""; - } - - return "Press '/' for commands..."; - }, - includeChildren: true, - }), ]; diff --git a/packages/editor/rich-text-editor/src/ui/index.tsx b/packages/editor/rich-text-editor/src/ui/index.tsx index 33c14327e..9490d478e 100644 --- a/packages/editor/rich-text-editor/src/ui/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/index.tsx @@ -35,6 +35,7 @@ export type IRichTextEditor = { highlights: () => Promise; suggestions: () => Promise; }; + placeholder?: string | ((isFocused: boolean) => string); tabIndex?: number; }; @@ -50,6 +51,7 @@ const RichTextEditor = (props: IRichTextEditor) => { forwardedRef, // rerenderOnPropsChange, id = "", + placeholder, tabIndex, mentionHandler, } = props; @@ -74,8 +76,13 @@ const RichTextEditor = (props: IRichTextEditor) => { value, forwardedRef, // rerenderOnPropsChange, - extensions: RichTextEditorExtensions(fileHandler.upload, dragDropEnabled, setHideDragHandleFunction), + extensions: RichTextEditorExtensions({ + uploadFile: fileHandler.upload, + dragDropEnabled, + setHideDragHandle: setHideDragHandleFunction, + }), mentionHandler, + placeholder, }); const editorContainerClassName = getEditorClassNames({ diff --git a/web/components/inbox/modals/create-edit-modal/issue-description.tsx b/web/components/inbox/modals/create-edit-modal/issue-description.tsx index 313b94527..c749a6700 100644 --- a/web/components/inbox/modals/create-edit-modal/issue-description.tsx +++ b/web/components/inbox/modals/create-edit-modal/issue-description.tsx @@ -38,8 +38,10 @@ export const InboxIssueDescription: FC = observer((props workspaceId={workspaceId} projectId={projectId} dragDropEnabled={false} - onChange={(_description: object, description_html: string) => { - handleData("description_html", description_html); + onChange={(_description: object, description_html: string) => handleData("description_html", description_html)} + placeholder={(isFocused) => { + if (isFocused) return "Press '/' for commands..."; + else return "Click to add description"; }} /> diff --git a/web/components/issues/description-input.tsx b/web/components/issues/description-input.tsx index 0b9af36fa..aededa28f 100644 --- a/web/components/issues/description-input.tsx +++ b/web/components/issues/description-input.tsx @@ -19,6 +19,7 @@ export type IssueDescriptionInputProps = { initialValue: string | undefined; disabled?: boolean; issueOperations: TIssueOperations; + placeholder?: string | ((isFocused: boolean) => string); setIsSubmitting: (initialValue: "submitting" | "submitted" | "saved") => void; swrIssueDescription: string | null | undefined; }; @@ -33,6 +34,7 @@ export const IssueDescriptionInput: FC = observer((p initialValue, issueOperations, setIsSubmitting, + placeholder, } = props; const { handleSubmit, reset, control } = useForm({ @@ -103,6 +105,14 @@ export const IssueDescriptionInput: FC = observer((p onChange(description_html); debouncedFormSave(); }} + placeholder={ + placeholder + ? placeholder + : (isFocused) => { + if (isFocused) return "Press '/' for commands..."; + else return "Click to add description"; + } + } /> ) : ( = observer((props) => { }} ref={editorRef} tabIndex={getTabIndex("description_html")} + placeholder={(isFocused) => { + if (isFocused) return "Press '/' for commands..."; + else return "Click to add description"; + }} /> )} /> diff --git a/yarn.lock b/yarn.lock index 10ea0c35f..15daf8267 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2477,10 +2477,10 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.13.tgz#30f8ae3f8833c606b339f3554b9ffdbe1e604463" integrity sha512-cEoZBJrsQn69FPpUMePXG/ltGXtqKISgypj70PEHXt5meKDjpmMVSY4/8cXvFYEYsI9GvIwyAK0OrfAHiSoROA== -"@tiptap/extension-placeholder@^2.1.13": - version "2.1.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.13.tgz#b735591f719b9fe89c90dcc6327d2ef2851be510" - integrity sha512-vIY7y7UbqsrAW/y8bDE9eRenbQEU16kNHB5Wri8RU1YiUZpkPgdXP/pLqyjIIq95SwP/vdTIHjHoQ77VLRl1hA== +"@tiptap/extension-placeholder@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.3.0.tgz#db1f4375c8365c491211457c6d13f6efa486cd3a" + integrity sha512-1BOyxVLzyUYf6yOOeJ8CfpP6DSCS4L6HjBZqj6WP1z1NyBV8RAfhf3UuLNcimfSWAETXFR3g0ZbaxxWffI1cEg== "@tiptap/extension-strike@^2.1.13": version "2.1.13" @@ -7854,16 +7854,8 @@ streamx@^2.15.0: fast-fifo "^1.1.0" queue-tick "^1.0.1" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: + name string-width-cjs version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -7939,14 +7931,7 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==