From eb002df6c881abdc8a5b68f43f3eeffd899d86a6 Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Wed, 17 Sep 2025 20:31:16 +0530 Subject: [PATCH 1/3] fix: pane extensions close method moved into hook --- .../hooks/pages/use-pages-pane-extensions.ts | 9 ++ .../components/editor/lite-text/editor.tsx | 93 ++++++++++++------- .../editor/lite-text/lite-toolbar.tsx | 33 +++++++ .../components/pages/editor/page-root.tsx | 30 +++--- apps/web/core/constants/editor.ts | 11 ++- 5 files changed, 125 insertions(+), 51 deletions(-) create mode 100644 apps/web/core/components/editor/lite-text/lite-toolbar.tsx diff --git a/apps/web/ce/hooks/pages/use-pages-pane-extensions.ts b/apps/web/ce/hooks/pages/use-pages-pane-extensions.ts index cd405c1ca4e..b73ffc58b01 100644 --- a/apps/web/ce/hooks/pages/use-pages-pane-extensions.ts +++ b/apps/web/ce/hooks/pages/use-pages-pane-extensions.ts @@ -4,6 +4,7 @@ import type { EditorRefApi } from "@plane/editor"; import { PAGE_NAVIGATION_PANE_TAB_KEYS, PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM, + PAGE_NAVIGATION_PANE_VERSION_QUERY_PARAM, } from "@/components/pages/navigation-pane"; import { useAppRouter } from "@/hooks/use-app-router"; import { useQueryParams } from "@/hooks/use-query-params"; @@ -43,10 +44,18 @@ export const usePagesPaneExtensions = (_params: TPageExtensionHookParams) => { const navigationPaneExtensions: INavigationPaneExtension[] = []; + const handleCloseNavigationPane = useCallback(() => { + const updatedRoute = updateQueryParams({ + paramsToRemove: [PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM, PAGE_NAVIGATION_PANE_VERSION_QUERY_PARAM], + }); + router.push(updatedRoute); + }, [router, updateQueryParams]); + return { editorExtensionHandlers, navigationPaneExtensions, handleOpenNavigationPane, isNavigationPaneOpen, + handleCloseNavigationPane, }; }; diff --git a/apps/web/core/components/editor/lite-text/editor.tsx b/apps/web/core/components/editor/lite-text/editor.tsx index 42d6f0bd95c..0d4135bac0d 100644 --- a/apps/web/core/components/editor/lite-text/editor.tsx +++ b/apps/web/core/components/editor/lite-text/editor.tsx @@ -16,6 +16,7 @@ import { useMember } from "@/hooks/store/use-member"; import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; // plane web services import { WorkspaceService } from "@/plane-web/services"; +import { LiteToolbar } from "./lite-toolbar"; const workspaceService = new WorkspaceService(); type LiteTextEditorWrapperProps = MakeOptional< @@ -30,10 +31,12 @@ type LiteTextEditorWrapperProps = MakeOptional< showAccessSpecifier?: boolean; showSubmitButton?: boolean; isSubmitting?: boolean; + showLiteToolbar?: boolean; showToolbarInitially?: boolean; showToolbar?: boolean; issue_id?: string; parentClassName?: string; + editorClassName?: string; } & ( | { editable: false; @@ -60,9 +63,11 @@ export const LiteTextEditor = React.forwardRef !showToolbarInitially && setIsFocused(true)} onBlur={() => !showToolbarInitially && setIsFocused(false)} > - "", - workspaceId, - workspaceSlug, - })} - mentionHandler={{ - searchCallback: async (query) => { - const res = await fetchMentions(query); - if (!res) throw new Error("Failed in fetching mentions"); - return res; - }, - renderComponent: EditorMentionsRoot, - getMentionedEntityDetails: (id) => ({ - display_name: getUserDetails(id)?.display_name ?? "", - }), - }} - placeholder={placeholder} - containerClassName={cn(containerClassName, "relative", { - "p-2": !editable, - })} - extendedEditorProps={{}} - {...rest} - /> - {showToolbar && editable && ( + {/* Wrapper for lite toolbar layout */} +
+ {/* Main Editor - always rendered once */} +
+ "", + workspaceId, + workspaceSlug, + })} + mentionHandler={{ + searchCallback: async (query) => { + const res = await fetchMentions(query); + if (!res) throw new Error("Failed in fetching mentions"); + return res; + }, + renderComponent: EditorMentionsRoot, + getMentionedEntityDetails: (id) => ({ + display_name: getUserDetails(id)?.display_name ?? "", + }), + }} + placeholder={placeholder} + containerClassName={cn(containerClassName, "relative", { + "p-2": !editable, + })} + extendedEditorProps={{}} + editorClassName={editorClassName} + {...rest} + /> +
+ + {/* Lite Toolbar - conditionally rendered */} + {showLiteToolbar && editable && ( + { + // TODO: update this while toolbar homogenization + // @ts-expect-error type mismatch here + editorRef?.executeMenuItemCommand({ + itemKey: item.itemKey, + ...item.extraProps, + }); + }} + onSubmit={(e) => rest.onEnterKeyPress?.(e)} + isSubmitting={isSubmitting} + isEmpty={isEmpty} + /> + )} +
+ + {/* Full Toolbar - conditionally rendered */} + {showToolbar && editable && !showLiteToolbar && (
| React.MouseEvent) => void; + isSubmitting: boolean; + isEmpty: boolean; + executeCommand: (item: ToolbarMenuItem) => void; +}; + +export const LiteToolbar = ({ onSubmit, isSubmitting, isEmpty, executeCommand }: LiteToolbarProps) => ( +
+ + +
+); + +export type { LiteToolbarProps }; diff --git a/apps/web/core/components/pages/editor/page-root.tsx b/apps/web/core/components/pages/editor/page-root.tsx index 3159691e136..487592b0195 100644 --- a/apps/web/core/components/pages/editor/page-root.tsx +++ b/apps/web/core/components/pages/editor/page-root.tsx @@ -6,7 +6,6 @@ import type { TDocumentPayload, TPage, TPageVersion, TWebhookConnectionQueryPara // hooks import { useAppRouter } from "@/hooks/use-app-router"; import { usePageFallback } from "@/hooks/use-page-fallback"; -import { useQueryParams } from "@/hooks/use-query-params"; // plane web import import { PageModals } from "@/plane-web/components/pages"; import { usePagesPaneExtensions, useExtendedEditorProps } from "@/plane-web/hooks/pages"; @@ -14,11 +13,7 @@ import { EPageStoreType } from "@/plane-web/hooks/store"; // store import type { TPageInstance } from "@/store/pages/base-page"; // local imports -import { - PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM, - PAGE_NAVIGATION_PANE_VERSION_QUERY_PARAM, - PageNavigationPaneRoot, -} from "../navigation-pane"; +import { PageNavigationPaneRoot } from "../navigation-pane"; import { PageVersionsOverlay } from "../version"; import { PagesVersionEditor } from "../version/editor"; import { PageEditorBody, type TEditorBodyConfig, type TEditorBodyHandlers } from "./editor-body"; @@ -66,7 +61,6 @@ export const PageRoot = observer((props: TPageRootProps) => { hasConnectionFailed, updatePageDescription: handlers.updateDescription, }); - const { updateQueryParams } = useQueryParams(); const handleEditorReady = useCallback( (status: boolean) => { @@ -85,11 +79,16 @@ export const PageRoot = observer((props: TPageRootProps) => { }, [isContentEditable, setEditorRef]); // Get extensions and navigation logic from hook - const { editorExtensionHandlers, navigationPaneExtensions, handleOpenNavigationPane, isNavigationPaneOpen } = - usePagesPaneExtensions({ - page, - editorRef, - }); + const { + editorExtensionHandlers, + navigationPaneExtensions, + handleOpenNavigationPane, + handleCloseNavigationPane, + isNavigationPaneOpen, + } = usePagesPaneExtensions({ + page, + editorRef, + }); // Get extended editor extensions configuration const extendedEditorProps = useExtendedEditorProps({ @@ -118,13 +117,6 @@ export const PageRoot = observer((props: TPageRootProps) => { [setEditorRef] ); - const handleCloseNavigationPane = useCallback(() => { - const updatedRoute = updateQueryParams({ - paramsToRemove: [PAGE_NAVIGATION_PANE_TABS_QUERY_PARAM, PAGE_NAVIGATION_PANE_VERSION_QUERY_PARAM], - }); - router.push(updatedRoute); - }, [router, updateQueryParams]); - return (
diff --git a/apps/web/core/constants/editor.ts b/apps/web/core/constants/editor.ts index ff046b917df..c6bc2fef400 100644 --- a/apps/web/core/constants/editor.ts +++ b/apps/web/core/constants/editor.ts @@ -158,9 +158,18 @@ const USER_ACTION_ITEMS: ToolbarMenuItem<"quote" | "code">[] = [ { itemKey: "code", renderKey: "code", name: "Code", icon: Code2, editors: ["lite", "document"] }, ]; +export const IMAGE_ITEM = { + itemKey: "image", + renderKey: "image", + name: "Image", + icon: Image, + editors: ["lite", "document"], + extraProps: {}, +} as ToolbarMenuItem<"image">; + const COMPLEX_ITEMS: ToolbarMenuItem<"table" | "image">[] = [ { itemKey: "table", renderKey: "table", name: "Table", icon: Table, editors: ["document"] }, - { itemKey: "image", renderKey: "image", name: "Image", icon: Image, editors: ["lite", "document"], extraProps: {} }, + IMAGE_ITEM, ]; export const TOOLBAR_ITEMS: { From 2c2b86f150c92b39b17e7d20d6f04666f3181bf2 Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Thu, 18 Sep 2025 16:01:04 +0530 Subject: [PATCH 2/3] fix: editor build breaks web everytime in dev mode --- packages/editor/tsdown.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/tsdown.config.ts b/packages/editor/tsdown.config.ts index 348f1fd7a7e..5e9a7b960ad 100644 --- a/packages/editor/tsdown.config.ts +++ b/packages/editor/tsdown.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ outDir: "dist", format: ["esm", "cjs"], dts: true, - clean: true, + clean: false, sourcemap: true, copy: ["src/styles"], }); From 37a3978a6f05c906afcce0b15cdf742c04692af9 Mon Sep 17 00:00:00 2001 From: Palanikannan M Date: Thu, 18 Sep 2025 19:40:55 +0530 Subject: [PATCH 3/3] fix: variant of lite text toolbar --- .../components/editor/lite-text/editor.tsx | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/apps/web/core/components/editor/lite-text/editor.tsx b/apps/web/core/components/editor/lite-text/editor.tsx index 0d4135bac0d..7e1cf4f7617 100644 --- a/apps/web/core/components/editor/lite-text/editor.tsx +++ b/apps/web/core/components/editor/lite-text/editor.tsx @@ -14,7 +14,7 @@ import { useEditorConfig, useEditorMention } from "@/hooks/editor"; import { useMember } from "@/hooks/store/use-member"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; -// plane web services +// plane web service import { WorkspaceService } from "@/plane-web/services"; import { LiteToolbar } from "./lite-toolbar"; const workspaceService = new WorkspaceService(); @@ -31,9 +31,8 @@ type LiteTextEditorWrapperProps = MakeOptional< showAccessSpecifier?: boolean; showSubmitButton?: boolean; isSubmitting?: boolean; - showLiteToolbar?: boolean; showToolbarInitially?: boolean; - showToolbar?: boolean; + variant?: "full" | "lite" | "none"; issue_id?: string; parentClassName?: string; editorClassName?: string; @@ -62,8 +61,7 @@ export const LiteTextEditor = React.forwardRef !showToolbarInitially && setIsFocused(true)} - onBlur={() => !showToolbarInitially && setIsFocused(false)} + onFocus={() => isFullVariant && !showToolbarInitially && setIsFocused(true)} + onBlur={() => isFullVariant && !showToolbarInitially && setIsFocused(false)} > {/* Wrapper for lite toolbar layout */} -
+
{/* Main Editor - always rendered once */} -
+
{/* Lite Toolbar - conditionally rendered */} - {showLiteToolbar && editable && ( + {isLiteVariant && editable && ( { // TODO: update this while toolbar homogenization @@ -162,7 +162,7 @@ export const LiteTextEditor = React.forwardRef {/* Full Toolbar - conditionally rendered */} - {showToolbar && editable && !showLiteToolbar && ( + {isFullVariant && editable && (