diff --git a/resources/css/app.css b/resources/css/app.css index 6c48d4a9..93a68b8b 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -71,6 +71,8 @@ } :root { + --safe-area-top: env(safe-area-inset-top, 0px); + --safe-area-bottom: env(safe-area-inset-bottom, 0px); --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); diff --git a/resources/js/components/ui/popover.tsx b/resources/js/components/ui/popover.tsx index 6d51b6ce..80ce42b3 100644 --- a/resources/js/components/ui/popover.tsx +++ b/resources/js/components/ui/popover.tsx @@ -3,6 +3,32 @@ import * as PopoverPrimitive from "@radix-ui/react-popover" import { cn } from "@/lib/utils" +function useSafeAreaTopPadding(): number { + const [padding, setPadding] = React.useState(8) + + React.useEffect(() => { + const updatePadding = () => { + const value = Number.parseFloat( + getComputedStyle(document.documentElement).getPropertyValue("--safe-area-top") + ) + + setPadding(Number.isNaN(value) ? 8 : Math.max(8, value + 8)) + } + + updatePadding() + + window.addEventListener("resize", updatePadding) + window.visualViewport?.addEventListener("resize", updatePadding) + + return () => { + window.removeEventListener("resize", updatePadding) + window.visualViewport?.removeEventListener("resize", updatePadding) + } + }, []) + + return padding +} + function Popover({ ...props }: React.ComponentProps) { @@ -19,14 +45,18 @@ function PopoverContent({ className, align = "center", sideOffset = 4, + collisionPadding, ...props }: React.ComponentProps) { + const safeAreaTopPadding = useSafeAreaTopPadding() + return ( toContain('collisionPadding={collisionPadding ?? { top: safeAreaTopPadding, right: 8, bottom: 8, left: 8 }}') + ->and($css)->toContain('--safe-area-top: env(safe-area-inset-top, 0px);'); +});