fix: make rich-text inline editor mobile keyboard-safe

https://sonarly.com/issue/40147?type=bug

Inline rich-text editing in the record field flow is rendered in a fixed-size floating overlay that is not adapted for mobile soft keyboards. On small viewports with long content, users cannot reliably reach the expand action or navigate content.

Fix: Implemented a production-focused fix in the frontend rendering path that caused the mobile inline rich-text editor to be unusable.

What I changed:

1) `packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/components/RichTextFieldInput.tsx`
- Kept the desktop baseline width, but made the floating editor container responsive and viewport-bounded:
  - added `max-width: calc(100vw - spacing)` so it no longer overflows narrow screens,
  - added `max-height: calc(100dvh - spacing)` and `overflow: auto` so content remains reachable when the visual viewport shrinks (soft keyboard).
- Added a mobile breakpoint (`MOBILE_VIEWPORT`) to remove the negative left margin and shrink left padding, preventing off-screen clipping in inline overlay mode.
- Ensured content/button layout remains stable by making the editor content flex (`flex: 1; min-width: 0`) and the collapse/expand action non-shrinking (`flex-shrink: 0`), so the expand action stays reachable.

2) `packages/twenty-front/src/modules/blocknote-editor/components/BlockEditor.tsx`
- Added mobile-specific editor min-height behavior:
  - on mobile breakpoint, `min-height: clamp(140px, 45dvh, 400px)`.
- This preserves desktop behavior while reducing the hard 400px pressure under soft-keyboard viewport shrink.

Why this fixes the reported issue:
- The inline overlay is no longer fixed to a desktop-only layout on mobile.
- The editor now adapts to reduced viewport height during keyboard usage.
- The expand action remains visible/reachable instead of being clipped out of the overlay.

I also checked recent history for this exact fix (`git log --all --oneline --since='30 days ago' -- <affected files>` + `git show` on candidates). Recent commits addressed BlockNote upload panel clipping/slash-menu behavior, not this inline mobile keyboard overlay path.

Authored by Sonarly by autonomous analysis (run 45750).
This commit is contained in:
sonarly-bot
2026-05-23 19:58:54 +00:00
parent 85d649e831
commit 45ee7bb32b
2 changed files with 29 additions and 2 deletions
@@ -17,7 +17,11 @@ import {
} from '@/blocknote-editor/components/CustomSlashMenu';
import { useMentionMenu } from '@/mention/hooks/useMentionMenu';
import { IconX } from 'twenty-ui/display';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
import {
MOBILE_VIEWPORT,
ThemeContext,
themeCssVariables,
} from 'twenty-ui/theme-constants';
interface BlockEditorProps {
editor: typeof BLOCK_SCHEMA.BlockNoteEditor;
@@ -37,6 +41,10 @@ const StyledEditor = styled.div`
color: ${themeCssVariables.font.color.primary};
font-size: 13px;
min-height: 400px;
@media (max-width: ${MOBILE_VIEWPORT}px) {
min-height: clamp(140px, 45dvh, 400px);
}
}
& .editor [class^='_inlineContent']:before {
color: ${themeCssVariables.font.color.tertiary};
@@ -14,7 +14,11 @@ import { Suspense, lazy, useContext, useRef } from 'react';
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
import { IconLayoutSidebarLeftCollapse } from 'twenty-ui/display';
import { FloatingIconButton } from 'twenty-ui/input';
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
import {
MOBILE_VIEWPORT,
ThemeContext,
themeCssVariables,
} from 'twenty-ui/theme-constants';
const ActivityRichTextEditor = lazy(() =>
import('@/activities/components/ActivityRichTextEditor').then((module) => ({
@@ -35,10 +39,24 @@ const StyledContainer = styled.div`
box-sizing: border-box;
display: flex;
margin: 0 0 0 calc(-1 * ${themeCssVariables.spacing[5]});
max-height: calc(100dvh - ${themeCssVariables.spacing[6]});
max-width: calc(100vw - ${themeCssVariables.spacing[4]});
overflow: auto;
padding: ${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[2]}
${themeCssVariables.spacing[2]} ${themeCssVariables.spacing[12]};
position: relative;
width: 480px;
& > *:first-child {
flex: 1;
min-width: 0;
}
@media (max-width: ${MOBILE_VIEWPORT}px) {
margin-left: 0;
padding-left: ${themeCssVariables.spacing[2]};
width: calc(100vw - ${themeCssVariables.spacing[4]});
}
`;
const StyledCollapseButton = styled.div`
@@ -46,6 +64,7 @@ const StyledCollapseButton = styled.div`
color: ${themeCssVariables.font.color.light};
cursor: pointer;
display: flex;
flex-shrink: 0;
`;
const LoadingSkeleton = () => {