forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 💫
1// measure safe area insets via getBoundingClientRect() on elements
2// with height: env(safe-area-inset-*). Safari WebKit returns 0 for env() via
3// getComputedStyle() in standalone PWA mode, but CSS rendering works — so we
4// create elements sized by env() and measure their rendered dimensions.
5//
6// Usage: wrap children of SafeAreaProvider with <SafeAreaOverride> to replace
7// the broken insets with our measured values.
8
9import {type PropsWithChildren, useEffect, useState} from 'react'
10import {type EdgeInsets} from 'react-native-safe-area-context'
11
12// Access the context — exported as SafeAreaContext (alias for SafeAreaInsetsContext)
13const {SafeAreaContext} = require('react-native-safe-area-context')
14
15function createMeasureEl(id: string, heightEnv: string): HTMLElement {
16 let el = document.getElementById(id)
17 if (!el) {
18 el = document.createElement('div')
19 el.id = id
20 el.style.cssText = [
21 'position:fixed',
22 'left:0',
23 'top:0',
24 'width:1px',
25 'visibility:hidden',
26 'pointer-events:none',
27 `height:${heightEnv}`,
28 ].join(';')
29 document.documentElement.appendChild(el)
30 }
31 return el
32}
33
34function measure(): EdgeInsets {
35 if (typeof document === 'undefined') {
36 return {top: 0, bottom: 0, left: 0, right: 0}
37 }
38
39 const topEl = createMeasureEl(
40 'safe-area-measure-top',
41 'env(safe-area-inset-top, 0px)',
42 )
43 const bottomEl = createMeasureEl(
44 'safe-area-measure-bottom',
45 'env(safe-area-inset-bottom, 0px)',
46 )
47
48 return {
49 top: topEl.getBoundingClientRect().height,
50 bottom: bottomEl.getBoundingClientRect().height,
51 left: 0,
52 right: 0,
53 }
54}
55
56export function SafeAreaOverride({children}: PropsWithChildren) {
57 const [insets, setInsets] = useState<EdgeInsets>({
58 top: 0,
59 bottom: 0,
60 left: 0,
61 right: 0,
62 })
63
64 useEffect(() => {
65 // Measure after mount + a frame to ensure CSS env() has been resolved
66 requestAnimationFrame(() => {
67 setInsets(measure())
68 })
69 }, [])
70
71 const Provider = SafeAreaContext.Provider
72 return <Provider value={insets}>{children}</Provider>
73}