MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m25s
- FormSheet: create dialogs (task list, shopping list, folder) as bottom sheet right above the on-screen keyboard (visualViewport), large fields; centred or anchored dialog on desktop - Emoji picker: category icons keep their sprite size (no doubled icons, round highlight), one 'Zuletzt verwendet' (library category, German names), sheet and picker height follow the keyboard - Mobile header no longer repeats the current section next to the logo Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
28 lines
1.2 KiB
TypeScript
28 lines
1.2 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
|
|
// Space the on-screen keyboard takes at the bottom (0 without keyboard) and the height that stays
|
|
// visible. Fixed bottom sheets use it to sit right above the keyboard instead of behind it (iOS keeps
|
|
// fixed elements on the layout viewport; on Android the inset is usually 0 because the page shrinks).
|
|
export function useKeyboardInset(): { inset: number; visibleHeight: number } {
|
|
const read = () => {
|
|
const vv = typeof window !== 'undefined' ? window.visualViewport : null;
|
|
if (!vv) return { inset: 0, visibleHeight: typeof window !== 'undefined' ? window.innerHeight : 0 };
|
|
return { inset: Math.max(0, Math.round(window.innerHeight - vv.height - vv.offsetTop)), visibleHeight: Math.round(vv.height) };
|
|
};
|
|
const [state, setState] = useState(read);
|
|
|
|
useEffect(() => {
|
|
const vv = window.visualViewport;
|
|
if (!vv) return;
|
|
const update = () => setState(read());
|
|
vv.addEventListener('resize', update);
|
|
vv.addEventListener('scroll', update);
|
|
update();
|
|
return () => {
|
|
vv.removeEventListener('resize', update);
|
|
vv.removeEventListener('scroll', update);
|
|
};
|
|
}, []);
|
|
return state;
|
|
}
|