microsoft / react-native-macos

A framework for building native macOS apps with React.
https://microsoft.github.io/react-native-windows/
MIT License
3.37k stars 129 forks source link

Dimensions.get('window') and useWindowDimensions() return 0 when the containing window is an NSPopover #2129

Open michelcrypt4d4mus opened 1 month ago

michelcrypt4d4mus commented 1 month ago

Environment

react-native -v: 12.3.6

npm ls react-native-macos: 
├── react-native-macos@0.73.27
└─┬ react-native-menubar-extra@0.3.1
  └── react-native-macos@0.73.27 deduped

node -v: v21.7.2
npm -v: 10.5.0
xcodebuild -version: Xcode 15.2 Build version 15C500b

Steps to reproduce the bug

I have my app embedded in an NSPopover instead of the usual NSWindow and I'm getting zeroes when I try to get the dimensions of the window the app appears in. I suspect that's because the main NSApplication still has a window property that was initialized in the scaffolding even though I'm not using it?

Expected Behavior

I should get the actual dimensions.

Actual Behavior

Here's what I get:

useWindowDimensions(): {"fontScale":1,"height":0,"width":0,"scale":1}
Dimensions.get('window'): {"fontScale":1,"height":0,"width":0,"scale":1}
Dimensions.get('screen'): {"fontScale":1,"height":900,"width":1440,"scale":1}

Reproducible Demo

Here's AppDelegate.swift (I converted the template for react-native-macos to Swift):

import Foundation
import Cocoa
import OSLog

@NSApplicationMain
class AppDelegate: RCTAppDelegate {
  let MENU_BAR_ICON = "X"
  var popover: NSPopover!
  var statusBarItem: NSStatusItem!

  override func applicationDidFinishLaunching(_ aNotification: Notification) {
    self.moduleName = "YXXY_XZZX"
    self.initialProps = [:]

    if self.bridge == nil {
      self.bridge = self.createBridge(with: self, launchOptions: aNotification.userInfo)
    }

    let rootView = self.createRootView(with: self.bridge, moduleName: self.moduleName, initProps: self.initialProps)
    let rootViewController = NSViewController()
    rootViewController.view = rootView!

    statusBarItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
    popover = NSPopover()
    popover.contentSize = NSSize(width: 700, height: 800)
    popover.contentViewController = rootViewController
    popover.animates = true
    popover.behavior = .transient

    if #available(macOS 14, *) {
      popover.hasFullSizeContent = true
    }

    if let button = self.statusBarItem.button {
      button.action = #selector(togglePopover(_:))
      button.title = MENU_BAR_ICON
    }
  }

  @objc func togglePopover(_ sender: NSMenuItem?) {
    if let button = self.statusBarItem.button {
      if self.popover.isShown {
        self.popover.performClose(sender)
      } else {
        self.popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
        NSApp.activate(ignoringOtherApps: true)  // https://stackoverflow.com/questions/29612628/nspopover-not-closing
        self.popover.contentViewController?.view.window?.becomeKey()
      }
    }
  }

  @objc override func sourceURL(for bridge: RCTBridge!) -> URL! {
#if DEBUG
    return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
#else
    return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
#endif
  }

  @objc func concurrentRootEnabled() -> Bool {
#if RN_FABRIC_ENABLED
        return true;
#else
        return false;
#endif
  }
}

And here's the macos-bridging-header.h:

#if __has_include(<React/RCTAppDelegate.h>)
#import <React/RCTAppDelegate.h>
#elif __has_include("RCTAppDelegate.h")
#import "RCTAppDelegate.h"
#else
#import "React/RCTAppDelegate.h"
#endif

#import <React/RCTBridgeModule.h>
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>
#import <React/RCTBundleURLProvider.h>

Additional context

No response

Saadnajmi commented 1 month ago

It might be helpful to compare you app to Expo's Orbit app (i.E: https://github.com/expo/orbit/blob/main/apps/menu-bar/macos/ExpoMenuBar-macOS/AppDelegate.m) to see what the differences may be. Like, if there's a phantom window it's reading as you theorized