a tool for shared writing and social publishing
at main 2.3 kB view raw
1"use client"; 2import { useEffect, useState } from "react"; 3import { isIOS } from "src/utils/isDevice"; 4 5export function ViewportSizeLayout(props: { children: React.ReactNode }) { 6 let viewheight = useViewportSize().height; 7 let difference = useViewportDifference(); 8 return ( 9 <div 10 style={{ 11 height: 12 isIOS() && difference !== 0 13 ? `calc(${viewheight}px + 10px)` 14 : "calc(100% + env(safe-area-inset-top)", 15 }} 16 > 17 {props.children} 18 </div> 19 ); 20} 21 22function useViewportDifference(): number { 23 let [difference, setDifference] = useState(0); 24 25 useEffect(() => { 26 // Use visualViewport api to track available height even on iOS virtual keyboard opening 27 let onResize = () => { 28 setDifference(window.innerHeight - getViewportSize().height); 29 }; 30 31 if (!visualViewport) { 32 window.addEventListener("resize", onResize); 33 } else { 34 visualViewport.addEventListener("resize", onResize); 35 } 36 37 return () => { 38 if (!visualViewport) { 39 window.removeEventListener("resize", onResize); 40 } else { 41 visualViewport.removeEventListener("resize", onResize); 42 } 43 }; 44 }, []); 45 46 return difference; 47} 48 49function getViewportSize() { 50 if (typeof window === "undefined") return { width: 0, height: 0 }; 51 return { 52 width: visualViewport?.width || window?.innerWidth, 53 height: visualViewport?.height || window?.innerHeight, 54 }; 55} 56 57export function useViewportSize(): { 58 width: number; 59 height: number; 60} { 61 let [size, setSize] = useState(() => getViewportSize()); 62 63 useEffect(() => { 64 // Use visualViewport api to track available height even on iOS virtual keyboard opening 65 let onResize = () => { 66 setSize((size) => { 67 let newSize = getViewportSize(); 68 if (newSize.width === size.width && newSize.height === size.height) { 69 return size; 70 } 71 return newSize; 72 }); 73 }; 74 75 if (!visualViewport) { 76 window.addEventListener("resize", onResize); 77 } else { 78 visualViewport.addEventListener("resize", onResize); 79 } 80 81 return () => { 82 if (!visualViewport) { 83 window.removeEventListener("resize", onResize); 84 } else { 85 visualViewport.removeEventListener("resize", onResize); 86 } 87 }; 88 }, []); 89 90 return size; 91}