Add `packages/app/src/constants/platform.ts` with canonical gates (isWeb, isNative, getIsElectron) and refactor all ~100 ad-hoc Platform.OS checks across 69 files to use shared imports. Fix sidebar hover crash on native (onPointerEnter → onHoverIn), fix tooltip to use breakpoint instead of platform detection, make sidebar action buttons always visible on native where hover doesn't work, and document the platform gating decision matrix in CLAUDE.md.
50 lines
2.0 KiB
TypeScript
50 lines
2.0 KiB
TypeScript
import { Platform } from "react-native";
|
|
import { isElectronRuntime, isElectronRuntimeMac } from "@/desktop/host";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Runtime environment constants
|
|
//
|
|
// These are the ONLY platform gates in the app. See CLAUDE.md for the
|
|
// decision matrix on when to use each one.
|
|
//
|
|
// Default is cross-platform. Gate only when you must:
|
|
// isWeb → DOM APIs (document, window, <div>, addEventListener)
|
|
// isNative → Native-only APIs (Haptics, StatusBar, push tokens, camera)
|
|
// isElectron → Desktop wrapper features (file dialogs, titlebar, updates)
|
|
//
|
|
// For layout decisions, use useIsCompactFormFactor() from constants/layout.ts.
|
|
// For hover, use onHoverIn/onHoverOut on Pressable — no platform gate needed.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/** Browser or Electron — the JS runtime has access to the DOM. */
|
|
export const isWeb = Platform.OS === "web";
|
|
|
|
/** iOS or Android — the JS runtime is React Native. */
|
|
export const isNative = Platform.OS !== "web";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Electron detection (cached — only caches `true`, keeps checking if false
|
|
// because the desktop bridge may load after initial module evaluation)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
let _isElectronCached: boolean | null = null;
|
|
let _isElectronMacCached: boolean | null = null;
|
|
|
|
/** Running inside the Electron desktop wrapper (any OS). */
|
|
export function getIsElectron(): boolean {
|
|
if (_isElectronCached === true) return true;
|
|
if (!isWeb) return false;
|
|
const result = isElectronRuntime();
|
|
if (result) _isElectronCached = true;
|
|
return result;
|
|
}
|
|
|
|
/** Running inside the Electron desktop wrapper on macOS. */
|
|
export function getIsElectronMac(): boolean {
|
|
if (_isElectronMacCached === true) return true;
|
|
if (!isWeb) return false;
|
|
const result = isElectronRuntimeMac();
|
|
if (result) _isElectronMacCached = true;
|
|
return result;
|
|
}
|