microsoft / react-native-windows

A framework for building native Windows apps with React.
https://microsoft.github.io/react-native-windows/
Other
16.35k stars 1.14k forks source link

Breakup XamlUIService into separate APIs #10430

Open rozele opened 2 years ago

rozele commented 2 years ago

Summary

It feels like over time, XamlUIService has become a bit of a dumping ground for various APIs.

  1. It was originally created in https://github.com/microsoft/react-native-windows/commit/2809c9a14a68cdbaa4b735b189197b5692af0d53 to handle looking up tags from elements.
  2. Then we added an option to get a singleton XamlRoot in https://github.com/microsoft/react-native-windows/commit/f52d4942a42ed75d6fa92594897d2f3d7db1b7d7
  3. Then we added options to set the HWND in https://github.com/microsoft/react-native-windows/commit/bdd23dc452f4167769e3166513524f263fd3cda0
  4. The an accessibility workaround in https://github.com/microsoft/react-native-windows/commit/2dfb964e57020226828867f816bd31cff25814b8
  5. There is a proposed addition for getting the React tag and ReactRootView here: https://github.com/microsoft/react-native-windows/pull/10403
  6. And another proposal for adding a mechanism to invoke nested Yoga layout here: https://github.com/microsoft/react-native-windows/pull/10237

It feels like we should separate concerns a bit here and expose a few new APIs:

  1. XamlUIService can remain as a translation layer between XAML views and the React shadow tree to fill the gap of missing shadow nodes in the exposed ABI, e.g.:

    void XamlUIService::GetElementFromTag(int64_t tag)
    void XamlUIService::GetReactTag(xaml::DependencyObject view)
    ReactRootView XamlUIService::GetReactRootView(xaml::DependencyObject view)
  2. A per root view ReactWindowService could be added to ReactRootView to handle things like getting / setting the HWND, getting / setting the XamlRoot, getting / setting the accessibility root, etc.

    ReactWindowService ReactRootView::WindowService()
    void ReactWindowService::XamlRoot(XamlRoot root);
    XamlRoot ReactWindowService::XamlRoot();
    void ReactWindowService::HWND(int64_t);
    uint64_t ReactWindowService::HWND();
    // Do not exist yet, but would be needed to feed scale factors to Yoga
    double ReactWindowService::ScaleFactor();
    void ReactWindowService::ScaleFactor(double scaleFactor);
  3. A service for the AccessibilityInfoModule, AccessibilityInfoService:

    AccessibilityInfoService ReactContext::AccessibilityInfoService();
    void AccessibilityInfoService::AccessibleRoot(xaml::FrameworkElement root);
    xaml::FrameworkElement AccessibilityInfoService::AccessibleRoot();
  4. An API for event dispatching, EventDispatcher:

    EventDispatcher ReactContext::EventDispatcher()
    void EventDispatcher::DispatchEvent(...)
    // Does not exist yet, but would be useful
    void EventDispatcher::DispatchCoalescedEvent(...)
  5. An API for UIManager, UIManagerService:

    UIManagerService ReactContext::UIManagerService()
    void UIManagerService::UpdateYogaLayout(int64_t tag);
    // Does not exist yet, but would expose public surfaces for functionality in iOS/Android
    void UIManagerService::AddOnBatchCompleteListener(...);

Motivation

Separation of concerns for the collection of methods exposed in XamlUIService.

Basic Example

No response

Open Questions

No response

rozele commented 2 years ago

The thing I like most about attaching something like ReactWindowService to ReactRootView is that it would force us to think about multi-window scenarios any time we add functionality that involves HWND / window message loops / XamlRoot / etc.

rozele commented 2 years ago

We could potentially lump the AccessibilityInfoService and UIManagerService into a single "NativeModuleService" catch all for utilities needed for core native modules. Or put the AccessibilityInfoService APIs into the WindowService, since this is a catch all for issues related to creating win32 windows for WinUI 3 or XamlIslands, and the AccessibilityInfoModule workarounds are similar in theme.

acoates-ms commented 2 years ago

The original reason for XamlUIService was to try to get anything Xaml specific out of the primary interfaces, since Office is trying to get its platform onto the same APIs as the public RNW, but Office isn't using Xaml yet and couldn't have any Xaml interfaces in the main interfaces.

We were hoping to eventually get to a place where there is a UI agnostic core set of APIs / DLL. And then more specific DLLs for each UI technology. So we could have a MS.RN.Core.dll, and a MS.RN.Xaml.dll, so keeping the xaml APIs on separate interfaces was an explicit goal.