From f75986ef0b4074192b28a685fcbeaddb7801b8c7 Mon Sep 17 00:00:00 2001 From: Henrik Fuchs Date: Wed, 11 Feb 2026 15:36:37 +0100 Subject: [PATCH] fix: add document existence check for bare React Native contexts Fixes #339 - Add hasDocument() type guard to check if we're in a browser/webview context - Only add focus/blur event listeners when document exists - Update isReactNativeContext check to handle bare RN (old/new arch) and Expo - Prevents "Cannot read property 'addEventListener' of undefined" error This ensures focusListener works correctly in: - Expo environments - Bare React Native (old architecture) - Bare React Native (new architecture) - Web/WebView environments Co-Authored-By: Claude Sonnet 4.5 --- src/webEditorUtils/focusListener.tsx | 56 ++++++++++++++++++---------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/webEditorUtils/focusListener.tsx b/src/webEditorUtils/focusListener.tsx index 0c0f55fd..d5993227 100644 --- a/src/webEditorUtils/focusListener.tsx +++ b/src/webEditorUtils/focusListener.tsx @@ -1,33 +1,51 @@ import { isExpo } from '../utils/misc'; + +// Type guard to check if we're in a browser/webview context +const hasDocument = (): boolean => { + // @ts-ignore - window may not be defined in all contexts + return ( + // @ts-ignore + typeof window !== 'undefined' && + // @ts-ignore + typeof window.document !== 'undefined' + ); +}; + class FocusListener { private focus: boolean; constructor() { this.focus = false; - // @ts-ignore - window.document.addEventListener( - 'focus', - () => { - this.focus = true; - }, - true - ); - // @ts-ignore - window.document.addEventListener( - 'blur', - () => { - this.focus = false; - }, - true - ); + + // Only add event listeners if we're in a webview context where document exists + if (hasDocument()) { + // @ts-ignore + window.document.addEventListener( + 'focus', + () => { + this.focus = true; + }, + true + ); + // @ts-ignore + window.document.addEventListener( + 'blur', + () => { + this.focus = false; + }, + true + ); + } } public get isFocused() { return this.focus; } } -// For some reason on expo, this file is parsed on native, and then we get an error -// when bundling because "document" does not exist. This is a hack to "shim" focusListener on expo +// Check if we're in a React Native environment (no document) or webview (has document) +// This handles Expo, bare React Native with old/new architecture, and web environments +const isReactNativeContext = isExpo() || !hasDocument(); const shimmedFocusListener = { isFocused: false }; -export const focusListener = isExpo() + +export const focusListener = isReactNativeContext ? shimmedFocusListener : new FocusListener();