Files
MindSift/frontend/src/features/workspace/MobileOutlineBar.tsx
T
sandrodachandClaude Opus 5.5 5982563579
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m51s
fix(mobile): outline bar only while the keyboard is open
The indent/move bar above the keyboard stayed after the keyboard was
closed (back button) because the bullet kept its focus, and covered the
bottom navigation. useKeyboardInset now reports keyboardOpen by
comparing the visible height with the height without keyboard, which
works whether the browser shrinks the page or only the visual viewport.

Release v0.27.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 21:18:05 +01:00

58 lines
2.4 KiB
TypeScript

import React from 'react';
import { createPortal } from 'react-dom';
import { ArrowDown, ArrowUp, IndentDecrease, IndentIncrease } from 'lucide-react';
import { useKeyboardInset } from '../../lib/useKeyboardInset';
// Phones and tablets have no Tab key: while a bullet is being edited, a slim bar sits right above the
// on-screen keyboard (only while it is open) with outdent / indent and move up / down (the bullet takes its children along).
export const isTouchOnly =
typeof window !== 'undefined' &&
!!window.matchMedia?.('(hover: none) and (pointer: coarse)').matches &&
!window.matchMedia?.('(any-pointer: fine)').matches;
interface MobileOutlineBarProps {
onOutdent: () => void;
onIndent: () => void;
onMoveUp: () => void;
onMoveDown: () => void;
}
export const MobileOutlineBar: React.FC<MobileOutlineBarProps> = ({ onOutdent, onIndent, onMoveUp, onMoveDown }) => {
// iOS keeps fixed elements behind the keyboard: lift the bar by the keyboard's height
const { inset, keyboardOpen } = useKeyboardInset();
const button = (label: string, icon: React.ReactNode, action: () => void) => (
<button
type="button"
aria-label={label}
title={label}
// Keep the focus (and the keyboard) in the bullet: no focus change on press, act on click
onPointerDown={(e) => e.preventDefault()}
onMouseDown={(e) => e.preventDefault()}
onClick={action}
className="h-10 flex-1 max-w-[4.5rem] flex items-center justify-center rounded-btn border border-border bg-canvas text-main active:bg-panel-elevated touch-manipulation"
>
{icon}
</button>
);
// Keyboard closed (e.g. back button) while the bullet keeps its focus: no bar over the bottom navigation
if (!keyboardOpen) return null;
return createPortal(
<div
className="fixed left-0 right-0 z-[70] flex items-center justify-center gap-2 px-3 py-1.5 bg-panel/95 backdrop-blur-md border-t border-border"
style={{ bottom: inset }}
role="toolbar"
aria-label="Punkt bearbeiten"
>
{button('Ausrücken', <IndentDecrease className="w-5 h-5" />, onOutdent)}
{button('Einrücken', <IndentIncrease className="w-5 h-5" />, onIndent)}
<span className="w-px h-6 bg-border mx-1" aria-hidden />
{button('Nach oben', <ArrowUp className="w-5 h-5" />, onMoveUp)}
{button('Nach unten', <ArrowDown className="w-5 h-5" />, onMoveDown)}
</div>,
document.body
);
};