From e5fea85351b56f10fb8bc21496e09725577bd88b Mon Sep 17 00:00:00 2001 From: kpark1208 <113814902+kpark1208@users.noreply.github.com> Date: Tue, 9 Dec 2025 05:52:58 -0500 Subject: [PATCH] fix : slash menu overflow causing page scroll (#16303) Issue : #15794 ## Context As shown in the linked issue, slash menu dropdown for rich text editor at bottom of notes editor screen extended beyond the page container, causing main page to scroll. ## Changes Made Added floating UI's `flip()` middleware to the component in `CustomSlashMenu.tsx` so that the menu automatically flips upward when detecting not enough space for dropdown. This prevents overflow beyond the page container. Additionally, added offset to menu when flipping up to prevent overlapping of the current line / caret. ## Results https://github.com/user-attachments/assets/47a79468-779c-4fd7-8e22-2b496456ea92 --------- Co-authored-by: Hyeonjae Park Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com> --- .../editor/components/CustomSlashMenu.tsx | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/packages/twenty-front/src/modules/ui/input/editor/components/CustomSlashMenu.tsx b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSlashMenu.tsx index c0b909d031..093c08f6b4 100644 --- a/packages/twenty-front/src/modules/ui/input/editor/components/CustomSlashMenu.tsx +++ b/packages/twenty-front/src/modules/ui/input/editor/components/CustomSlashMenu.tsx @@ -1,5 +1,6 @@ +import { useBlockNoteEditor } from '@blocknote/react'; import styled from '@emotion/styled'; -import { autoUpdate, useFloating } from '@floating-ui/react'; +import { autoUpdate, flip, offset, useFloating } from '@floating-ui/react'; import { motion } from 'framer-motion'; import { useEffect } from 'react'; import { createPortal } from 'react-dom'; @@ -7,9 +8,9 @@ import { createPortal } from 'react-dom'; import { SLASH_MENU_DROPDOWN_CLICK_OUTSIDE_ID } from '@/ui/input/constants/SlashMenuDropdownClickOutsideId'; import { SLASH_MENU_LIST_ID } from '@/ui/input/constants/SlashMenuListId'; import { CustomSlashMenuListItem } from '@/ui/input/editor/components/CustomSlashMenuListItem'; -import { - type CustomSlashMenuProps, - type SuggestionItem, +import type { + CustomSlashMenuProps, + SuggestionItem, } from '@/ui/input/editor/components/types'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; @@ -29,9 +30,32 @@ export const CustomSlashMenu = ({ items, selectedIndex, }: CustomSlashMenuProps) => { + const editor = useBlockNoteEditor(); + + const currentBlock = editor?.getTextCursorPosition()?.block; + const blockType = currentBlock?.type; + const headingLevel = + blockType === 'heading' ? (currentBlock?.props?.level as number) : null; + + const getOffsetValue = (placement: string) => { + if (!placement.startsWith('top')) return 0; + + switch (headingLevel) { + case 1: + return 65; + case 2: + return 50; + case 3: + return 45; + default: + return 40; + } + }; + const { refs, floatingStyles } = useFloating({ placement: 'bottom-start', whileElementsMounted: autoUpdate, + middleware: [flip(), offset(({ placement }) => getOffsetValue(placement))], }); const { setSelectedItemId } = useSelectableList(SLASH_MENU_LIST_ID);