diff --git a/moon/apps/web/components/EditorBubbleMenu/EditorBubbleMenu.tsx b/moon/apps/web/components/EditorBubbleMenu/EditorBubbleMenu.tsx index f338b6339..326d75626 100644 --- a/moon/apps/web/components/EditorBubbleMenu/EditorBubbleMenu.tsx +++ b/moon/apps/web/components/EditorBubbleMenu/EditorBubbleMenu.tsx @@ -145,6 +145,48 @@ export const EditorBubbleMenu = memo(function EditorBubbleMemo({ } }, [closeLinkEditor, editor, linkEditorOpen, openLinkEditor, forceUpdate]) + // Handle clicking outside to hide menu + useEffect(() => { + if (typeof window === 'undefined' || !editor?.view?.dom) { + return + } + + const handleClickOutside = (event: Event) => { + const target = event.target as Node + const editorElement = editor?.view.dom + const menuElement = containerRef.current + + // Check if click is outside both editor and menu + if (editorElement && menuElement) { + const isClickInsideEditor = editorElement.contains(target) + const isClickInsideMenu = menuElement.contains(target) + + if (!isClickInsideEditor && !isClickInsideMenu) { + // Clear selection to hide the bubble menu + editor?.commands.setTextSelection(editor.state.selection.from) + // Also blur the editor to ensure menu hides + editor?.view.dom.blur() + } + } + } + + try { + document.addEventListener('mousedown', handleClickOutside) + } catch (error) { + // eslint-disable-next-line no-console + console.warn('Failed to add click outside listener:', error) + } + + return () => { + try { + document.removeEventListener('mousedown', handleClickOutside) + } catch (error) { + // eslint-disable-next-line no-console + console.warn('Failed to remove click outside listener:', error) + } + } + }, [editor]) + const containerRef = useRef(null) if (!editor) return null diff --git a/moon/apps/web/pages/[org]/mr/[id].tsx b/moon/apps/web/pages/[org]/mr/[id].tsx index ad1f11d8f..938c4f392 100644 --- a/moon/apps/web/pages/[org]/mr/[id].tsx +++ b/moon/apps/web/pages/[org]/mr/[id].tsx @@ -48,7 +48,7 @@ const MRDetailPage:PageWithLayout = () =>{ const id = typeof tempId === 'string' ? tempId : ''; const { data: MrDetailData, isLoading: detailIsLoading } = useGetMrDetail(id) const mrDetail = MrDetailData?.data as MRDetail | undefined - const UnderlinePanels = require('@primer/react/experimental') + const { UnderlinePanels } = require('@primer/react/experimental') if (mrDetail && typeof mrDetail.status === 'string') { mrDetail.status = mrDetail.status.toLowerCase();