react-native-windows 0.74.5 → 0.74.7

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 (26) hide show
  1. package/Microsoft.ReactNative/ComponentView.idl +26 -0
  2. package/Microsoft.ReactNative/CompositionComponentView.idl +2 -0
  3. package/Microsoft.ReactNative/CompositionRootView.idl +13 -3
  4. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +83 -12
  5. package/Microsoft.ReactNative/Fabric/ComponentView.h +33 -2
  6. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +6 -6
  7. package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.cpp +3 -2
  8. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootView.cpp +131 -79
  9. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootView.h +20 -13
  10. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +37 -23
  11. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +8 -2
  12. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +152 -0
  13. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +85 -0
  14. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +54 -40
  15. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +9 -1
  16. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +7 -5
  17. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +2 -2
  18. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +6 -12
  19. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +1 -0
  20. package/Microsoft.ReactNative/FocusManager.idl +22 -0
  21. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  22. package/Shared/Shared.vcxitems +6 -5
  23. package/package.json +1 -1
  24. package/templates/cpp-app/windows/MyApp/MyApp.cpp +3 -2
  25. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootView_emptyimpl.cpp +0 -149
  26. package/Microsoft.ReactNative/Views/ICompositionRootView.h +0 -18
@@ -7,11 +7,11 @@
7
7
  #include <FocusNavigationResult.g.h>
8
8
 
9
9
  #include <ReactContext.h>
10
+ #include <react/renderer/core/LayoutConstraints.h>
10
11
  #include <winrt/Microsoft.ReactNative.Composition.Experimental.h>
11
12
  #include <winrt/Microsoft.ReactNative.h>
12
13
  #include "CompositionEventHandler.h"
13
14
  #include "ReactHost/React.h"
14
- #include "Views/ICompositionRootView.h"
15
15
 
16
16
  namespace winrt::Microsoft::ReactNative::implementation {
17
17
 
@@ -42,8 +42,7 @@ struct FocusNavigationResult : FocusNavigationResultT<FocusNavigationResult> {
42
42
  };
43
43
 
44
44
  struct CompositionRootView
45
- : CompositionRootViewT<CompositionRootView, Composition::Experimental::IInternalCompositionRootView>,
46
- ::Microsoft::ReactNative::ICompositionRootView {
45
+ : CompositionRootViewT<CompositionRootView, Composition::Experimental::IInternalCompositionRootView> {
47
46
  CompositionRootView() noexcept;
48
47
  ~CompositionRootView() noexcept;
49
48
 
@@ -70,6 +69,12 @@ struct CompositionRootView
70
69
  float ScaleFactor() noexcept;
71
70
  void ScaleFactor(float value) noexcept;
72
71
 
72
+ winrt::event_token SizeChanged(
73
+ winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::RootViewSizeChangedEventArgs> const
74
+ &handler) noexcept;
75
+ void SizeChanged(winrt::event_token const &token) noexcept;
76
+ void NotifySizeChanged() noexcept;
77
+
73
78
  void AddRenderedVisual(const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept;
74
79
  void RemoveRenderedVisual(const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept;
75
80
  bool TrySetFocus() noexcept;
@@ -80,8 +85,12 @@ struct CompositionRootView
80
85
  winrt::Microsoft::ReactNative::Composition::Theme Theme() noexcept;
81
86
  void Theme(const winrt::Microsoft::ReactNative::Composition::Theme &value) noexcept;
82
87
 
83
- winrt::Windows::Foundation::Size Measure(winrt::Windows::Foundation::Size const &availableSize) const;
84
- winrt::Windows::Foundation::Size Arrange(winrt::Windows::Foundation::Size finalSize) const;
88
+ winrt::Windows::Foundation::Size Measure(
89
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
90
+ const winrt::Windows::Foundation::Point &viewportOffset) const noexcept;
91
+ void Arrange(
92
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
93
+ const winrt::Windows::Foundation::Point &viewportOffset) noexcept;
85
94
 
86
95
  winrt::Microsoft::ReactNative::FocusNavigationResult NavigateFocus(
87
96
  const winrt::Microsoft::ReactNative::FocusNavigationRequest &request) noexcept;
@@ -103,13 +112,6 @@ struct CompositionRootView
103
112
  const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
104
113
  facebook::react::Tag tag) noexcept;
105
114
 
106
- public: // IReactRootView
107
- std::string JSComponentName() const noexcept override;
108
- int64_t GetActualHeight() const noexcept override;
109
- int64_t GetActualWidth() const noexcept override;
110
- int64_t GetTag() const noexcept override;
111
- void SetTag(int64_t tag) noexcept override;
112
-
113
115
  public: // IReactViewInstance UI-thread implementation
114
116
  void InitRootView(
115
117
  winrt::Microsoft::ReactNative::IReactContext &&context,
@@ -121,6 +123,8 @@ struct CompositionRootView
121
123
  #ifdef USE_WINUI3
122
124
  winrt::Microsoft::UI::Composition::Compositor m_compositor{nullptr};
123
125
  winrt::Microsoft::UI::Content::ContentIsland m_island{nullptr};
126
+ winrt::event_token m_islandFrameworkClosedToken;
127
+ winrt::event_token m_islandAutomationProviderRequestedToken;
124
128
  #endif
125
129
 
126
130
  HWND m_hwnd{0};
@@ -132,7 +136,7 @@ struct CompositionRootView
132
136
  winrt::IInspectable m_uiaProvider{nullptr};
133
137
  int64_t m_rootTag{-1};
134
138
  float m_scaleFactor{1.0};
135
- winrt::Windows::Foundation::Size m_size;
139
+ winrt::Windows::Foundation::Size m_size{0, 0};
136
140
  winrt::Microsoft::ReactNative::ReactContext m_context;
137
141
  winrt::Microsoft::ReactNative::IReactViewHost m_reactViewHost;
138
142
  winrt::Microsoft::ReactNative::ReactViewOptions m_reactViewOptions;
@@ -143,6 +147,9 @@ struct CompositionRootView
143
147
  winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader m_resources{nullptr};
144
148
  winrt::Microsoft::ReactNative::Composition::Theme m_theme{nullptr};
145
149
  winrt::Microsoft::ReactNative::Composition::Theme::ThemeChanged_revoker m_themeChangedRevoker;
150
+ facebook::react::LayoutConstraints m_layoutConstraints;
151
+ winrt::event<winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::RootViewSizeChangedEventArgs>>
152
+ m_sizeChangedEvent;
146
153
 
147
154
  void UpdateRootViewInternal() noexcept;
148
155
  void ClearLoadingUI() noexcept;
@@ -121,6 +121,10 @@ winrt::Microsoft::ReactNative::Composition::Theme ComponentView::Theme() const n
121
121
  return theme()->get_strong().as<winrt::Microsoft::ReactNative::Composition::Theme>();
122
122
  }
123
123
 
124
+ winrt::Microsoft::ReactNative::Composition::RootComponentView ComponentView::Root() noexcept {
125
+ return *rootComponentView();
126
+ }
127
+
124
128
  winrt::Microsoft::UI::Composition::Compositor ComponentView::Compositor() const noexcept {
125
129
  return winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerCompositor(
126
130
  m_compContext);
@@ -171,6 +175,10 @@ void ComponentView::updateLayoutMetrics(
171
175
  base_type::updateLayoutMetrics(layoutMetrics, oldLayoutMetrics);
172
176
  }
173
177
 
178
+ const facebook::react::LayoutMetrics &ComponentView::layoutMetrics() const noexcept {
179
+ return m_layoutMetrics;
180
+ }
181
+
174
182
  void ComponentView::FinalizeUpdates(winrt::Microsoft::ReactNative::ComponentViewUpdateMask updateMask) noexcept {
175
183
  if ((m_flags & ComponentViewFeatures::NativeBorder) == ComponentViewFeatures::NativeBorder) {
176
184
  finalizeBorderUpdates(m_layoutMetrics, *viewProps());
@@ -179,32 +187,38 @@ void ComponentView::FinalizeUpdates(winrt::Microsoft::ReactNative::ComponentView
179
187
  base_type::FinalizeUpdates(updateMask);
180
188
  }
181
189
 
182
- void ComponentView::onFocusLost() noexcept {
183
- m_eventEmitter->onBlur();
184
- showFocusVisual(false);
185
- if (m_uiaProvider) {
186
- winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
187
- m_uiaProvider, UIA_HasKeyboardFocusPropertyId, true, false);
190
+ void ComponentView::onLostFocus(
191
+ const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
192
+ if (args.OriginalSource() == Tag()) {
193
+ m_eventEmitter->onBlur();
194
+ showFocusVisual(false);
195
+ if (m_uiaProvider) {
196
+ winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
197
+ m_uiaProvider, UIA_HasKeyboardFocusPropertyId, true, false);
198
+ }
188
199
  }
189
- base_type::onFocusLost();
200
+ base_type::onLostFocus(args);
190
201
  }
191
202
 
192
- void ComponentView::onFocusGained() noexcept {
193
- m_eventEmitter->onFocus();
194
- if (m_enableFocusVisual) {
195
- showFocusVisual(true);
196
- }
197
- if (m_uiaProvider) {
198
- auto spProviderSimple = m_uiaProvider.try_as<IRawElementProviderSimple>();
199
- if (spProviderSimple != nullptr) {
200
- winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
201
- m_uiaProvider, UIA_HasKeyboardFocusPropertyId, false, true);
202
- UiaRaiseAutomationEvent(spProviderSimple.get(), UIA_AutomationFocusChangedEventId);
203
+ void ComponentView::onGotFocus(
204
+ const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
205
+ if (args.OriginalSource() == Tag()) {
206
+ m_eventEmitter->onFocus();
207
+ if (m_enableFocusVisual) {
208
+ showFocusVisual(true);
209
+ }
210
+ if (m_uiaProvider) {
211
+ auto spProviderSimple = m_uiaProvider.try_as<IRawElementProviderSimple>();
212
+ if (spProviderSimple != nullptr) {
213
+ winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
214
+ m_uiaProvider, UIA_HasKeyboardFocusPropertyId, false, true);
215
+ UiaRaiseAutomationEvent(spProviderSimple.get(), UIA_AutomationFocusChangedEventId);
216
+ }
203
217
  }
204
- }
205
218
 
206
- StartBringIntoView({});
207
- base_type::onFocusGained();
219
+ StartBringIntoView({});
220
+ }
221
+ base_type::onGotFocus(args);
208
222
  }
209
223
 
210
224
  void ComponentView::StartBringIntoView(
@@ -234,13 +248,13 @@ void ComponentView::HandleCommand(
234
248
  const winrt::Microsoft::ReactNative::IJSValueReader &args) noexcept {
235
249
  if (commandName == L"focus") {
236
250
  if (auto root = rootComponentView()) {
237
- root->SetFocusedComponent(*get_strong());
251
+ root->TrySetFocusedComponent(*get_strong());
238
252
  }
239
253
  return;
240
254
  }
241
255
  if (commandName == L"blur") {
242
256
  if (auto root = rootComponentView()) {
243
- root->SetFocusedComponent(nullptr); // Todo store this component as previously focused element
257
+ root->TrySetFocusedComponent(nullptr); // Todo store this component as previously focused element
244
258
  }
245
259
  return;
246
260
  }
@@ -69,11 +69,14 @@ struct ComponentView
69
69
  assert(false);
70
70
  return emptyProps;
71
71
  };
72
+
73
+ winrt::Microsoft::ReactNative::Composition::RootComponentView Root() noexcept;
74
+
72
75
  void Theme(const winrt::Microsoft::ReactNative::Composition::Theme &theme) noexcept;
73
76
  winrt::Microsoft::ReactNative::Composition::Theme Theme() const noexcept;
74
77
  void onThemeChanged() noexcept override;
75
- void onFocusLost() noexcept override;
76
- void onFocusGained() noexcept override;
78
+ void onLostFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept override;
79
+ void onGotFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept override;
77
80
  bool CapturePointer(const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer) noexcept;
78
81
  void ReleasePointerCapture(const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer) noexcept;
79
82
 
@@ -117,6 +120,8 @@ struct ComponentView
117
120
  bool getAcccessiblityIsReadOnly() noexcept override;
118
121
  virtual winrt::Microsoft::ReactNative::implementation::ClipState getClipState() noexcept;
119
122
 
123
+ const facebook::react::LayoutMetrics &layoutMetrics() const noexcept;
124
+
120
125
  virtual std::string DefaultControlType() const noexcept;
121
126
  virtual std::string DefaultAccessibleName() const noexcept;
122
127
  virtual std::string DefaultHelpText() const noexcept;
@@ -189,6 +194,7 @@ struct ViewComponentView : public ViewComponentViewT<ViewComponentView, Componen
189
194
  facebook::react::LayoutMetrics const &layoutMetrics,
190
195
  facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept override;
191
196
  void prepareForRecycle() noexcept override;
197
+ bool TryFocus() noexcept;
192
198
  bool focusable() const noexcept override;
193
199
  void OnKeyDown(
194
200
  const winrt::Microsoft::ReactNative::Composition::Input::KeyboardSource &source,
@@ -0,0 +1,152 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "pch.h"
5
+ #include "FocusManager.h"
6
+ #include "Composition.FocusManager.g.cpp"
7
+ #include <Fabric/FabricUIManagerModule.h>
8
+
9
+ namespace winrt::Microsoft::ReactNative::implementation {
10
+
11
+ LostFocusEventArgs::LostFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource)
12
+ : m_originalSource(originalSource ? originalSource.Tag() : -1) {}
13
+ int32_t LostFocusEventArgs::OriginalSource() noexcept {
14
+ return m_originalSource;
15
+ }
16
+
17
+ GotFocusEventArgs::GotFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource)
18
+ : m_originalSource(originalSource ? originalSource.Tag() : -1) {}
19
+ int32_t GotFocusEventArgs::OriginalSource() noexcept {
20
+ return m_originalSource;
21
+ }
22
+
23
+ LosingFocusEventArgs::LosingFocusEventArgs(
24
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
25
+ const winrt::Microsoft::ReactNative::ComponentView &oldFocusedComponent,
26
+ const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent)
27
+ : m_originalSource(originalSource ? originalSource.Tag() : -1),
28
+ m_old(oldFocusedComponent),
29
+ m_new(newFocusedComponent) {}
30
+
31
+ int32_t LosingFocusEventArgs::OriginalSource() noexcept {
32
+ return m_originalSource;
33
+ }
34
+ winrt::Microsoft::ReactNative::ComponentView LosingFocusEventArgs::NewFocusedComponent() noexcept {
35
+ return m_new;
36
+ }
37
+ winrt::Microsoft::ReactNative::ComponentView LosingFocusEventArgs::OldFocusedComponent() noexcept {
38
+ return m_old;
39
+ }
40
+
41
+ void LosingFocusEventArgs::TryCancel() noexcept {
42
+ m_new = m_old;
43
+ }
44
+
45
+ void LosingFocusEventArgs::TrySetNewFocusedComponent(
46
+ const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent) noexcept {
47
+ auto selfView = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(newFocusedComponent);
48
+ if (selfView->focusable()) {
49
+ m_new = newFocusedComponent;
50
+ } else {
51
+ auto target =
52
+ winrt::Microsoft::ReactNative::Composition::FocusManager::FindFirstFocusableElement(newFocusedComponent);
53
+ if (!target)
54
+ return;
55
+ m_new = target;
56
+ }
57
+ }
58
+
59
+ GettingFocusEventArgs::GettingFocusEventArgs(
60
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
61
+ const winrt::Microsoft::ReactNative::ComponentView &oldFocusedComponent,
62
+ const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent)
63
+ : m_originalSource(originalSource ? originalSource.Tag() : -1),
64
+ m_old(oldFocusedComponent),
65
+ m_new(newFocusedComponent) {}
66
+
67
+ int32_t GettingFocusEventArgs::OriginalSource() noexcept {
68
+ return m_originalSource;
69
+ }
70
+ winrt::Microsoft::ReactNative::ComponentView GettingFocusEventArgs::NewFocusedComponent() noexcept {
71
+ return m_new;
72
+ }
73
+ winrt::Microsoft::ReactNative::ComponentView GettingFocusEventArgs::OldFocusedComponent() noexcept {
74
+ return m_old;
75
+ }
76
+
77
+ void GettingFocusEventArgs::TryCancel() noexcept {
78
+ m_new = m_old;
79
+ }
80
+
81
+ void GettingFocusEventArgs::TrySetNewFocusedComponent(
82
+ const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent) noexcept {
83
+ auto selfView = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(newFocusedComponent);
84
+ if (selfView->focusable()) {
85
+ m_new = newFocusedComponent;
86
+ } else {
87
+ auto target =
88
+ winrt::Microsoft::ReactNative::Composition::FocusManager::FindFirstFocusableElement(newFocusedComponent);
89
+ if (!target)
90
+ return;
91
+ m_new = target;
92
+ }
93
+ }
94
+
95
+ } // namespace winrt::Microsoft::ReactNative::implementation
96
+
97
+ namespace winrt::Microsoft::ReactNative::Composition::implementation {
98
+
99
+ winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelper(
100
+ winrt::Microsoft::ReactNative::implementation::ComponentView &view,
101
+ winrt::Microsoft::ReactNative::FocusNavigationReason reason) {
102
+ if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First) {
103
+ if (view.focusable()) {
104
+ return &view;
105
+ }
106
+ }
107
+ winrt::Microsoft::ReactNative::implementation::ComponentView *toFocus = nullptr;
108
+
109
+ Mso::Functor<bool(::winrt::Microsoft::ReactNative::implementation::ComponentView & v)> fn =
110
+ [reason, &toFocus](::winrt::Microsoft::ReactNative::implementation::ComponentView &v) noexcept
111
+ -> bool { return (toFocus = NavigateFocusHelper(v, reason)); };
112
+
113
+ if (view.runOnChildren(reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First, fn)) {
114
+ return toFocus;
115
+ }
116
+
117
+ if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::Last) {
118
+ if (view.focusable()) {
119
+ return &view;
120
+ }
121
+ }
122
+
123
+ return nullptr;
124
+ }
125
+
126
+ winrt::Microsoft::ReactNative::ComponentView FocusManager::FindFirstFocusableElement(
127
+ const winrt::Microsoft::ReactNative::ComponentView &searchScope) noexcept {
128
+ auto selfSearchScope = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(searchScope);
129
+ auto view = NavigateFocusHelper(*selfSearchScope, winrt::Microsoft::ReactNative::FocusNavigationReason::First);
130
+ if (view) {
131
+ winrt::Microsoft::ReactNative::ComponentView component{nullptr};
132
+ winrt::check_hresult(view->QueryInterface(
133
+ winrt::guid_of<winrt::Microsoft::ReactNative::ComponentView>(), winrt::put_abi(component)));
134
+ return *view;
135
+ }
136
+ return nullptr;
137
+ }
138
+
139
+ winrt::Microsoft::ReactNative::ComponentView FocusManager::FindLastFocusableElement(
140
+ const winrt::Microsoft::ReactNative::ComponentView &searchScope) noexcept {
141
+ auto selfSearchScope = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(searchScope);
142
+ auto view = NavigateFocusHelper(*selfSearchScope, winrt::Microsoft::ReactNative::FocusNavigationReason::Last);
143
+ if (view) {
144
+ winrt::Microsoft::ReactNative::ComponentView component{nullptr};
145
+ winrt::check_hresult(view->QueryInterface(
146
+ winrt::guid_of<winrt::Microsoft::ReactNative::ComponentView>(), winrt::put_abi(component)));
147
+ return *view;
148
+ }
149
+ return nullptr;
150
+ }
151
+
152
+ } // namespace winrt::Microsoft::ReactNative::Composition::implementation
@@ -0,0 +1,85 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+ #include "Composition.FocusManager.g.h"
6
+ #include "GettingFocusEventArgs.g.h"
7
+ #include "LosingFocusEventArgs.g.h"
8
+ #include <winrt/Microsoft.ReactNative.Composition.Experimental.h>
9
+ #include <winrt/Microsoft.ReactNative.Composition.Input.h>
10
+
11
+ namespace winrt::Microsoft::ReactNative::implementation {
12
+
13
+ struct LostFocusEventArgs
14
+ : winrt::implements<LostFocusEventArgs, winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs> {
15
+ LostFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource);
16
+ int32_t OriginalSource() noexcept;
17
+
18
+ private:
19
+ const int32_t m_originalSource;
20
+ };
21
+
22
+ struct GotFocusEventArgs
23
+ : winrt::implements<GotFocusEventArgs, winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs> {
24
+ GotFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource);
25
+ int32_t OriginalSource() noexcept;
26
+
27
+ private:
28
+ const int32_t m_originalSource;
29
+ };
30
+
31
+ struct LosingFocusEventArgs
32
+ : winrt::Microsoft::ReactNative::implementation::LosingFocusEventArgsT<LosingFocusEventArgs> {
33
+ LosingFocusEventArgs(
34
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
35
+ const winrt::Microsoft::ReactNative::ComponentView &oldFocusedComponent,
36
+ 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;
40
+
41
+ void TryCancel() noexcept;
42
+ void TrySetNewFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent) noexcept;
43
+
44
+ private:
45
+ const int32_t m_originalSource;
46
+ winrt::Microsoft::ReactNative::ComponentView m_old{nullptr};
47
+ winrt::Microsoft::ReactNative::ComponentView m_new{nullptr};
48
+ };
49
+
50
+ struct GettingFocusEventArgs
51
+ : winrt::Microsoft::ReactNative::implementation::GettingFocusEventArgsT<GettingFocusEventArgs> {
52
+ GettingFocusEventArgs(
53
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
54
+ const winrt::Microsoft::ReactNative::ComponentView &oldFocusedComponent,
55
+ 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;
59
+
60
+ void TryCancel() noexcept;
61
+ void TrySetNewFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &newFocusedComponent) noexcept;
62
+
63
+ private:
64
+ const int32_t m_originalSource;
65
+ winrt::Microsoft::ReactNative::ComponentView m_old{nullptr};
66
+ winrt::Microsoft::ReactNative::ComponentView m_new{nullptr};
67
+ };
68
+ } // namespace winrt::Microsoft::ReactNative::implementation
69
+
70
+ namespace winrt::Microsoft::ReactNative::Composition::implementation {
71
+
72
+ struct FocusManager : FocusManagerT<FocusManager> {
73
+ FocusManager() = default;
74
+
75
+ static winrt::Microsoft::ReactNative::ComponentView FindFirstFocusableElement(
76
+ const winrt::Microsoft::ReactNative::ComponentView &searchScope) noexcept;
77
+ static winrt::Microsoft::ReactNative::ComponentView FindLastFocusableElement(
78
+ const winrt::Microsoft::ReactNative::ComponentView &searchScope) noexcept;
79
+ };
80
+
81
+ } // namespace winrt::Microsoft::ReactNative::Composition::implementation
82
+
83
+ namespace winrt::Microsoft::ReactNative::Composition::factory_implementation {
84
+ struct FocusManager : FocusManagerT<FocusManager, implementation::FocusManager> {};
85
+ } // namespace winrt::Microsoft::ReactNative::Composition::factory_implementation
@@ -45,7 +45,21 @@ RootComponentView *RootComponentView::rootComponentView() noexcept {
45
45
  return this;
46
46
  }
47
47
 
48
- winrt::Microsoft::ReactNative::ComponentView &RootComponentView::GetFocusedComponent() noexcept {
48
+ void RootComponentView::updateLayoutMetrics(
49
+ facebook::react::LayoutMetrics const &layoutMetrics,
50
+ facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept {
51
+ base_type::updateLayoutMetrics(layoutMetrics, oldLayoutMetrics);
52
+
53
+ if (oldLayoutMetrics.frame != layoutMetrics.frame ||
54
+ oldLayoutMetrics.pointScaleFactor != layoutMetrics.pointScaleFactor) {
55
+ if (auto rootView = m_wkRootView.get()) {
56
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(rootView)
57
+ ->NotifySizeChanged();
58
+ }
59
+ }
60
+ }
61
+
62
+ winrt::Microsoft::ReactNative::ComponentView RootComponentView::GetFocusedComponent() noexcept {
49
63
  return m_focusedComponent;
50
64
  }
51
65
  void RootComponentView::SetFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &value) noexcept {
@@ -53,69 +67,69 @@ void RootComponentView::SetFocusedComponent(const winrt::Microsoft::ReactNative:
53
67
  return;
54
68
 
55
69
  if (m_focusedComponent) {
56
- winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(m_focusedComponent)->onFocusLost();
70
+ auto args = winrt::make<winrt::Microsoft::ReactNative::implementation::LostFocusEventArgs>(m_focusedComponent);
71
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(m_focusedComponent)
72
+ ->onLostFocus(args);
57
73
  }
58
74
 
59
75
  if (value) {
60
76
  if (auto rootView = m_wkRootView.get()) {
61
77
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::CompositionRootView>(rootView)->TrySetFocus();
62
78
  }
63
- winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(value)->onFocusGained();
79
+ auto args = winrt::make<winrt::Microsoft::ReactNative::implementation::GotFocusEventArgs>(value);
80
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(value)->onGotFocus(args);
64
81
  }
65
82
 
66
83
  m_focusedComponent = value;
67
84
  }
68
85
 
69
- winrt::Microsoft::ReactNative::implementation::ComponentView *NavigateFocusHelper(
70
- winrt::Microsoft::ReactNative::implementation::ComponentView &view,
71
- winrt::Microsoft::ReactNative::FocusNavigationReason reason) {
72
- if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First) {
73
- if (view.focusable()) {
74
- return &view;
75
- }
76
- }
77
- winrt::Microsoft::ReactNative::implementation::ComponentView *toFocus = nullptr;
78
-
79
- Mso::Functor<bool(::winrt::Microsoft::ReactNative::implementation::ComponentView & v)> fn =
80
- [reason, &toFocus](::winrt::Microsoft::ReactNative::implementation::ComponentView &v) noexcept
81
- -> bool { return (toFocus = NavigateFocusHelper(v, reason)); };
82
-
83
- if (view.runOnChildren(reason == winrt::Microsoft::ReactNative::FocusNavigationReason::First, fn)) {
84
- return toFocus;
85
- }
86
-
87
- if (reason == winrt::Microsoft::ReactNative::FocusNavigationReason::Last) {
88
- if (view.focusable()) {
89
- return &view;
90
- }
91
- }
92
-
93
- return nullptr;
94
- }
95
-
96
86
  bool RootComponentView::NavigateFocus(const winrt::Microsoft::ReactNative::FocusNavigationRequest &request) noexcept {
97
87
  if (request.Reason() == winrt::Microsoft::ReactNative::FocusNavigationReason::Restore) {
98
88
  // No-op for now
99
89
  return m_focusedComponent != nullptr;
100
90
  }
101
91
 
102
- auto view = NavigateFocusHelper(*this, request.Reason());
92
+ auto view = (request.Reason() == winrt::Microsoft::ReactNative::FocusNavigationReason::First)
93
+ ? FocusManager::FindFirstFocusableElement(*this)
94
+ : FocusManager::FindLastFocusableElement(*this);
103
95
  if (view) {
104
- winrt::Microsoft::ReactNative::ComponentView component{nullptr};
105
- winrt::check_hresult(view->QueryInterface(
106
- winrt::guid_of<winrt::Microsoft::ReactNative::ComponentView>(), winrt::put_abi(component)));
107
- SetFocusedComponent(component);
96
+ TrySetFocusedComponent(view);
108
97
  }
109
98
  return view != nullptr;
110
99
  }
111
100
 
112
101
  bool RootComponentView::TrySetFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
113
- auto selfView = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(view);
114
- if (selfView->focusable()) {
115
- selfView->rootComponentView()->SetFocusedComponent(view);
116
- return true;
102
+ auto target = view;
103
+ auto selfView = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(target);
104
+ if (selfView && !selfView->focusable()) {
105
+ target = FocusManager::FindFirstFocusableElement(target);
106
+ if (!target)
107
+ return false;
108
+ selfView = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(target);
109
+ }
110
+
111
+ if (selfView && selfView->rootComponentView() != this)
112
+ return false;
113
+
114
+ auto losingFocusArgs = winrt::make<winrt::Microsoft::ReactNative::implementation::LosingFocusEventArgs>(
115
+ target, m_focusedComponent, target);
116
+ if (m_focusedComponent) {
117
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(m_focusedComponent)
118
+ ->onLosingFocus(losingFocusArgs);
119
+ }
120
+
121
+ if (losingFocusArgs.NewFocusedComponent()) {
122
+ auto gettingFocusArgs = winrt::make<winrt::Microsoft::ReactNative::implementation::GettingFocusEventArgs>(
123
+ target, m_focusedComponent, losingFocusArgs.NewFocusedComponent());
124
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(losingFocusArgs.NewFocusedComponent())
125
+ ->onGettingFocus(gettingFocusArgs);
126
+
127
+ winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(losingFocusArgs.NewFocusedComponent())
128
+ ->rootComponentView()
129
+ ->SetFocusedComponent(gettingFocusArgs.NewFocusedComponent());
117
130
  }
118
- return false;
131
+
132
+ return true;
119
133
  }
120
134
 
121
135
  bool RootComponentView::TryMoveFocus(bool next) noexcept {
@@ -8,6 +8,7 @@
8
8
  #include <Microsoft.ReactNative.Cxx/ReactContext.h>
9
9
 
10
10
  #include "CompositionViewComponentView.h"
11
+ #include "FocusManager.h"
11
12
  #include "Theme.h"
12
13
 
13
14
  #include "Composition.RootComponentView.g.h"
@@ -25,7 +26,7 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
25
26
  facebook::react::Tag tag,
26
27
  winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept;
27
28
 
28
- winrt::Microsoft::ReactNative::ComponentView &GetFocusedComponent() noexcept;
29
+ winrt::Microsoft::ReactNative::ComponentView GetFocusedComponent() noexcept;
29
30
  void SetFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &value) noexcept;
30
31
  bool TrySetFocusedComponent(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept;
31
32
 
@@ -42,6 +43,10 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
42
43
  HRESULT GetFragmentRoot(IRawElementProviderFragmentRoot **pRetVal) noexcept;
43
44
  winrt::Microsoft::ReactNative::implementation::ClipState getClipState() noexcept override;
44
45
 
46
+ void updateLayoutMetrics(
47
+ facebook::react::LayoutMetrics const &layoutMetrics,
48
+ facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept override;
49
+
45
50
  winrt::IInspectable UiaProviderFromPoint(const POINT &ptPixels) noexcept;
46
51
 
47
52
  RootComponentView(
@@ -51,6 +56,9 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
51
56
 
52
57
  virtual ~RootComponentView();
53
58
 
59
+ winrt::Microsoft::ReactNative::ComponentView FindFirstFocusableElement() noexcept;
60
+ winrt::Microsoft::ReactNative::ComponentView FindLastFocusableElement() noexcept;
61
+
54
62
  private:
55
63
  // should this be a ReactTaggedView? - It shouldn't actually matter since if the view is going away it should always
56
64
  // be clearing its focus But being a reactTaggedView might make it easier to identify cases where that isn't
@@ -224,7 +224,7 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
224
224
  winrt::Microsoft::ReactNative::ComponentView view{nullptr};
225
225
  winrt::check_hresult(
226
226
  m_outer->QueryInterface(winrt::guid_of<winrt::Microsoft::ReactNative::ComponentView>(), winrt::put_abi(view)));
227
- m_outer->rootComponentView()->SetFocusedComponent(view);
227
+ m_outer->rootComponentView()->TrySetFocusedComponent(view);
228
228
  // assert(false);
229
229
  // TODO focus
230
230
  }
@@ -929,8 +929,9 @@ void WindowsTextInputComponentView::UnmountChildComponentView(
929
929
  base_type::UnmountChildComponentView(childComponentView, index);
930
930
  }
931
931
 
932
- void WindowsTextInputComponentView::onFocusLost() noexcept {
933
- Super::onFocusLost();
932
+ void WindowsTextInputComponentView::onLostFocus(
933
+ const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
934
+ Super::onLostFocus(args);
934
935
  if (m_textServices) {
935
936
  LRESULT lresult;
936
937
  DrawBlock db(*this);
@@ -939,8 +940,9 @@ void WindowsTextInputComponentView::onFocusLost() noexcept {
939
940
  m_caretVisual.IsVisible(false);
940
941
  }
941
942
 
942
- void WindowsTextInputComponentView::onFocusGained() noexcept {
943
- Super::onFocusGained();
943
+ void WindowsTextInputComponentView::onGotFocus(
944
+ const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
945
+ Super::onGotFocus(args);
944
946
  if (m_textServices) {
945
947
  LRESULT lresult;
946
948
  DrawBlock db(*this);