react-native-windows 0.74.21 → 0.74.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/Microsoft.ReactNative/ComponentView.idl +11 -0
  2. package/Microsoft.ReactNative/Composition.Input.idl +1 -0
  3. package/Microsoft.ReactNative/CompositionSwitcher.idl +3 -0
  4. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +18 -8
  5. package/Microsoft.ReactNative/Fabric/ComponentView.h +7 -5
  6. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.cpp +4 -0
  7. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.h +1 -0
  8. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +44 -13
  9. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +75 -0
  10. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +8 -2
  11. package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.cpp +1 -0
  12. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +34 -7
  13. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +3 -2
  14. package/Microsoft.ReactNative/Fabric/Composition/DebuggingOverlayComponentView.cpp +8 -6
  15. package/Microsoft.ReactNative/Fabric/Composition/DebuggingOverlayComponentView.h +1 -2
  16. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +20 -6
  17. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +13 -6
  18. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +2 -3
  19. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.h +1 -2
  20. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +80 -55
  21. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +15 -4
  22. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +37 -8
  23. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +7 -2
  24. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +14 -7
  25. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +1 -2
  26. package/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp +6 -6
  27. package/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h +1 -2
  28. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.cpp +1 -2
  29. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.h +1 -1
  30. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +104 -152
  31. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +7 -3
  32. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +14 -11
  33. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +4 -4
  34. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.cpp +0 -13
  35. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.h +0 -3
  36. package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +12 -4
  37. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +338 -0
  38. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.h +66 -0
  39. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +37 -4
  40. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +3 -0
  41. package/Microsoft.ReactNative/Fabric/Composition/UnimplementedNativeViewComponentView.cpp +1 -2
  42. package/Microsoft.ReactNative/Fabric/Composition/UnimplementedNativeViewComponentView.h +1 -2
  43. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +31 -3
  44. package/Microsoft.ReactNative/Fabric/ReactTaggedView.h +4 -0
  45. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +5 -0
  46. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +1 -1
  47. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +1 -1
  48. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +9 -2
  49. package/Microsoft.ReactNative/IReactViewComponentBuilder.idl +8 -1
  50. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -1
  51. package/Microsoft.ReactNative/Modules/LogBoxModule.cpp +9 -0
  52. package/Microsoft.ReactNative/Modules/LogBoxModule.h +2 -0
  53. package/Microsoft.ReactNative/Modules/SampleTurboModule.cpp +104 -0
  54. package/Microsoft.ReactNative/Modules/SampleTurboModule.h +78 -0
  55. package/Microsoft.ReactNative/ReactCoreInjection.h +0 -1
  56. package/Microsoft.ReactNative/ReactHost/MsoReactContext.cpp +0 -7
  57. package/Microsoft.ReactNative/ReactHost/MsoReactContext.h +0 -5
  58. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +17 -1
  59. package/Microsoft.ReactNative/ReactInstanceSettingsBuilder.cpp +59 -0
  60. package/Microsoft.ReactNative/ReactInstanceSettingsBuilder.h +23 -0
  61. package/Microsoft.ReactNative/ReactNativeAppBuilder.cpp +179 -0
  62. package/Microsoft.ReactNative/ReactNativeAppBuilder.h +35 -0
  63. package/Microsoft.ReactNative/ReactNativeAppBuilder.idl +69 -0
  64. package/Microsoft.ReactNative/ReactNativeIsland.idl +2 -0
  65. package/Microsoft.ReactNative/ReactNativeWin32App.cpp +82 -0
  66. package/Microsoft.ReactNative/ReactNativeWin32App.h +38 -0
  67. package/Microsoft.ReactNative/Timer.idl +1 -1
  68. package/Microsoft.ReactNative/packages.lock.json +0 -10
  69. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  70. package/Shared/Shared.vcxitems +36 -0
  71. package/Shared/Shared.vcxitems.filters +2 -0
  72. package/Shared/TurboModuleManager.cpp +0 -3
  73. package/package.json +3 -3
  74. package/templates/cpp-app/windows/MyApp/MyApp.cpp +1 -0
@@ -32,17 +32,21 @@ struct LosingFocusEventArgs
32
32
  : winrt::Microsoft::ReactNative::implementation::LosingFocusEventArgsT<LosingFocusEventArgs> {
33
33
  LosingFocusEventArgs(
34
34
  const winrt::Microsoft::ReactNative::ComponentView &originalSource,
35
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction,
35
36
  const winrt::Microsoft::ReactNative::ComponentView &oldFocusedComponent,
36
37
  const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent);
37
- int32_t OriginalSource() noexcept;
38
- winrt::Microsoft::ReactNative::ComponentView NewFocusedComponent() noexcept;
39
- winrt::Microsoft::ReactNative::ComponentView OldFocusedComponent() noexcept;
38
+ int32_t OriginalSource() const noexcept;
39
+ winrt::Microsoft::ReactNative::FocusNavigationDirection Direction() const noexcept;
40
+
41
+ winrt::Microsoft::ReactNative::ComponentView NewFocusedComponent() const noexcept;
42
+ winrt::Microsoft::ReactNative::ComponentView OldFocusedComponent() const noexcept;
40
43
 
41
44
  void TryCancel() noexcept;
42
45
  void TrySetNewFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent) noexcept;
43
46
 
44
47
  private:
45
48
  const int32_t m_originalSource;
49
+ const winrt::Microsoft::ReactNative::FocusNavigationDirection m_direction;
46
50
  winrt::Microsoft::ReactNative::ComponentView m_old{nullptr};
47
51
  winrt::Microsoft::ReactNative::ComponentView m_new{nullptr};
48
52
  };
@@ -51,17 +55,20 @@ struct GettingFocusEventArgs
51
55
  : winrt::Microsoft::ReactNative::implementation::GettingFocusEventArgsT<GettingFocusEventArgs> {
52
56
  GettingFocusEventArgs(
53
57
  const winrt::Microsoft::ReactNative::ComponentView &originalSource,
58
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction,
54
59
  const winrt::Microsoft::ReactNative::ComponentView &oldFocusedComponent,
55
60
  const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent);
56
- int32_t OriginalSource() noexcept;
57
- winrt::Microsoft::ReactNative::ComponentView NewFocusedComponent() noexcept;
58
- winrt::Microsoft::ReactNative::ComponentView OldFocusedComponent() noexcept;
61
+ int32_t OriginalSource() const noexcept;
62
+ winrt::Microsoft::ReactNative::FocusNavigationDirection Direction() const noexcept;
63
+ winrt::Microsoft::ReactNative::ComponentView NewFocusedComponent() const noexcept;
64
+ winrt::Microsoft::ReactNative::ComponentView OldFocusedComponent() const noexcept;
59
65
 
60
66
  void TryCancel() noexcept;
61
67
  void TrySetNewFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent) noexcept;
62
68
 
63
69
  private:
64
70
  const int32_t m_originalSource;
71
+ const winrt::Microsoft::ReactNative::FocusNavigationDirection m_direction;
65
72
  winrt::Microsoft::ReactNative::ComponentView m_old{nullptr};
66
73
  winrt::Microsoft::ReactNative::ComponentView m_new{nullptr};
67
74
  };
@@ -191,9 +191,8 @@ void WindowsModalHostComponentView::UnmountChildComponentView(
191
191
  }
192
192
 
193
193
  void WindowsModalHostComponentView::HandleCommand(
194
- winrt::hstring commandName,
195
- const winrt::Microsoft::ReactNative::IJSValueReader &args) noexcept {
196
- Super::HandleCommand(commandName, args);
194
+ const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept {
195
+ Super::HandleCommand(args);
197
196
  }
198
197
 
199
198
  void WindowsModalHostComponentView::updateProps(
@@ -28,8 +28,7 @@ struct WindowsModalHostComponentView
28
28
  void UnmountChildComponentView(
29
29
  const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
30
30
  uint32_t index) noexcept override;
31
- void HandleCommand(winrt::hstring commandName, const winrt::Microsoft::ReactNative::IJSValueReader &args) noexcept
32
- override;
31
+ void HandleCommand(const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept override;
33
32
  void updateState(facebook::react::State::Shared const &state, facebook::react::State::Shared const &oldState) noexcept
34
33
  override;
35
34
 
@@ -58,10 +58,6 @@ struct CompositionReactViewInstance
58
58
  void UpdateRootView() noexcept;
59
59
  void UninitRootView() noexcept;
60
60
 
61
- private:
62
- template <class TAction>
63
- Mso::Future<void> PostInUIQueue(TAction &&action) noexcept;
64
-
65
61
  private:
66
62
  winrt::weak_ref<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland> m_weakRootControl;
67
63
  IReactDispatcher m_uiDispatcher{nullptr};
@@ -102,44 +98,36 @@ void CompositionReactViewInstance::UninitRootView() noexcept {
102
98
  }
103
99
  }
104
100
 
105
- //===========================================================================
106
- // ReactViewInstance inline implementation
107
- //===========================================================================
108
-
109
- template <class TAction>
110
- inline Mso::Future<void> CompositionReactViewInstance::PostInUIQueue(TAction &&action) noexcept {
111
- // ReactViewInstance has shorter lifetime than ReactRootControl. Thus, we capture this WeakPtr.
112
- auto promise = Mso::Promise<void>();
113
-
114
- m_uiDispatcher.Post([promise, weakThis{get_weak()}, action{std::forward<TAction>(action)}]() mutable {
115
- if (auto strongThis = weakThis.get()) {
116
- if (auto rootControl = strongThis->m_weakRootControl.get()) {
117
- action(rootControl);
118
- promise.SetValue();
119
- return;
120
- }
121
- }
122
- promise.TryCancel();
123
- });
124
-
125
- return promise.AsFuture();
126
- }
127
-
128
- void ApplyConstraints(
101
+ void ReactNativeIsland::ApplyConstraints(
129
102
  const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn,
130
- facebook::react::LayoutConstraints &layoutConstraintsOut) noexcept {
103
+ facebook::react::LayoutConstraints &layoutConstraintsOut) const noexcept {
131
104
  layoutConstraintsOut.minimumSize = {layoutConstraintsIn.MinimumSize.Width, layoutConstraintsIn.MinimumSize.Height};
132
105
  layoutConstraintsOut.maximumSize = {layoutConstraintsIn.MaximumSize.Width, layoutConstraintsIn.MaximumSize.Height};
133
- layoutConstraintsOut.layoutDirection =
134
- static_cast<facebook::react::LayoutDirection>(layoutConstraintsIn.LayoutDirection);
106
+ if (layoutConstraintsIn.LayoutDirection == winrt::Microsoft::ReactNative::LayoutDirection::Undefined) {
107
+ if (m_island) {
108
+ layoutConstraintsOut.layoutDirection =
109
+ (m_island.LayoutDirection() == winrt::Microsoft::UI::Content::ContentLayoutDirection::LeftToRight)
110
+ ? facebook::react::LayoutDirection::LeftToRight
111
+ : facebook::react::LayoutDirection::RightToLeft;
112
+ } else if (m_hwnd) {
113
+ auto styles = GetWindowLongPtrW(m_hwnd, GWL_EXSTYLE);
114
+ layoutConstraintsOut.layoutDirection = ((styles & WS_EX_LAYOUTRTL) == WS_EX_LAYOUTRTL)
115
+ ? facebook::react::LayoutDirection::RightToLeft
116
+ : facebook::react::LayoutDirection::LeftToRight;
117
+ }
118
+ } else {
119
+ layoutConstraintsOut.layoutDirection =
120
+ static_cast<facebook::react::LayoutDirection>(layoutConstraintsIn.LayoutDirection);
121
+ }
135
122
  }
136
123
 
137
- ReactNativeIsland::ReactNativeIsland() noexcept {}
138
-
139
- #ifdef USE_WINUI3
140
124
  ReactNativeIsland::ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept
141
- : m_compositor(compositor) {}
142
- #endif
125
+ : m_compositor(compositor),
126
+ m_layoutConstraints({{0, 0}, {0, 0}, winrt::Microsoft::ReactNative::LayoutDirection::Undefined}) {
127
+ InitTextScaleMultiplier();
128
+ }
129
+
130
+ ReactNativeIsland::ReactNativeIsland() noexcept : ReactNativeIsland(nullptr) {}
143
131
 
144
132
  ReactNativeIsland::~ReactNativeIsland() noexcept {
145
133
  #ifdef USE_WINUI3
@@ -169,6 +157,7 @@ void ReactNativeIsland::ReactViewHost(winrt::Microsoft::ReactNative::IReactViewH
169
157
  }
170
158
 
171
159
  if (m_reactViewHost) {
160
+ UninitRootView();
172
161
  m_reactViewHost.DetachViewInstance();
173
162
  }
174
163
 
@@ -275,6 +264,10 @@ void ReactNativeIsland::ScaleFactor(float value) noexcept {
275
264
  }
276
265
  }
277
266
 
267
+ float ReactNativeIsland::FontSizeMultiplier() const noexcept {
268
+ return m_textScaleMultiplier;
269
+ }
270
+
278
271
  int64_t ReactNativeIsland::RootTag() const noexcept {
279
272
  return m_rootTag;
280
273
  }
@@ -340,7 +333,7 @@ winrt::IInspectable ReactNativeIsland::GetUiaProvider() noexcept {
340
333
  if (m_uiaProvider == nullptr) {
341
334
  m_uiaProvider =
342
335
  winrt::make<winrt::Microsoft::ReactNative::implementation::CompositionRootAutomationProvider>(*this);
343
- if (m_hwnd) {
336
+ if (m_hwnd && !m_island) {
344
337
  auto pRootProvider =
345
338
  static_cast<winrt::Microsoft::ReactNative::implementation::CompositionRootAutomationProvider *>(
346
339
  m_uiaProvider.as<IRawElementProviderSimple>().get());
@@ -356,6 +349,10 @@ void ReactNativeIsland::SetWindow(uint64_t hwnd) noexcept {
356
349
  m_hwnd = reinterpret_cast<HWND>(hwnd);
357
350
  }
358
351
 
352
+ HWND ReactNativeIsland::GetHwndForParenting() noexcept {
353
+ return m_hwnd;
354
+ }
355
+
359
356
  int64_t ReactNativeIsland::SendMessage(uint32_t msg, uint64_t wParam, int64_t lParam) noexcept {
360
357
  if (m_rootTag == -1)
361
358
  return 0;
@@ -375,7 +372,7 @@ int64_t ReactNativeIsland::SendMessage(uint32_t msg, uint64_t wParam, int64_t lP
375
372
  bool ReactNativeIsland::CapturePointer(
376
373
  const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
377
374
  facebook::react::Tag tag) noexcept {
378
- if (m_hwnd) {
375
+ if (m_hwnd && !m_island) {
379
376
  SetCapture(m_hwnd);
380
377
  }
381
378
  return m_CompositionEventHandler->CapturePointer(pointer, tag);
@@ -385,7 +382,7 @@ void ReactNativeIsland::ReleasePointerCapture(
385
382
  const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
386
383
  facebook::react::Tag tag) noexcept {
387
384
  if (m_CompositionEventHandler->ReleasePointerCapture(pointer, tag)) {
388
- if (m_hwnd) {
385
+ if (m_hwnd && !m_island) {
389
386
  if (m_hwnd == GetCapture()) {
390
387
  ReleaseCapture();
391
388
  }
@@ -451,8 +448,9 @@ void ReactNativeIsland::UninitRootView() noexcept {
451
448
  uiManager->stopSurface(static_cast<facebook::react::SurfaceId>(RootTag()));
452
449
 
453
450
  // This is needed to ensure that the unmount JS logic is completed before the the instance is shutdown during
454
- // instance destruction. Aligns with similar code in ReactInstanceWin::DetachRootView for paper Future: Instead this
455
- // method should return a Promise, which should be resolved when the JS logic is complete.
451
+ // instance destruction. Aligns with similar code in ReactInstanceWin::DetachRootView for paper Future: Instead
452
+ // this method should return a Promise, which should be resolved when the JS logic is complete. The task will auto
453
+ // set the event on destruction to ensure that the event is set if the JS Queue has already been shutdown
456
454
  Mso::ManualResetEvent mre;
457
455
  m_context.JSDispatcher().Post([&]() { mre.Set(); });
458
456
  mre.Wait();
@@ -517,9 +515,8 @@ facebook::react::AttributedStringBox CreateLoadingAttributedString() noexcept {
517
515
  return facebook::react::AttributedStringBox{attributedString};
518
516
  }
519
517
 
520
- facebook::react::Size MeasureLoading(
521
- const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
522
- float scaleFactor) {
518
+ facebook::react::Size ReactNativeIsland::MeasureLoading(
519
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints) const noexcept {
523
520
  facebook::react::LayoutConstraints fbLayoutConstraints;
524
521
  ApplyConstraints(layoutConstraints, fbLayoutConstraints);
525
522
 
@@ -532,7 +529,7 @@ facebook::react::Size MeasureLoading(
532
529
  textLayout->GetMetrics(&tm);
533
530
 
534
531
  return fbLayoutConstraints.clamp(
535
- {loadingActivityHorizontalOffset * scaleFactor + tm.width, loadingBarHeight * scaleFactor});
532
+ {loadingActivityHorizontalOffset * m_scaleFactor + tm.width, loadingBarHeight * m_scaleFactor});
536
533
  }
537
534
 
538
535
  winrt::event_token ReactNativeIsland::SizeChanged(
@@ -562,7 +559,7 @@ void ReactNativeIsland::NotifySizeChanged() noexcept {
562
559
  if (rootComponentView) {
563
560
  size = rootComponentView->layoutMetrics().frame.size;
564
561
  } else if (m_loadingVisual) {
565
- size = MeasureLoading(m_layoutConstraints, m_scaleFactor);
562
+ size = MeasureLoading(m_layoutConstraints);
566
563
  }
567
564
 
568
565
  m_size = {size.width, size.height};
@@ -656,11 +653,34 @@ void ReactNativeIsland::ShowInstanceLoading() noexcept {
656
653
  InternalRootVisual().InsertAt(m_loadingVisual, m_hasRenderedVisual ? 1 : 0);
657
654
  }
658
655
 
656
+ void ReactNativeIsland::InitTextScaleMultiplier() noexcept {
657
+ m_uiSettings = winrt::Windows::UI::ViewManagement::UISettings();
658
+ m_textScaleMultiplier = static_cast<float>(m_uiSettings.TextScaleFactor());
659
+ m_textScaleChangedRevoker = m_uiSettings.TextScaleFactorChanged(
660
+ winrt::auto_revoke,
661
+ [this](const winrt::Windows::UI::ViewManagement::UISettings &uiSettings, const winrt::IInspectable &) {
662
+ if (m_context) {
663
+ m_context.UIDispatcher().Post(
664
+ [wkThis = get_weak(), textScaleMultiplier = static_cast<float>(uiSettings.TextScaleFactor())]() {
665
+ if (auto strongThis = wkThis.get()) {
666
+ strongThis->m_textScaleMultiplier = textScaleMultiplier;
667
+ strongThis->Arrange(strongThis->m_layoutConstraints, strongThis->m_viewportOffset);
668
+ }
669
+ });
670
+ }
671
+ });
672
+ }
673
+
659
674
  winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
660
675
  const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
661
- const winrt::Windows::Foundation::Point &viewportOffset) const noexcept {
676
+ const winrt::Windows::Foundation::Point &viewportOffset) const {
662
677
  facebook::react::Size size{0, 0};
663
678
 
679
+ if (layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight &&
680
+ layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::RightToLeft &&
681
+ layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::Undefined)
682
+ winrt::throw_hresult(E_INVALIDARG);
683
+
664
684
  facebook::react::LayoutConstraints constraints;
665
685
  ApplyConstraints(layoutConstraints, constraints);
666
686
 
@@ -668,15 +688,14 @@ winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
668
688
  if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
669
689
  winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()))) {
670
690
  facebook::react::LayoutContext context;
671
- // TODO scaling factor
691
+ context.fontSizeMultiplier = m_textScaleMultiplier;
672
692
  context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
673
- context.fontSizeMultiplier = static_cast<facebook::react::Float>(m_scaleFactor);
674
693
  context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
675
694
 
676
695
  size = fabricuiManager->measureSurface(static_cast<facebook::react::SurfaceId>(m_rootTag), constraints, context);
677
696
  }
678
697
  } else if (m_loadingVisual) {
679
- size = MeasureLoading(layoutConstraints, m_scaleFactor);
698
+ size = MeasureLoading(layoutConstraints);
680
699
  }
681
700
 
682
701
  auto clampedSize = constraints.clamp(size);
@@ -685,7 +704,12 @@ winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
685
704
 
686
705
  void ReactNativeIsland::Arrange(
687
706
  const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
688
- const winrt::Windows::Foundation::Point &viewportOffset) noexcept {
707
+ const winrt::Windows::Foundation::Point &viewportOffset) {
708
+ if (layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::LeftToRight &&
709
+ layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::RightToLeft &&
710
+ layoutConstraints.LayoutDirection != winrt::Microsoft::ReactNative::LayoutDirection::Undefined)
711
+ winrt::throw_hresult(E_INVALIDARG);
712
+
689
713
  m_layoutConstraints = layoutConstraints;
690
714
  m_viewportOffset = viewportOffset;
691
715
  facebook::react::LayoutConstraints fbLayoutConstraints;
@@ -695,8 +719,8 @@ void ReactNativeIsland::Arrange(
695
719
  if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
696
720
  winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()))) {
697
721
  facebook::react::LayoutContext context;
722
+ context.fontSizeMultiplier = m_textScaleMultiplier;
698
723
  context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
699
- context.fontSizeMultiplier = static_cast<facebook::react::Float>(m_scaleFactor);
700
724
  context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
701
725
 
702
726
  fabricuiManager->constraintSurfaceLayout(
@@ -704,12 +728,11 @@ void ReactNativeIsland::Arrange(
704
728
  }
705
729
  } else if (m_loadingVisual) {
706
730
  // TODO: Resize to align loading
707
- auto s = fbLayoutConstraints.clamp(MeasureLoading(layoutConstraints, m_scaleFactor));
731
+ auto s = fbLayoutConstraints.clamp(MeasureLoading(layoutConstraints));
708
732
  NotifySizeChanged();
709
733
  }
710
734
  }
711
735
 
712
- #ifdef USE_WINUI3
713
736
  winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
714
737
  if (!m_compositor) {
715
738
  return nullptr;
@@ -763,6 +786,9 @@ winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
763
786
  if (args.DidRasterizationScaleChange()) {
764
787
  pThis->ScaleFactor(island.RasterizationScale());
765
788
  }
789
+ if (args.DidLayoutDirectionChange()) {
790
+ pThis->Arrange(pThis->m_layoutConstraints, pThis->m_viewportOffset);
791
+ }
766
792
  #ifndef USE_EXPERIMENTAL_WINUI3 // Use this in place of Connected/Disconnected events for now. -- Its not quite what we
767
793
  // want, but it will do for now.
768
794
  if (args.DidSiteVisibleChange()) {
@@ -795,7 +821,6 @@ winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
795
821
  }
796
822
  return m_island;
797
823
  }
798
- #endif
799
824
 
800
825
  void ReactNativeIsland::OnMounted() noexcept {
801
826
  if (m_mounted)
@@ -10,6 +10,7 @@
10
10
  #include <react/renderer/core/LayoutConstraints.h>
11
11
  #include <winrt/Microsoft.ReactNative.Composition.Experimental.h>
12
12
  #include <winrt/Microsoft.ReactNative.h>
13
+ #include <winrt/Windows.UI.ViewManagement.h>
13
14
  #include "CompositionEventHandler.h"
14
15
  #include "ReactHost/React.h"
15
16
 
@@ -46,10 +47,8 @@ struct ReactNativeIsland
46
47
  ReactNativeIsland() noexcept;
47
48
  ~ReactNativeIsland() noexcept;
48
49
 
49
- #ifdef USE_WINUI3
50
50
  ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept;
51
51
  winrt::Microsoft::UI::Content::ContentIsland Island();
52
- #endif
53
52
 
54
53
  // property ReactViewHost
55
54
  ReactNative::IReactViewHost ReactViewHost() noexcept;
@@ -72,6 +71,8 @@ struct ReactNativeIsland
72
71
  float ScaleFactor() noexcept;
73
72
  void ScaleFactor(float value) noexcept;
74
73
 
74
+ float FontSizeMultiplier() const noexcept;
75
+
75
76
  winrt::event_token SizeChanged(
76
77
  winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::RootViewSizeChangedEventArgs> const
77
78
  &handler) noexcept;
@@ -81,6 +82,7 @@ struct ReactNativeIsland
81
82
  void AddRenderedVisual(const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept;
82
83
  void RemoveRenderedVisual(const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept;
83
84
  bool TrySetFocus() noexcept;
85
+ HWND GetHwndForParenting() noexcept;
84
86
 
85
87
  winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader Resources() noexcept;
86
88
  void Resources(const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept;
@@ -90,10 +92,10 @@ struct ReactNativeIsland
90
92
 
91
93
  winrt::Windows::Foundation::Size Measure(
92
94
  const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
93
- const winrt::Windows::Foundation::Point &viewportOffset) const noexcept;
95
+ const winrt::Windows::Foundation::Point &viewportOffset) const;
94
96
  void Arrange(
95
97
  const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
96
- const winrt::Windows::Foundation::Point &viewportOffset) noexcept;
98
+ const winrt::Windows::Foundation::Point &viewportOffset);
97
99
 
98
100
  winrt::Microsoft::ReactNative::FocusNavigationResult NavigateFocus(
99
101
  const winrt::Microsoft::ReactNative::FocusNavigationRequest &request) noexcept;
@@ -143,6 +145,9 @@ struct ReactNativeIsland
143
145
  winrt::IInspectable m_uiaProvider{nullptr};
144
146
  int64_t m_rootTag{-1};
145
147
  float m_scaleFactor{1.0};
148
+ float m_textScaleMultiplier{1.0};
149
+ winrt::Windows::UI::ViewManagement::UISettings::TextScaleFactorChanged_revoker m_textScaleChangedRevoker;
150
+ winrt::Windows::UI::ViewManagement::UISettings m_uiSettings{nullptr};
146
151
  winrt::Windows::Foundation::Size m_size{0, 0};
147
152
  winrt::Microsoft::ReactNative::ReactContext m_context;
148
153
  winrt::Microsoft::ReactNative::IReactViewHost m_reactViewHost;
@@ -168,6 +173,12 @@ struct ReactNativeIsland
168
173
  void UpdateRootVisualSize() noexcept;
169
174
  void UpdateLoadingVisualSize() noexcept;
170
175
  Composition::Experimental::IDrawingSurfaceBrush CreateLoadingVisualBrush() noexcept;
176
+ void ApplyConstraints(
177
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn,
178
+ facebook::react::LayoutConstraints &layoutConstraintsOut) const noexcept;
179
+ facebook::react::Size MeasureLoading(
180
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints) const noexcept;
181
+ void InitTextScaleMultiplier() noexcept;
171
182
  };
172
183
 
173
184
  } // namespace winrt::Microsoft::ReactNative::implementation
@@ -40,8 +40,8 @@ winrt::Microsoft::ReactNative::ComponentView RootComponentView::Create(
40
40
  return winrt::make<RootComponentView>(compContext, tag, reactContext);
41
41
  }
42
42
 
43
- RootComponentView *RootComponentView::rootComponentView() noexcept {
44
- return this;
43
+ RootComponentView *RootComponentView::rootComponentView() const noexcept {
44
+ return const_cast<RootComponentView *>(this);
45
45
  }
46
46
 
47
47
  void RootComponentView::updateLayoutMetrics(
@@ -91,12 +91,18 @@ bool RootComponentView::NavigateFocus(const winrt::Microsoft::ReactNative::Focus
91
91
  ? FocusManager::FindFirstFocusableElement(*this)
92
92
  : FocusManager::FindLastFocusableElement(*this);
93
93
  if (view) {
94
- TrySetFocusedComponent(view);
94
+ TrySetFocusedComponent(
95
+ view,
96
+ request.Reason() == winrt::Microsoft::ReactNative::FocusNavigationReason::First
97
+ ? winrt::Microsoft::ReactNative::FocusNavigationDirection::First
98
+ : winrt::Microsoft::ReactNative::FocusNavigationDirection::Last);
95
99
  }
96
100
  return view != nullptr;
97
101
  }
98
102
 
99
- bool RootComponentView::TrySetFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
103
+ bool RootComponentView::TrySetFocusedComponent(
104
+ const winrt::Microsoft::ReactNative::ComponentView &view,
105
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction) noexcept {
100
106
  auto target = view;
101
107
  auto selfView = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(target);
102
108
  if (selfView && !selfView->focusable()) {
@@ -110,7 +116,7 @@ bool RootComponentView::TrySetFocusedComponent(const winrt::Microsoft::ReactNati
110
116
  return false;
111
117
 
112
118
  auto losingFocusArgs = winrt::make<winrt::Microsoft::ReactNative::implementation::LosingFocusEventArgs>(
113
- target, m_focusedComponent, target);
119
+ target, direction, m_focusedComponent, target);
114
120
  if (m_focusedComponent) {
115
121
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(m_focusedComponent)
116
122
  ->onLosingFocus(losingFocusArgs);
@@ -118,7 +124,7 @@ bool RootComponentView::TrySetFocusedComponent(const winrt::Microsoft::ReactNati
118
124
 
119
125
  if (losingFocusArgs.NewFocusedComponent()) {
120
126
  auto gettingFocusArgs = winrt::make<winrt::Microsoft::ReactNative::implementation::GettingFocusEventArgs>(
121
- target, m_focusedComponent, losingFocusArgs.NewFocusedComponent());
127
+ target, direction, m_focusedComponent, losingFocusArgs.NewFocusedComponent());
122
128
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(losingFocusArgs.NewFocusedComponent())
123
129
  ->onGettingFocus(gettingFocusArgs);
124
130
 
@@ -138,13 +144,16 @@ bool RootComponentView::TryMoveFocus(bool next) noexcept {
138
144
  }
139
145
 
140
146
  Mso::Functor<bool(const winrt::Microsoft::ReactNative::ComponentView &)> fn =
141
- [currentlyFocused = m_focusedComponent](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
147
+ [currentlyFocused = m_focusedComponent, next](const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
142
148
  if (view == currentlyFocused)
143
149
  return false;
144
150
 
145
151
  return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(view)
146
152
  ->rootComponentView()
147
- ->TrySetFocusedComponent(view);
153
+ ->TrySetFocusedComponent(
154
+ view,
155
+ next ? winrt::Microsoft::ReactNative::FocusNavigationDirection::Next
156
+ : winrt::Microsoft::ReactNative::FocusNavigationDirection::Previous);
148
157
  };
149
158
 
150
159
  return winrt::Microsoft::ReactNative::implementation::walkTree(m_focusedComponent, next, fn);
@@ -202,6 +211,15 @@ winrt::IInspectable RootComponentView::UiaProviderFromPoint(const POINT &ptPixel
202
211
  return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(view)->EnsureUiaProvider();
203
212
  }
204
213
 
214
+ float RootComponentView::FontSizeMultiplier() const noexcept {
215
+ if (auto rootView = m_wkRootView.get()) {
216
+ return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)
217
+ ->FontSizeMultiplier();
218
+ }
219
+ assert(false);
220
+ return 1.0f;
221
+ }
222
+
205
223
  winrt::Microsoft::UI::Content::ContentIsland RootComponentView::parentContentIsland() noexcept {
206
224
  if (auto rootView = m_wkRootView.get()) {
207
225
  return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)->Island();
@@ -213,4 +231,15 @@ winrt::Microsoft::ReactNative::implementation::ClipState RootComponentView::getC
213
231
  return winrt::Microsoft::ReactNative::implementation::ClipState::NoClip;
214
232
  }
215
233
 
234
+ HWND RootComponentView::GetHwndForParenting() noexcept {
235
+ if (auto rootView = m_wkRootView.get()) {
236
+ auto hwnd = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)
237
+ ->GetHwndForParenting();
238
+ if (hwnd)
239
+ return hwnd;
240
+ }
241
+
242
+ return base_type::GetHwndForParenting();
243
+ }
244
+
216
245
  } // namespace winrt::Microsoft::ReactNative::Composition::implementation
@@ -28,13 +28,15 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
28
28
 
29
29
  winrt::Microsoft::ReactNative::ComponentView GetFocusedComponent() noexcept;
30
30
  void SetFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &value) noexcept;
31
- bool TrySetFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept;
31
+ bool TrySetFocusedComponent(
32
+ const winrt::Microsoft::ReactNative::ComponentView &view,
33
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction) noexcept;
32
34
 
33
35
  bool NavigateFocus(const winrt::Microsoft::ReactNative::FocusNavigationRequest &request) noexcept;
34
36
 
35
37
  bool TryMoveFocus(bool next) noexcept;
36
38
 
37
- RootComponentView *rootComponentView() noexcept override;
39
+ RootComponentView *rootComponentView() const noexcept override;
38
40
 
39
41
  winrt::Microsoft::UI::Content::ContentIsland parentContentIsland() noexcept;
40
42
 
@@ -44,6 +46,7 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
44
46
 
45
47
  HRESULT GetFragmentRoot(IRawElementProviderFragmentRoot **pRetVal) noexcept;
46
48
  winrt::Microsoft::ReactNative::implementation::ClipState getClipState() noexcept override;
49
+ float FontSizeMultiplier() const noexcept;
47
50
 
48
51
  void updateLayoutMetrics(
49
52
  facebook::react::LayoutMetrics const &layoutMetrics,
@@ -61,6 +64,8 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
61
64
  winrt::Microsoft::ReactNative::ComponentView FindFirstFocusableElement() noexcept;
62
65
  winrt::Microsoft::ReactNative::ComponentView FindLastFocusableElement() noexcept;
63
66
 
67
+ HWND GetHwndForParenting() noexcept override;
68
+
64
69
  private:
65
70
  // should this be a ReactTaggedView? - It shouldn't actually matter since if the view is going away it should always
66
71
  // be clearing its focus But being a reactTaggedView might make it easier to identify cases where that isn't
@@ -886,6 +886,12 @@ void ScrollViewComponentView::OnPointerPressed(
886
886
  m_verticalScrollbarComponent->OnPointerPressed(args);
887
887
  m_horizontalScrollbarComponent->OnPointerPressed(args);
888
888
  Super::OnPointerPressed(args);
889
+
890
+ if (!args.Handled()) {
891
+ auto f = args.Pointer();
892
+ auto g = f.PointerDeviceType();
893
+ m_scrollVisual.OnPointerPressed(args);
894
+ }
889
895
  }
890
896
 
891
897
  void ScrollViewComponentView::OnPointerReleased(
@@ -1045,13 +1051,16 @@ bool ScrollViewComponentView::scrollRight(float delta, bool animate) noexcept {
1045
1051
  return true;
1046
1052
  }
1047
1053
 
1048
- void ScrollViewComponentView::HandleCommand(
1049
- winrt::hstring commandName,
1050
- const winrt::Microsoft::ReactNative::IJSValueReader &args) noexcept {
1054
+ void ScrollViewComponentView::HandleCommand(const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept {
1055
+ Super::HandleCommand(args);
1056
+ if (args.Handled())
1057
+ return;
1058
+
1059
+ auto commandName = args.CommandName();
1051
1060
  if (commandName == L"scrollTo") {
1052
1061
  double x, y;
1053
1062
  bool animate;
1054
- winrt::Microsoft::ReactNative::ReadArgs(args, x, y, animate);
1063
+ winrt::Microsoft::ReactNative::ReadArgs(args.CommandArgs(), x, y, animate);
1055
1064
  scrollTo(
1056
1065
  {static_cast<float>(x) * m_layoutMetrics.pointScaleFactor,
1057
1066
  static_cast<float>(y) * m_layoutMetrics.pointScaleFactor,
@@ -1061,12 +1070,10 @@ void ScrollViewComponentView::HandleCommand(
1061
1070
  // No-op for now
1062
1071
  } else if (commandName == L"scrollToEnd") {
1063
1072
  bool animate;
1064
- winrt::Microsoft::ReactNative::ReadArgs(args, animate);
1073
+ winrt::Microsoft::ReactNative::ReadArgs(args.CommandArgs(), animate);
1065
1074
  scrollToEnd(animate);
1066
1075
  } else if (commandName == L"zoomToRect") {
1067
1076
  // No-op for now
1068
- } else {
1069
- Super::HandleCommand(commandName, args);
1070
1077
  }
1071
1078
  }
1072
1079
 
@@ -74,8 +74,7 @@ struct ScrollInteractionTrackerOwner : public winrt::implements<
74
74
  void prepareForRecycle() noexcept override;
75
75
  void OnKeyDown(const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept override;
76
76
 
77
- void HandleCommand(winrt::hstring commandName, const winrt::Microsoft::ReactNative::IJSValueReader &args) noexcept
78
- override;
77
+ void HandleCommand(const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept override;
79
78
  facebook::react::Tag hitTest(facebook::react::Point pt, facebook::react::Point &localPt, bool ignorePointerEvents)
80
79
  const noexcept override;
81
80
  facebook::react::Point getClientOffset() const noexcept override;
@@ -56,14 +56,14 @@ void SwitchComponentView::UnmountChildComponentView(
56
56
  base_type::UnmountChildComponentView(childComponentView, index);
57
57
  }
58
58
 
59
- void SwitchComponentView::HandleCommand(
60
- winrt::hstring commandName,
61
- const winrt::Microsoft::ReactNative::IJSValueReader &args) noexcept {
59
+ void SwitchComponentView::HandleCommand(const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept {
60
+ Super::HandleCommand(args);
61
+ if (args.Handled())
62
+ return;
63
+ auto commandName = args.CommandName();
62
64
  if (commandName == L"setValue") {
63
65
  // TODO - Current implementation always aligns with JS value
64
66
  // This will be needed when we move to using WinUI controls
65
- } else {
66
- Super::HandleCommand(commandName, args);
67
67
  }
68
68
  }
69
69
 
@@ -261,7 +261,7 @@ void SwitchComponentView::OnPointerPressed(
261
261
  m_supressAnimationForNextFrame = true;
262
262
 
263
263
  if (auto root = rootComponentView()) {
264
- root->TrySetFocusedComponent(*get_strong());
264
+ root->TrySetFocusedComponent(*get_strong(), winrt::Microsoft::ReactNative::FocusNavigationDirection::None);
265
265
  }
266
266
 
267
267
  updateVisuals();
@@ -27,8 +27,7 @@ struct SwitchComponentView : SwitchComponentViewT<SwitchComponentView, ViewCompo
27
27
  void UnmountChildComponentView(
28
28
  const winrt::Microsoft::ReactNative::ComponentView &childComponentView,
29
29
  uint32_t index) noexcept override;
30
- void HandleCommand(winrt::hstring commandName, const winrt::Microsoft::ReactNative::IJSValueReader &args) noexcept
31
- override;
30
+ void HandleCommand(const winrt::Microsoft::ReactNative::HandleCommandArgs &args) noexcept override;
32
31
  void updateProps(facebook::react::Props::Shared const &props, facebook::react::Props::Shared const &oldProps) noexcept
33
32
  override;
34
33
  void updateState(facebook::react::State::Shared const &state, facebook::react::State::Shared const &oldState) noexcept