From 69b64680d16a07777651373cea5a113c9486187a Mon Sep 17 00:00:00 2001 From: Vipin Chaudhary Date: Tue, 9 Dec 2025 21:13:20 +0530 Subject: [PATCH] [WIKI-829] fix: add option to only show placeholder on empty editor (#8232) * feat: add placeholderOnEmpty functionality to editor components * Update packages/editor/src/core/extensions/placeholder.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: rename placeholderOnEmpty to showPlaceholderOnEmpty across editor components * chore : make optional --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- apps/web/core/components/editor/lite-text/editor.tsx | 2 ++ .../src/core/components/editors/editor-wrapper.tsx | 2 ++ packages/editor/src/core/extensions/extensions.ts | 4 +++- packages/editor/src/core/extensions/placeholder.ts | 10 +++++++++- .../editor/src/core/hooks/use-collaborative-editor.ts | 2 ++ packages/editor/src/core/hooks/use-editor.ts | 2 ++ packages/editor/src/core/types/editor.ts | 1 + packages/editor/src/core/types/hook.ts | 2 ++ 8 files changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/web/core/components/editor/lite-text/editor.tsx b/apps/web/core/components/editor/lite-text/editor.tsx index 13e2c018e..4f43f2b57 100644 --- a/apps/web/core/components/editor/lite-text/editor.tsx +++ b/apps/web/core/components/editor/lite-text/editor.tsx @@ -72,6 +72,7 @@ export const LiteTextEditor = React.forwardRef(function LiteTextEditor( placeholder = t("issue.comments.placeholder"), disabledExtensions: additionalDisabledExtensions = [], editorClassName = "", + showPlaceholderOnEmpty = true, ...rest } = props; // states @@ -154,6 +155,7 @@ export const LiteTextEditor = React.forwardRef(function LiteTextEditor( }), }} placeholder={placeholder} + showPlaceholderOnEmpty={showPlaceholderOnEmpty} containerClassName={cn(containerClassName, "relative", { "p-2": !editable, })} diff --git a/packages/editor/src/core/components/editors/editor-wrapper.tsx b/packages/editor/src/core/components/editors/editor-wrapper.tsx index 14570a656..5c0ba9c24 100644 --- a/packages/editor/src/core/components/editors/editor-wrapper.tsx +++ b/packages/editor/src/core/components/editors/editor-wrapper.tsx @@ -41,6 +41,7 @@ export function EditorWrapper(props: Props) { handleEditorReady, autofocus, placeholder, + showPlaceholderOnEmpty, tabIndex, value, } = props; @@ -67,6 +68,7 @@ export function EditorWrapper(props: Props) { handleEditorReady, autofocus, placeholder, + showPlaceholderOnEmpty, tabIndex, value, }); diff --git a/packages/editor/src/core/extensions/extensions.ts b/packages/editor/src/core/extensions/extensions.ts index 79daaccef..460ae7dc3 100644 --- a/packages/editor/src/core/extensions/extensions.ts +++ b/packages/editor/src/core/extensions/extensions.ts @@ -47,6 +47,7 @@ type TArguments = Pick< | "isTouchDevice" | "mentionHandler" | "placeholder" + | "showPlaceholderOnEmpty" | "tabIndex" | "extendedEditorProps" > & { @@ -65,6 +66,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => { isTouchDevice = false, mentionHandler, placeholder, + showPlaceholderOnEmpty, tabIndex, editable, extendedEditorProps, @@ -108,7 +110,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => { TableCell, TableRow, CustomMentionExtension(mentionHandler), - CustomPlaceholderExtension({ placeholder }), + CustomPlaceholderExtension({ placeholder, showPlaceholderOnEmpty }), CharacterCount, CustomColorExtension, CustomTextAlignExtension, diff --git a/packages/editor/src/core/extensions/placeholder.ts b/packages/editor/src/core/extensions/placeholder.ts index 7a236332c..ade422d26 100644 --- a/packages/editor/src/core/extensions/placeholder.ts +++ b/packages/editor/src/core/extensions/placeholder.ts @@ -6,10 +6,11 @@ import type { IEditorProps } from "@/types"; type TArgs = { placeholder: IEditorProps["placeholder"]; + showPlaceholderOnEmpty: IEditorProps["showPlaceholderOnEmpty"]; }; export const CustomPlaceholderExtension = (args: TArgs) => { - const { placeholder } = args; + const { placeholder, showPlaceholderOnEmpty = false } = args; return Placeholder.configure({ placeholder: ({ editor, node }) => { @@ -29,6 +30,13 @@ export const CustomPlaceholderExtension = (args: TArgs) => { if (shouldHidePlaceholder) return ""; + if (showPlaceholderOnEmpty) { + const isDocumentEmpty = editor.state.doc.textContent.length === 0; + if (!isDocumentEmpty) { + return ""; + } + } + if (placeholder) { if (typeof placeholder === "string") return placeholder; else return placeholder(editor.isFocused, editor.getHTML()); diff --git a/packages/editor/src/core/hooks/use-collaborative-editor.ts b/packages/editor/src/core/hooks/use-collaborative-editor.ts index 4549f7ea6..80a9d760c 100644 --- a/packages/editor/src/core/hooks/use-collaborative-editor.ts +++ b/packages/editor/src/core/hooks/use-collaborative-editor.ts @@ -33,6 +33,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) => mentionHandler, onEditorFocus, placeholder, + showPlaceholderOnEmpty, realtimeConfig, serverHandler, tabIndex, @@ -119,6 +120,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) => onEditorFocus, onTransaction, placeholder, + showPlaceholderOnEmpty, provider, tabIndex, }); diff --git a/packages/editor/src/core/hooks/use-editor.ts b/packages/editor/src/core/hooks/use-editor.ts index 5328a3ea5..0ae81d9dc 100644 --- a/packages/editor/src/core/hooks/use-editor.ts +++ b/packages/editor/src/core/hooks/use-editor.ts @@ -40,6 +40,7 @@ export const useEditor = (props: TEditorHookProps) => { onEditorFocus, onTransaction, placeholder, + showPlaceholderOnEmpty, tabIndex, provider, value, @@ -70,6 +71,7 @@ export const useEditor = (props: TEditorHookProps) => { isTouchDevice, mentionHandler, placeholder, + showPlaceholderOnEmpty, tabIndex, provider, }), diff --git a/packages/editor/src/core/types/editor.ts b/packages/editor/src/core/types/editor.ts index 41b26e4db..2c7f9bbf3 100644 --- a/packages/editor/src/core/types/editor.ts +++ b/packages/editor/src/core/types/editor.ts @@ -164,6 +164,7 @@ export type IEditorProps = { onEnterKeyPress?: (e?: any) => void; onTransaction?: () => void; placeholder?: string | ((isFocused: boolean, value: string) => string); + showPlaceholderOnEmpty?: boolean; tabIndex?: number; value?: string | null; extendedEditorProps: IEditorPropsExtended; diff --git a/packages/editor/src/core/types/hook.ts b/packages/editor/src/core/types/hook.ts index bffd8d7e9..6036be6b8 100644 --- a/packages/editor/src/core/types/hook.ts +++ b/packages/editor/src/core/types/hook.ts @@ -29,6 +29,7 @@ export type TEditorHookProps = TCoreHookProps & | "onChange" | "onTransaction" | "placeholder" + | "showPlaceholderOnEmpty" | "tabIndex" | "value" > & { @@ -50,6 +51,7 @@ export type TCollaborativeEditorHookProps = TCoreHookProps & | "onChange" | "onTransaction" | "placeholder" + | "showPlaceholderOnEmpty" | "tabIndex" > & Pick<