diff --git a/.changeset/fix-floating-toolbar-mobile-placement-overlap.md b/.changeset/fix-floating-toolbar-mobile-placement-overlap.md new file mode 100644 index 0000000000..4ff4fd29a2 --- /dev/null +++ b/.changeset/fix-floating-toolbar-mobile-placement-overlap.md @@ -0,0 +1,5 @@ +--- +"www": patch +--- + +Fix `FloatingToolbar` overlapping with native mobile text selection context menus on mobile devices. Uses `useIsMobile` to set `placement: 'bottom'` on mobile viewports so custom floating toolbars render below selection instead of colliding with native mobile context menus. diff --git a/apps/www/src/registry/ui/floating-toolbar.tsx b/apps/www/src/registry/ui/floating-toolbar.tsx index f794bea9c6..206559fcad 100644 --- a/apps/www/src/registry/ui/floating-toolbar.tsx +++ b/apps/www/src/registry/ui/floating-toolbar.tsx @@ -17,6 +17,7 @@ import { usePluginOption, } from 'platejs/react'; +import { useIsMobile } from '@/hooks/use-mobile'; import { cn } from '@/lib/utils'; import { Toolbar } from './toolbar'; @@ -29,6 +30,7 @@ export function FloatingToolbar({ }: React.ComponentProps & { state?: FloatingToolbarState; }) { + const isMobile = useIsMobile(); const editorId = useEditorId(); const focusedEditorId = useEventEditorValue('focus'); const isFloatingLinkOpen = !!usePluginOption({ key: KEYS.link }, 'mode'); @@ -43,16 +45,23 @@ export function FloatingToolbar({ middleware: [ offset(12), flip({ - fallbackPlacements: [ - 'top-start', - 'top-end', - 'bottom-start', - 'bottom-end', - ], + fallbackPlacements: isMobile + ? [ + 'bottom-start', + 'bottom-end', + 'top-start', + 'top-end', + ] + : [ + 'top-start', + 'top-end', + 'bottom-start', + 'bottom-end', + ], padding: 12, }), ], - placement: 'top', + placement: isMobile ? 'bottom' : 'top', ...state?.floatingOptions, }, });