| 1 | import { requireOptionalNativeModule } from "expo"; |
| 2 | import { useEffect, useState } from "react"; |
| 3 | import { Platform } from "react-native"; |
| 4 | import { useNativeLayoutMetrics } from "./native-layout-metrics"; |
| 5 | |
| 6 | const nativeControls = requireOptionalNativeModule<{ |
| 7 | readonly supportsWorkspaceColumns?: boolean; |
| 8 | readonly ViewPrototypes?: { readonly T3NativeControls_LayoutMetrics?: unknown }; |
| 9 | }>("T3NativeControls"); |
| 10 | export const NATIVE_WORKSPACE_COLUMNS_SUPPORTED = |
| 11 | Platform.OS === "ios" && Platform.isPad && nativeControls?.supportsWorkspaceColumns === true; |
| 12 | |
| 13 | // Binaries without the native no-hinge fallback never report metrics on ordinary |
| 14 | // iPhones running iOS 27.1 or later. Use the compact navigator rather than staying blank. |
| 15 | const NATIVE_METRICS_TIMEOUT_MS = 1000; |
| 16 | |
| 17 | export function useNativeWorkspaceColumnsReady() { |
| 18 | const metrics = useNativeLayoutMetrics(); |
| 19 | const [timedOut, setTimedOut] = useState(false); |
| 20 | // Choose the phone's native host before attaching any screens. Older clients |
| 21 | // without the observer can immediately use the compact navigator. |
| 22 | const waiting = |
| 23 | !(Platform.OS === "ios" && Platform.isPad) && |
| 24 | !!nativeControls?.ViewPrototypes?.T3NativeControls_LayoutMetrics && |
| 25 | metrics === null; |
| 26 | |
| 27 | useEffect(() => { |
| 28 | if (!waiting) return; |
| 29 | const timeout = setTimeout(() => setTimedOut(true), NATIVE_METRICS_TIMEOUT_MS); |
| 30 | return () => clearTimeout(timeout); |
| 31 | }, [waiting]); |
| 32 | |
| 33 | return !waiting || timedOut; |
| 34 | } |
| 35 | |
| 36 | export function useNativeWorkspaceColumnsSupported() { |
| 37 | const metrics = useNativeLayoutMetrics(); |
| 38 | return ( |
| 39 | NATIVE_WORKSPACE_COLUMNS_SUPPORTED || |
| 40 | (nativeControls?.supportsWorkspaceColumns === true && metrics?.hasHinge === true) |
| 41 | ); |
| 42 | } |