diff --git a/packages/editor/core/src/hooks/use-editor.tsx b/packages/editor/core/src/hooks/use-editor.tsx index 563cb5122..3c10f5d44 100644 --- a/packages/editor/core/src/hooks/use-editor.tsx +++ b/packages/editor/core/src/hooks/use-editor.tsx @@ -187,6 +187,24 @@ export const useEditor = ({ scrollSummary(editorRef.current, marking); }, isEditorReadyToDiscard: () => editorRef.current?.storage.image.uploadInProgress === false, + isEditorFocused: () => editorRef.current?.isFocused, + setFocusAtSavedSelection: () => { + if (!editorRef.current || editorRef.current.isDestroyed) { + console.error("Editor reference is not available or has been destroyed."); + return; + } + try { + let focusPosition = 0; + if (savedSelection) { + focusPosition = savedSelection.from; + } + const docSize = editorRef.current.state.doc.content.size; + const safePosition = Math.max(0, Math.min(focusPosition, docSize)); + editorRef.current.chain().focus().setTextSelection(safePosition).run(); + } catch (error) { + console.error("An error occurred while setting focus at position:", error); + } + }, setFocusAtPosition: (position: number) => { if (!editorRef.current || editorRef.current.isDestroyed) { console.error("Editor reference is not available or has been destroyed."); diff --git a/packages/editor/core/src/types/editor-ref-api.ts b/packages/editor/core/src/types/editor-ref-api.ts index b15ae943d..c0456d729 100644 --- a/packages/editor/core/src/types/editor-ref-api.ts +++ b/packages/editor/core/src/types/editor-ref-api.ts @@ -16,4 +16,6 @@ export interface EditorRefApi extends EditorReadOnlyRefApi { onStateChange: (callback: () => void) => () => void; setFocusAtPosition: (position: number) => void; isEditorReadyToDiscard: () => boolean; + isEditorFocused: () => boolean; + setFocusAtSavedSelection: () => void; } diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 2507aca36..f35a45e0f 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -139,6 +139,9 @@ export const CoreEditorExtensions = ({ }), Placeholder.configure({ placeholder: ({ editor, node }) => { + if (!editor.isFocused && editor.state.doc.content.size === 2) { + return "Focus by pressing /"; + } if (node.type.name === "heading") return `Heading ${node.attrs.level}`; if (editor.storage.image.uploadInProgress) return ""; diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx index 2c8df4618..f2b595c97 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/pages/(detail)/[pageId]/page.tsx @@ -20,6 +20,7 @@ import { PageEditorBody, PageEditorHeaderRoot } from "@/components/pages"; import { cn } from "@/helpers/common.helper"; // hooks import { usePage, useProjectPages } from "@/hooks/store"; +import useFocusOnSlash from "@/hooks/use-focus-on-slash"; const PageDetailsPage = observer(() => { // states @@ -29,6 +30,8 @@ const PageDetailsPage = observer(() => { // refs const editorRef = useRef(null); const readOnlyEditorRef = useRef(null); + // Use the custom hook to focus on the editor when "/" is pressed + useFocusOnSlash(editorRef); // router const router = useRouter(); const { workspaceSlug, projectId, pageId } = useParams(); diff --git a/web/core/hooks/use-focus-on-slash.ts b/web/core/hooks/use-focus-on-slash.ts new file mode 100644 index 000000000..e464f3239 --- /dev/null +++ b/web/core/hooks/use-focus-on-slash.ts @@ -0,0 +1,23 @@ +import { useEffect } from "react"; +import { EditorRefApi } from "@plane/document-editor"; + +const useFocusOnSlash = (editorRef: React.RefObject) => { + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (!editorRef.current?.isEditorFocused()) { + if (e.key === "/") { + e.preventDefault(); + editorRef.current?.setFocusAtSavedSelection(); + } + } + }; + + window.addEventListener("keydown", handleKeyDown); + + return () => { + window.removeEventListener("keydown", handleKeyDown); + }; + }, [editorRef]); +}; + +export default useFocusOnSlash;