react-native-windows 0.78.5 → 0.78.6

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 (189) hide show
  1. package/Directory.Build.props +6 -4
  2. package/Folly/Folly.vcxproj +46 -6
  3. package/Folly/Folly.vcxproj.filters +16 -4
  4. package/Folly/TEMP_UntilFollyUpdate/ConstexprMath.h +26 -18
  5. package/Folly/TEMP_UntilFollyUpdate/Conv.cpp +1205 -0
  6. package/Folly/TEMP_UntilFollyUpdate/chrono/Hardware.h +155 -0
  7. package/Folly/TEMP_UntilFollyUpdate/concurrency/CacheLocality.cpp +633 -0
  8. package/Folly/TEMP_UntilFollyUpdate/{dynamic-inl.h → json/dynamic-inl.h} +3 -4
  9. package/Folly/TEMP_UntilFollyUpdate/{json.cpp → json/json.cpp} +14 -10
  10. package/Folly/TEMP_UntilFollyUpdate/lang/SafeAssert.h +7 -14
  11. package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h +6 -6
  12. package/Folly/ThreadNameStub.cpp +10 -0
  13. package/Folly/cgmanifest.json +11 -1
  14. package/Libraries/Components/View/View.windows.js +107 -56
  15. package/Libraries/Components/View/ViewAccessibility.d.ts +60 -1
  16. package/Libraries/Image/Image.windows.js +42 -21
  17. package/Libraries/Modal/Modal.d.ts +7 -0
  18. package/Libraries/Modal/Modal.windows.js +7 -1
  19. package/Libraries/NativeComponent/BaseViewConfig.windows.js +3 -0
  20. package/Libraries/Text/Text.d.ts +18 -0
  21. package/Microsoft.ReactNative/AsynchronousEventBeat.cpp +4 -25
  22. package/Microsoft.ReactNative/AsynchronousEventBeat.h +0 -3
  23. package/Microsoft.ReactNative/Base/FollyIncludes.h +1 -0
  24. package/Microsoft.ReactNative/CallInvoker.cpp +42 -0
  25. package/Microsoft.ReactNative/CallInvoker.h +34 -0
  26. package/Microsoft.ReactNative/{JSDispatcherWriter.cpp → CallInvokerWriter.cpp} +35 -47
  27. package/Microsoft.ReactNative/CallInvokerWriter.h +74 -0
  28. package/Microsoft.ReactNative/CompositionComponentView.idl +0 -5
  29. package/Microsoft.ReactNative/CompositionSwitcher.idl +7 -0
  30. package/Microsoft.ReactNative/Fabric/AbiViewProps.cpp +8 -10
  31. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +4 -1
  32. package/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp +12 -2
  33. package/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h +2 -0
  34. package/Microsoft.ReactNative/Fabric/Composition/CompositionAnnotationProvider.cpp +100 -0
  35. package/Microsoft.ReactNative/Fabric/Composition/CompositionAnnotationProvider.h +31 -0
  36. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +77 -11
  37. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +43 -1
  38. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +7 -0
  39. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +86 -56
  40. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +5 -1
  41. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +0 -4
  42. package/Microsoft.ReactNative/Fabric/Composition/CompositionUIService.cpp +0 -2
  43. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +118 -63
  44. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +2 -0
  45. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +133 -8
  46. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +16 -2
  47. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +4 -2
  48. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +9 -1
  49. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +34 -11
  50. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +3 -0
  51. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +133 -135
  52. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +9 -6
  53. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +46 -49
  54. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +6 -1
  55. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +13 -8
  56. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +5 -2
  57. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +146 -25
  58. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +14 -0
  59. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +160 -12
  60. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +6 -0
  61. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.cpp +47 -0
  62. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.h +15 -1
  63. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.cpp +6 -2
  64. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h +4 -1
  65. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +7 -9
  66. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +4 -1
  67. package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +5 -0
  68. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +40 -36
  69. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +68 -0
  70. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +11 -0
  71. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +70 -13
  72. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +10 -2
  73. package/Microsoft.ReactNative/Fabric/ImageManager.cpp +5 -5
  74. package/Microsoft.ReactNative/Fabric/ImageRequestParams.cpp +26 -0
  75. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +47 -8
  76. package/Microsoft.ReactNative/Fabric/WindowsImageManager.h +10 -1
  77. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/CompositionAccessibilityProps.h +67 -0
  78. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.cpp +22 -4
  79. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.h +15 -2
  80. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +20 -0
  81. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +5 -0
  82. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/MouseEvent.h +20 -0
  83. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/HostPlatformColor.h +5 -8
  84. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorParser.h +1 -2
  85. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +247 -45
  86. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h +15 -0
  87. package/Microsoft.ReactNative/Fabric/platform/react/threading/MessageQueueThreadImpl.cpp +39 -0
  88. package/Microsoft.ReactNative/Fabric/platform/react/threading/MessageQueueThreadImpl.h +54 -0
  89. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.cpp +126 -0
  90. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.h +73 -0
  91. package/Microsoft.ReactNative/IReactContext.cpp +17 -0
  92. package/Microsoft.ReactNative/IReactContext.h +1 -0
  93. package/Microsoft.ReactNative/IReactContext.idl +18 -1
  94. package/Microsoft.ReactNative/IReactDispatcher.idl +1 -0
  95. package/Microsoft.ReactNative/IReactModuleBuilder.cpp +12 -0
  96. package/Microsoft.ReactNative/IReactModuleBuilder.h +2 -0
  97. package/Microsoft.ReactNative/IReactModuleBuilder.idl +8 -0
  98. package/Microsoft.ReactNative/JsiApi.cpp +10 -2
  99. package/Microsoft.ReactNative/JsiApi.h +1 -0
  100. package/Microsoft.ReactNative/JsiApi.idl +1 -0
  101. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +0 -3
  102. package/Microsoft.ReactNative/Modules/AccessibilityInfoModule.cpp +2 -3
  103. package/Microsoft.ReactNative/Modules/AlertModule.cpp +7 -12
  104. package/Microsoft.ReactNative/Modules/Animated/AnimationDriver.cpp +2 -1
  105. package/Microsoft.ReactNative/Modules/Animated/NativeAnimatedModule.cpp +4 -8
  106. package/Microsoft.ReactNative/Modules/AppStateModule.cpp +2 -2
  107. package/Microsoft.ReactNative/Modules/ClipboardModule.cpp +6 -8
  108. package/Microsoft.ReactNative/Modules/ClipboardModule.h +1 -1
  109. package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +6 -15
  110. package/Microsoft.ReactNative/Modules/NativeUIManager.cpp +13 -24
  111. package/Microsoft.ReactNative/QuirkSettings.cpp +0 -16
  112. package/Microsoft.ReactNative/QuirkSettings.h +0 -3
  113. package/Microsoft.ReactNative/ReactHost/ReactHost.cpp +11 -1
  114. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +78 -68
  115. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -2
  116. package/Microsoft.ReactNative/ReactInstanceSettings.cpp +12 -0
  117. package/Microsoft.ReactNative/ReactInstanceSettings.h +2 -0
  118. package/Microsoft.ReactNative/ReactInstanceSettings.idl +6 -0
  119. package/Microsoft.ReactNative/ReactNativeIsland.idl +3 -0
  120. package/Microsoft.ReactNative/ReactSupport.cpp +44 -11
  121. package/Microsoft.ReactNative/RedBox.cpp +30 -1
  122. package/Microsoft.ReactNative/SchedulerSettings.cpp +4 -4
  123. package/Microsoft.ReactNative/SchedulerSettings.h +1 -1
  124. package/Microsoft.ReactNative/TurboModulesProvider.cpp +30 -12
  125. package/Microsoft.ReactNative/Utils/ImageUtils.h +1 -0
  126. package/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +37 -31
  127. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.cpp +1 -0
  128. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.inc +2 -0
  129. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_posix.cpp +1 -1
  130. package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp +94 -27
  131. package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h +27 -6
  132. package/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.cpp +45 -11
  133. package/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.h +6 -0
  134. package/Microsoft.ReactNative.Cxx/JSI/decorator.h +220 -0
  135. package/Microsoft.ReactNative.Cxx/JSI/instrumentation.h +28 -0
  136. package/Microsoft.ReactNative.Cxx/JSI/jsi-inl.h +6 -0
  137. package/Microsoft.ReactNative.Cxx/JSI/jsi.cpp +241 -4
  138. package/Microsoft.ReactNative.Cxx/JSI/jsi.h +207 -19
  139. package/Microsoft.ReactNative.Cxx/JSValue.cpp +19 -3
  140. package/Microsoft.ReactNative.Cxx/JSValue.h +15 -7
  141. package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +2 -2
  142. package/Microsoft.ReactNative.Cxx/NativeModules.h +60 -2
  143. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.cpp +1267 -614
  144. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.h +4 -2
  145. package/Microsoft.ReactNative.Cxx/ReactContext.h +7 -0
  146. package/Microsoft.ReactNative.Cxx/TurboModuleProvider.cpp +11 -13
  147. package/Microsoft.ReactNative.Cxx/TurboModuleProvider.h +2 -3
  148. package/Microsoft.ReactNative.Cxx/node-api/js_native_api.h +81 -20
  149. package/Microsoft.ReactNative.Cxx/node-api/js_native_api_types.h +47 -2
  150. package/Microsoft.ReactNative.Cxx/node-api/js_runtime_api.h +13 -0
  151. package/Microsoft.ReactNative.Cxx/stubs/glog/logging.h +1 -1
  152. package/Microsoft.ReactNative.Managed/ReactContext.cs +3 -1
  153. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  154. package/PropertySheets/JSEngine.props +1 -1
  155. package/PropertySheets/React.Cpp.props +2 -1
  156. package/PropertySheets/WebView2.props +1 -1
  157. package/PropertySheets/WinUI.props +2 -2
  158. package/ReactCommon/TEMP_UntilReactCommonUpdate/jserrorhandler/JsErrorHandler.cpp +429 -0
  159. package/ReactCommon/cgmanifest.json +1 -1
  160. package/Shared/HermesRuntimeHolder.cpp +6 -0
  161. package/Shared/JSI/ChakraRuntime.cpp +4 -0
  162. package/Shared/JSI/ChakraRuntime.h +2 -0
  163. package/Shared/Modules/BlobModule.cpp +14 -16
  164. package/Shared/Modules/BlobModule.h +3 -1
  165. package/Shared/Shared.vcxitems +11 -7
  166. package/Shared/Shared.vcxitems.filters +6 -1
  167. package/Shared/TurboModuleManager.cpp +0 -15
  168. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +6 -6
  169. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +6 -6
  170. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +6 -6
  171. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +6 -6
  172. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +6 -6
  173. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +6 -6
  174. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +6 -6
  175. package/codegen/react/components/rnwcore/InputAccessory.g.h +6 -6
  176. package/codegen/react/components/rnwcore/ModalHostView.g.h +11 -7
  177. package/codegen/react/components/rnwcore/Props.cpp +2 -1
  178. package/codegen/react/components/rnwcore/Props.h +1 -0
  179. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +6 -6
  180. package/codegen/react/components/rnwcore/SafeAreaView.g.h +6 -6
  181. package/codegen/react/components/rnwcore/Switch.g.h +6 -6
  182. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +6 -6
  183. package/index.windows.js +4 -2
  184. package/package.json +3 -4
  185. package/src/private/specs/components/RCTModalHostViewNativeComponent.js +8 -0
  186. package/stubs/glog/logging.h +1 -1
  187. package/Microsoft.ReactNative/JSDispatcherWriter.h +0 -47
  188. package/Microsoft.ReactNative/SynchronousEventBeat.cpp +0 -51
  189. package/Microsoft.ReactNative/SynchronousEventBeat.h +0 -31
@@ -15,6 +15,7 @@
15
15
  #include <Utils/KeyboardUtils.h>
16
16
  #include <Utils/ValueUtils.h>
17
17
  #include <Views/FrameworkElementTransferProperties.h>
18
+ #include <atlcomcli.h>
18
19
  #include <winrt/Microsoft.ReactNative.Composition.Experimental.h>
19
20
  #include <winrt/Microsoft.UI.Input.h>
20
21
  #include <winrt/Windows.UI.Composition.h>
@@ -33,6 +34,7 @@
33
34
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
34
35
 
35
36
  constexpr float FOCUS_VISUAL_WIDTH = 2.0f;
37
+ constexpr float FOCUS_VISUAL_RADIUS = 3.0f;
36
38
 
37
39
  // m_outerVisual
38
40
  // |
@@ -182,7 +184,7 @@ void ComponentView::updateProps(
182
184
  updateShadowProps(oldViewProps, newViewProps);
183
185
  }
184
186
  if (oldViewProps.tooltip != newViewProps.tooltip) {
185
- if (!m_tooltipTracked && newViewProps.tooltip) {
187
+ if (!m_tooltipTracked && newViewProps.tooltip && !newViewProps.tooltip->empty()) {
186
188
  TooltipService::GetCurrent(m_reactContext.Properties())->StartTracking(*this);
187
189
  m_tooltipTracked = true;
188
190
  } else if (m_tooltipTracked && !newViewProps.tooltip) {
@@ -228,29 +230,11 @@ void ComponentView::updateFocusLayoutMetrics() noexcept {
228
230
  facebook::react::RectangleEdges<bool> nudgeEdges;
229
231
  auto scaleFactor = m_focusPrimitive->m_focusVisualComponent->m_layoutMetrics.pointScaleFactor;
230
232
  if (m_focusPrimitive) {
233
+ auto nudgeEdges = m_focusPrimitive->m_focusVisualComponent->focusNudges();
231
234
  if (m_focusPrimitive->m_focusOuterPrimitive) {
232
235
  auto outerFocusMetrics = m_focusPrimitive->m_focusVisualComponent->focusLayoutMetrics(false /*inner*/);
233
-
234
- if (outerFocusMetrics.frame.origin.x < 0) {
235
- nudgeEdges.left = true;
236
- }
237
- if (outerFocusMetrics.frame.origin.y < 0) {
238
- nudgeEdges.top = true;
239
- }
240
- if (outerFocusMetrics.frame.getMaxX() > m_layoutMetrics.frame.getMaxX()) {
241
- nudgeEdges.right = true;
242
- }
243
- if (outerFocusMetrics.frame.getMaxY() > m_layoutMetrics.frame.getMaxY()) {
244
- nudgeEdges.bottom = true;
245
- }
246
-
247
236
  m_focusPrimitive->m_focusOuterPrimitive->RootVisual().Size(
248
- {outerFocusMetrics.frame.size.width * scaleFactor -
249
- (nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0) -
250
- (nudgeEdges.right ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0),
251
- outerFocusMetrics.frame.size.height * scaleFactor -
252
- (nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0) -
253
- (nudgeEdges.bottom ? (FOCUS_VISUAL_WIDTH * 2 * scaleFactor) : 0)});
237
+ {outerFocusMetrics.frame.size.width * scaleFactor, outerFocusMetrics.frame.size.height * scaleFactor});
254
238
  m_focusPrimitive->m_focusOuterPrimitive->RootVisual().Offset(
255
239
  {nudgeEdges.left ? 0 : -(FOCUS_VISUAL_WIDTH * 2 * scaleFactor),
256
240
  nudgeEdges.top ? 0 : -(FOCUS_VISUAL_WIDTH * 2 * scaleFactor),
@@ -261,15 +245,10 @@ void ComponentView::updateFocusLayoutMetrics() noexcept {
261
245
  if (m_focusPrimitive->m_focusInnerPrimitive) {
262
246
  auto innerFocusMetrics = m_focusPrimitive->m_focusVisualComponent->focusLayoutMetrics(true /*inner*/);
263
247
  m_focusPrimitive->m_focusInnerPrimitive->RootVisual().Size(
264
- {innerFocusMetrics.frame.size.width * scaleFactor -
265
- (nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0) -
266
- (nudgeEdges.right ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0),
267
- innerFocusMetrics.frame.size.height * scaleFactor -
268
- (nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0) -
269
- (nudgeEdges.bottom ? (FOCUS_VISUAL_WIDTH * scaleFactor) : 0)});
248
+ {innerFocusMetrics.frame.size.width * scaleFactor, innerFocusMetrics.frame.size.height * scaleFactor});
270
249
  m_focusPrimitive->m_focusInnerPrimitive->RootVisual().Offset(
271
- {nudgeEdges.left ? 0 : -FOCUS_VISUAL_WIDTH * scaleFactor,
272
- nudgeEdges.top ? 0 : -FOCUS_VISUAL_WIDTH * scaleFactor,
250
+ {nudgeEdges.left ? (FOCUS_VISUAL_WIDTH * scaleFactor) : (-FOCUS_VISUAL_WIDTH * scaleFactor),
251
+ nudgeEdges.top ? (FOCUS_VISUAL_WIDTH * scaleFactor) : (-FOCUS_VISUAL_WIDTH * scaleFactor),
273
252
  0.0f});
274
253
  m_focusPrimitive->m_focusInnerPrimitive->markNeedsUpdate();
275
254
  }
@@ -353,9 +332,9 @@ void ComponentView::onLostFocus(
353
332
 
354
333
  m_componentHostingFocusVisual->hostFocusVisual(false, get_strong());
355
334
  }
356
- if (m_uiaProvider) {
335
+ if (UiaClientsAreListening()) {
357
336
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
358
- m_uiaProvider, UIA_HasKeyboardFocusPropertyId, true, false);
337
+ EnsureUiaProvider(), UIA_HasKeyboardFocusPropertyId, true, false);
359
338
  }
360
339
  }
361
340
  base_type::onLostFocus(args);
@@ -403,8 +382,8 @@ void ComponentView::onGotFocus(
403
382
  focusRect.size.height += (FOCUS_VISUAL_WIDTH * 2);
404
383
  focusVisualRoot(focusRect)->hostFocusVisual(true, get_strong());
405
384
  }
406
- if (m_uiaProvider) {
407
- auto spProviderSimple = m_uiaProvider.try_as<IRawElementProviderSimple>();
385
+ if (UiaClientsAreListening()) {
386
+ auto spProviderSimple = EnsureUiaProvider().try_as<IRawElementProviderSimple>();
408
387
  if (spProviderSimple != nullptr) {
409
388
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
410
389
  m_uiaProvider, UIA_HasKeyboardFocusPropertyId, false, true);
@@ -538,7 +517,33 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ComponentView:
538
517
  return m_outerVisual ? m_outerVisual : Visual();
539
518
  }
540
519
 
541
- facebook::react::LayoutMetrics ComponentView::focusLayoutMetrics(bool inner) const noexcept {
520
+ // If the focus visual would extend past the bounds of the hosting visual,
521
+ // then we will nudge the focus visual back inside the hosting visuals bounds.
522
+ facebook::react::RectangleEdges<bool> ComponentView::focusNudges() const noexcept {
523
+ facebook::react::RectangleEdges<bool> nudgeEdges;
524
+
525
+ // Always use outer focus metrics to determine if we need to nudge the focus rect over to fit
526
+ facebook::react::LayoutMetrics layoutMetrics = focusLayoutMetricsNoNudge(false /*inner*/);
527
+
528
+ Assert(m_componentHostingFocusVisual);
529
+
530
+ if (layoutMetrics.frame.origin.x < 0) {
531
+ nudgeEdges.left = true;
532
+ }
533
+ if (layoutMetrics.frame.origin.y < 0) {
534
+ nudgeEdges.top = true;
535
+ }
536
+ if (layoutMetrics.frame.getMaxX() > m_componentHostingFocusVisual->m_layoutMetrics.frame.getMaxX()) {
537
+ nudgeEdges.right = true;
538
+ }
539
+ if (layoutMetrics.frame.getMaxY() > m_componentHostingFocusVisual->m_layoutMetrics.frame.getMaxY()) {
540
+ nudgeEdges.bottom = true;
541
+ }
542
+
543
+ return nudgeEdges;
544
+ }
545
+
546
+ facebook::react::LayoutMetrics ComponentView::focusLayoutMetricsNoNudge(bool inner) const noexcept {
542
547
  facebook::react::LayoutMetrics layoutMetrics = m_layoutMetrics;
543
548
  layoutMetrics.frame.origin.x -= FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
544
549
  layoutMetrics.frame.origin.y -= FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
@@ -547,6 +552,28 @@ facebook::react::LayoutMetrics ComponentView::focusLayoutMetrics(bool inner) con
547
552
  return layoutMetrics;
548
553
  }
549
554
 
555
+ facebook::react::LayoutMetrics ComponentView::focusLayoutMetrics(bool inner) const noexcept {
556
+ auto nudgeEdges = focusNudges();
557
+ auto layoutMetrics = focusLayoutMetricsNoNudge(inner);
558
+
559
+ if (nudgeEdges.left) {
560
+ layoutMetrics.frame.origin.x += FOCUS_VISUAL_WIDTH * 2;
561
+ layoutMetrics.frame.size.width -= FOCUS_VISUAL_WIDTH * 2;
562
+ }
563
+ if (nudgeEdges.top) {
564
+ layoutMetrics.frame.origin.y += FOCUS_VISUAL_WIDTH * 2;
565
+ layoutMetrics.frame.size.height -= FOCUS_VISUAL_WIDTH * 2;
566
+ }
567
+ if (nudgeEdges.right) {
568
+ layoutMetrics.frame.size.width -= FOCUS_VISUAL_WIDTH * 2;
569
+ }
570
+ if (nudgeEdges.bottom) {
571
+ layoutMetrics.frame.size.height -= FOCUS_VISUAL_WIDTH * 2;
572
+ }
573
+
574
+ return layoutMetrics;
575
+ }
576
+
550
577
  facebook::react::BorderMetrics ComponentView::focusBorderMetrics(
551
578
  bool inner,
552
579
  const facebook::react::LayoutMetrics &layoutMetrics) const noexcept {
@@ -556,22 +583,31 @@ facebook::react::BorderMetrics ComponentView::focusBorderMetrics(
556
583
  innerColor.m_platformColor.push_back(inner ? "FocusVisualSecondary" : "FocusVisualPrimary");
557
584
  metrics.borderColors.bottom = metrics.borderColors.left = metrics.borderColors.right = metrics.borderColors.top =
558
585
  innerColor;
559
- if (metrics.borderRadii.bottomLeft.horizontal != 0)
560
- metrics.borderRadii.bottomLeft.horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
561
- if (metrics.borderRadii.bottomLeft.vertical != 0)
562
- metrics.borderRadii.bottomLeft.vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
563
- if (metrics.borderRadii.bottomRight.horizontal != 0)
564
- metrics.borderRadii.bottomRight.horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
565
- if (metrics.borderRadii.bottomRight.vertical != 0)
566
- metrics.borderRadii.bottomRight.vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
567
- if (metrics.borderRadii.topLeft.horizontal != 0)
568
- metrics.borderRadii.topLeft.horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
569
- if (metrics.borderRadii.topLeft.vertical != 0)
570
- metrics.borderRadii.topLeft.vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
571
- if (metrics.borderRadii.topRight.horizontal != 0)
572
- metrics.borderRadii.topRight.horizontal += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
573
- if (metrics.borderRadii.topRight.vertical != 0)
574
- metrics.borderRadii.topRight.vertical += FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
586
+
587
+ metrics.borderRadii.bottomLeft.horizontal =
588
+ (metrics.borderRadii.bottomLeft.horizontal ? metrics.borderRadii.bottomLeft.horizontal : FOCUS_VISUAL_RADIUS) +
589
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
590
+ metrics.borderRadii.bottomLeft.vertical =
591
+ (metrics.borderRadii.bottomLeft.vertical ? metrics.borderRadii.bottomLeft.vertical : FOCUS_VISUAL_RADIUS) +
592
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
593
+ metrics.borderRadii.bottomRight.horizontal =
594
+ (metrics.borderRadii.bottomRight.horizontal ? metrics.borderRadii.bottomRight.horizontal : FOCUS_VISUAL_RADIUS) +
595
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
596
+ metrics.borderRadii.bottomRight.vertical =
597
+ (metrics.borderRadii.bottomRight.vertical ? metrics.borderRadii.bottomRight.vertical : FOCUS_VISUAL_RADIUS) +
598
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
599
+ metrics.borderRadii.topLeft.horizontal =
600
+ (metrics.borderRadii.topLeft.horizontal ? metrics.borderRadii.topLeft.horizontal : FOCUS_VISUAL_RADIUS) +
601
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
602
+ metrics.borderRadii.topLeft.vertical =
603
+ (metrics.borderRadii.topLeft.vertical ? metrics.borderRadii.topLeft.vertical : FOCUS_VISUAL_RADIUS) +
604
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
605
+ metrics.borderRadii.topRight.horizontal =
606
+ (metrics.borderRadii.topRight.horizontal ? metrics.borderRadii.topRight.horizontal : FOCUS_VISUAL_RADIUS) +
607
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
608
+ metrics.borderRadii.topRight.vertical =
609
+ (metrics.borderRadii.topRight.vertical ? metrics.borderRadii.topRight.vertical : FOCUS_VISUAL_RADIUS) +
610
+ FOCUS_VISUAL_WIDTH * (inner ? 1 : 2);
575
611
 
576
612
  metrics.borderStyles.bottom = metrics.borderStyles.left = metrics.borderStyles.right = metrics.borderStyles.top =
577
613
  facebook::react::BorderStyle::Solid;
@@ -708,67 +744,86 @@ void ComponentView::updateTransformProps(
708
744
  void ComponentView::updateAccessibilityProps(
709
745
  const facebook::react::ViewProps &oldViewProps,
710
746
  const facebook::react::ViewProps &newViewProps) noexcept {
711
- if (!m_uiaProvider)
747
+ if (!UiaClientsAreListening())
712
748
  return;
713
749
 
714
750
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
715
- m_uiaProvider, UIA_IsKeyboardFocusablePropertyId, oldViewProps.focusable, newViewProps.focusable);
751
+ EnsureUiaProvider(), UIA_IsKeyboardFocusablePropertyId, oldViewProps.focusable, newViewProps.focusable);
716
752
 
717
753
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
718
- m_uiaProvider,
754
+ EnsureUiaProvider(),
719
755
  UIA_NamePropertyId,
720
756
  oldViewProps.accessibilityLabel,
721
757
  newViewProps.accessibilityLabel.empty() ? DefaultAccessibleName() : newViewProps.accessibilityLabel);
722
758
 
723
759
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
724
- m_uiaProvider,
760
+ EnsureUiaProvider(),
725
761
  UIA_IsContentElementPropertyId,
726
762
  (oldViewProps.accessible && oldViewProps.accessibilityRole != "none"),
727
763
  (newViewProps.accessible && newViewProps.accessibilityRole != "none"));
728
764
 
729
765
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
730
- m_uiaProvider,
766
+ EnsureUiaProvider(),
731
767
  UIA_IsControlElementPropertyId,
732
768
  (oldViewProps.accessible && oldViewProps.accessibilityRole != "none"),
733
769
  (newViewProps.accessible && newViewProps.accessibilityRole != "none"));
734
770
 
735
771
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
736
- m_uiaProvider,
772
+ EnsureUiaProvider(),
737
773
  UIA_IsEnabledPropertyId,
738
774
  !(oldViewProps.accessibilityState && oldViewProps.accessibilityState->disabled),
739
775
  !(newViewProps.accessibilityState && newViewProps.accessibilityState->disabled));
740
776
 
741
777
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
742
- m_uiaProvider,
778
+ EnsureUiaProvider(),
743
779
  UIA_IsEnabledPropertyId,
744
780
  !(oldViewProps.accessibilityState && oldViewProps.accessibilityState->busy),
745
781
  !(newViewProps.accessibilityState && newViewProps.accessibilityState->busy));
746
782
 
747
783
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
748
- m_uiaProvider, UIA_ControlTypePropertyId, oldViewProps.accessibilityRole, newViewProps.accessibilityRole);
784
+ EnsureUiaProvider(), UIA_ControlTypePropertyId, oldViewProps.accessibilityRole, newViewProps.accessibilityRole);
749
785
 
750
786
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
751
- m_uiaProvider, UIA_HelpTextPropertyId, oldViewProps.accessibilityHint, newViewProps.accessibilityHint);
787
+ EnsureUiaProvider(), UIA_HelpTextPropertyId, oldViewProps.accessibilityHint, newViewProps.accessibilityHint);
752
788
 
753
789
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
754
- m_uiaProvider,
790
+ EnsureUiaProvider(),
755
791
  UIA_PositionInSetPropertyId,
756
792
  oldViewProps.accessibilityPosInSet,
757
793
  newViewProps.accessibilityPosInSet);
758
794
 
759
795
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
760
- m_uiaProvider, UIA_SizeOfSetPropertyId, oldViewProps.accessibilitySetSize, newViewProps.accessibilitySetSize);
796
+ EnsureUiaProvider(),
797
+ UIA_SizeOfSetPropertyId,
798
+ oldViewProps.accessibilitySetSize,
799
+ newViewProps.accessibilitySetSize);
761
800
 
762
801
  winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
763
- m_uiaProvider,
802
+ EnsureUiaProvider(),
764
803
  UIA_LiveSettingPropertyId,
765
804
  oldViewProps.accessibilityLiveRegion,
766
805
  newViewProps.accessibilityLiveRegion);
767
806
 
807
+ winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
808
+ EnsureUiaProvider(), UIA_LevelPropertyId, oldViewProps.accessibilityLevel, newViewProps.accessibilityLevel);
809
+
810
+ winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
811
+ EnsureUiaProvider(),
812
+ UIA_AccessKeyPropertyId,
813
+ oldViewProps.accessibilityAccessKey,
814
+ newViewProps.accessibilityAccessKey);
815
+
816
+ winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
817
+ EnsureUiaProvider(),
818
+ UIA_ItemTypePropertyId,
819
+ oldViewProps.accessibilityItemType,
820
+ newViewProps.accessibilityItemType);
821
+
768
822
  if ((oldViewProps.accessibilityState.has_value() && oldViewProps.accessibilityState->selected.has_value()) !=
769
823
  ((newViewProps.accessibilityState.has_value() && newViewProps.accessibilityState->selected.has_value()))) {
770
824
  auto compProvider =
771
- m_uiaProvider.try_as<winrt::Microsoft::ReactNative::implementation::CompositionDynamicAutomationProvider>();
825
+ EnsureUiaProvider()
826
+ .try_as<winrt::Microsoft::ReactNative::implementation::CompositionDynamicAutomationProvider>();
772
827
  if (compProvider) {
773
828
  if ((newViewProps.accessibilityState.has_value() && newViewProps.accessibilityState->selected.has_value())) {
774
829
  winrt::Microsoft::ReactNative::implementation::AddSelectionItemsToContainer(compProvider.get());
@@ -143,6 +143,8 @@ struct ComponentView : public ComponentViewT<
143
143
  void FinalizeTransform(
144
144
  facebook::react::LayoutMetrics const &layoutMetrics,
145
145
  const facebook::react::ViewProps &viewProps) noexcept;
146
+ facebook::react::RectangleEdges<bool> focusNudges() const noexcept;
147
+ facebook::react::LayoutMetrics focusLayoutMetricsNoNudge(bool inner) const noexcept;
146
148
  facebook::react::LayoutMetrics focusLayoutMetrics(bool inner) const noexcept;
147
149
  facebook::react::BorderMetrics focusBorderMetrics(bool inner, const facebook::react::LayoutMetrics &layoutMetrics)
148
150
  const noexcept;
@@ -11,12 +11,15 @@
11
11
  #include <UI.Xaml.Controls.h>
12
12
  #include <Utils/ValueUtils.h>
13
13
  #include <winrt/Microsoft.UI.Content.h>
14
+ #include <winrt/Microsoft.UI.Input.h>
14
15
  #include <winrt/Windows.UI.Composition.h>
15
16
  #include "CompositionContextHelper.h"
16
17
  #include "RootComponentView.h"
17
18
 
18
19
  #include "Composition.ContentIslandComponentView.g.cpp"
19
20
 
21
+ #include "CompositionDynamicAutomationProvider.h"
22
+
20
23
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
21
24
 
22
25
  ContentIslandComponentView::ContentIslandComponentView(
@@ -41,12 +44,27 @@ ContentIslandComponentView::ContentIslandComponentView(
41
44
  }
42
45
 
43
46
  void ContentIslandComponentView::OnMounted() noexcept {
44
- #ifdef USE_EXPERIMENTAL_WINUI3
45
47
  m_childSiteLink = winrt::Microsoft::UI::Content::ChildSiteLink::Create(
46
48
  rootComponentView()->parentContentIsland(),
47
49
  winrt::Microsoft::ReactNative::Composition::Experimental::CompositionContextHelper::InnerVisual(Visual())
48
50
  .as<winrt::Microsoft::UI::Composition::ContainerVisual>());
49
51
  m_childSiteLink.ActualSize({m_layoutMetrics.frame.size.width, m_layoutMetrics.frame.size.height});
52
+
53
+ m_navigationHost = winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteLink(m_childSiteLink);
54
+
55
+ m_navigationHostDepartFocusRequestedToken =
56
+ m_navigationHost.DepartFocusRequested([wkThis = get_weak()](const auto &, const auto &args) {
57
+ if (auto strongThis = wkThis.get()) {
58
+ const bool next = (args.Request().Reason() != winrt::Microsoft::UI::Input::FocusNavigationReason::Last);
59
+ strongThis->rootComponentView()->TryMoveFocus(next);
60
+ args.Result(winrt::Microsoft::UI::Input::FocusNavigationResult::Moved);
61
+ }
62
+ });
63
+
64
+ // We configure automation even if there's no UIA client at this point, because it's possible the first UIA
65
+ // request we'll get will be for a child of this island calling upward in the UIA tree.
66
+ ConfigureChildSiteLinkAutomation();
67
+
50
68
  if (m_islandToConnect) {
51
69
  m_childSiteLink.Connect(m_islandToConnect);
52
70
  m_islandToConnect = nullptr;
@@ -65,15 +83,17 @@ void ContentIslandComponentView::OnMounted() noexcept {
65
83
  }));
66
84
  view = view.Parent();
67
85
  }
68
- #endif
69
86
  }
70
87
 
71
88
  void ContentIslandComponentView::OnUnmounted() noexcept {
72
89
  m_layoutMetricChangedRevokers.clear();
90
+ if (m_navigationHostDepartFocusRequestedToken && m_navigationHost) {
91
+ m_navigationHost.DepartFocusRequested(m_navigationHostDepartFocusRequestedToken);
92
+ m_navigationHostDepartFocusRequestedToken = {};
93
+ }
73
94
  }
74
95
 
75
96
  void ContentIslandComponentView::ParentLayoutChanged() noexcept {
76
- #ifdef USE_EXPERIMENTAL_WINUI3
77
97
  if (m_layoutChangePosted)
78
98
  return;
79
99
 
@@ -89,10 +109,67 @@ void ContentIslandComponentView::ParentLayoutChanged() noexcept {
89
109
  strongThis->m_layoutChangePosted = false;
90
110
  }
91
111
  });
92
- #endif
112
+ }
113
+
114
+ winrt::IInspectable ContentIslandComponentView::EnsureUiaProvider() noexcept {
115
+ if (m_uiaProvider == nullptr) {
116
+ m_uiaProvider = winrt::make<winrt::Microsoft::ReactNative::implementation::CompositionDynamicAutomationProvider>(
117
+ *get_strong(), m_childSiteLink);
118
+ }
119
+ return m_uiaProvider;
120
+ }
121
+
122
+ bool ContentIslandComponentView::focusable() const noexcept {
123
+ // We don't have a way to check to see if the ContentIsland has focusable content,
124
+ // so we'll always return true. We'll have to handle the case where the content doesn't have
125
+ // focusable content in the OnGotFocus handler.
126
+ return true;
127
+ }
128
+
129
+ // Helper to convert a FocusNavigationDirection to a FocusNavigationReason.
130
+ winrt::Microsoft::UI::Input::FocusNavigationReason GetFocusNavigationReason(
131
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction) noexcept {
132
+ switch (direction) {
133
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::First:
134
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::Next:
135
+ return winrt::Microsoft::UI::Input::FocusNavigationReason::First;
136
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::Last:
137
+ case winrt::Microsoft::ReactNative::FocusNavigationDirection::Previous:
138
+ return winrt::Microsoft::UI::Input::FocusNavigationReason::Last;
139
+ }
140
+ return winrt::Microsoft::UI::Input::FocusNavigationReason::Restore;
141
+ }
142
+
143
+ void ContentIslandComponentView::onGotFocus(
144
+ const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept {
145
+ auto gotFocusEventArgs = args.as<winrt::Microsoft::ReactNative::implementation::GotFocusEventArgs>();
146
+ const auto navigationReason = GetFocusNavigationReason(gotFocusEventArgs->Direction());
147
+ m_navigationHost.NavigateFocus(winrt::Microsoft::UI::Input::FocusNavigationRequest::Create(navigationReason));
93
148
  }
94
149
 
95
150
  ContentIslandComponentView::~ContentIslandComponentView() noexcept {
151
+ if (m_navigationHostDepartFocusRequestedToken && m_navigationHost) {
152
+ m_navigationHost.DepartFocusRequested(m_navigationHostDepartFocusRequestedToken);
153
+ m_navigationHostDepartFocusRequestedToken = {};
154
+ }
155
+ if (m_childSiteLink) {
156
+ if (m_fragmentRootAutomationProviderRequestedToken) {
157
+ m_childSiteLink.FragmentRootAutomationProviderRequested(m_fragmentRootAutomationProviderRequestedToken);
158
+ m_fragmentRootAutomationProviderRequestedToken = {};
159
+ }
160
+ if (m_parentAutomationProviderRequestedToken) {
161
+ m_childSiteLink.ParentAutomationProviderRequested(m_parentAutomationProviderRequestedToken);
162
+ m_parentAutomationProviderRequestedToken = {};
163
+ }
164
+ if (m_nextSiblingAutomationProviderRequestedToken) {
165
+ m_childSiteLink.NextSiblingAutomationProviderRequested(m_nextSiblingAutomationProviderRequestedToken);
166
+ m_nextSiblingAutomationProviderRequestedToken = {};
167
+ }
168
+ if (m_previousSiblingAutomationProviderRequestedToken) {
169
+ m_childSiteLink.PreviousSiblingAutomationProviderRequested(m_previousSiblingAutomationProviderRequestedToken);
170
+ m_previousSiblingAutomationProviderRequestedToken = {};
171
+ }
172
+ }
96
173
  if (m_islandToConnect) {
97
174
  m_islandToConnect.Close();
98
175
  }
@@ -115,28 +192,76 @@ void ContentIslandComponentView::UnmountChildComponentView(
115
192
  void ContentIslandComponentView::updateLayoutMetrics(
116
193
  facebook::react::LayoutMetrics const &layoutMetrics,
117
194
  facebook::react::LayoutMetrics const &oldLayoutMetrics) noexcept {
118
- #ifdef USE_EXPERIMENTAL_WINUI3
119
195
  if (m_childSiteLink) {
120
196
  m_childSiteLink.ActualSize({layoutMetrics.frame.size.width, layoutMetrics.frame.size.height});
121
197
  ParentLayoutChanged();
122
198
  }
123
- #endif
124
199
  base_type::updateLayoutMetrics(layoutMetrics, oldLayoutMetrics);
125
200
  }
126
201
 
127
202
  void ContentIslandComponentView::Connect(const winrt::Microsoft::UI::Content::ContentIsland &contentIsland) noexcept {
128
- #ifdef USE_EXPERIMENTAL_WINUI3
129
203
  if (m_childSiteLink) {
130
204
  m_islandToConnect = nullptr;
131
205
  m_childSiteLink.Connect(contentIsland);
132
206
  } else {
133
207
  m_islandToConnect = contentIsland;
134
208
  }
135
- #endif
136
209
  }
137
210
 
138
211
  void ContentIslandComponentView::prepareForRecycle() noexcept {
139
212
  Super::prepareForRecycle();
140
213
  }
141
214
 
215
+ void ContentIslandComponentView::ConfigureChildSiteLinkAutomation() noexcept {
216
+ // This automation mode must be set before connecting the child ContentIsland.
217
+ // It puts the child content into a mode where it won't own its own framework root. Instead, the child island's
218
+ // automation peers will use the same framework root as the automation peer of this ContentIslandComponentView.
219
+ m_childSiteLink.AutomationOption(winrt::Microsoft::UI::Content::ContentAutomationOptions::FragmentBased);
220
+
221
+ // These events are raised in response to the child ContentIsland asking for providers.
222
+ // For example, the ContentIsland.FragmentRootAutomationProvider property will return
223
+ // the provider we provide here in FragmentRootAutomationProviderRequested.
224
+
225
+ // We capture "this" as a raw pointer because ContentIslandComponentView doesn't currently support weak ptrs.
226
+ // It's safe because we disconnect these events in the destructor.
227
+
228
+ m_fragmentRootAutomationProviderRequestedToken = m_childSiteLink.FragmentRootAutomationProviderRequested(
229
+ [this](
230
+ const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
231
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
232
+ // The child island's fragment tree doesn't have its own fragment root.
233
+ // Here's how we can provide the correct fragment root to the child's UIA logic.
234
+ winrt::com_ptr<IRawElementProviderFragmentRoot> fragmentRoot{nullptr};
235
+ auto uiaProvider = this->EnsureUiaProvider();
236
+ uiaProvider.as<IRawElementProviderFragment>()->get_FragmentRoot(fragmentRoot.put());
237
+ args.AutomationProvider(fragmentRoot.as<IInspectable>());
238
+ args.Handled(true);
239
+ });
240
+
241
+ m_parentAutomationProviderRequestedToken = m_childSiteLink.ParentAutomationProviderRequested(
242
+ [this](
243
+ const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
244
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
245
+ auto uiaProvider = this->EnsureUiaProvider();
246
+ args.AutomationProvider(uiaProvider);
247
+ args.Handled(true);
248
+ });
249
+
250
+ m_nextSiblingAutomationProviderRequestedToken = m_childSiteLink.NextSiblingAutomationProviderRequested(
251
+ [](const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
252
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
253
+ // The ContentIsland will always be the one and only child of this node, so it won't have siblings.
254
+ args.AutomationProvider(nullptr);
255
+ args.Handled(true);
256
+ });
257
+
258
+ m_previousSiblingAutomationProviderRequestedToken = m_childSiteLink.PreviousSiblingAutomationProviderRequested(
259
+ [](const winrt::Microsoft::UI::Content::IContentSiteAutomation &,
260
+ const winrt::Microsoft::UI::Content::ContentSiteAutomationProviderRequestedEventArgs &args) {
261
+ // The ContentIsland will always be the one and only child of this node, so it won't have siblings.
262
+ args.AutomationProvider(nullptr);
263
+ args.Handled(true);
264
+ });
265
+ }
266
+
142
267
  } // namespace winrt::Microsoft::ReactNative::Composition::implementation
@@ -8,6 +8,7 @@
8
8
 
9
9
  #include <Microsoft.ReactNative.Cxx/ReactContext.h>
10
10
  #include <winrt/Microsoft.UI.Content.h>
11
+ #include <winrt/Microsoft.UI.Input.h>
11
12
  #include <winrt/Windows.UI.Composition.h>
12
13
  #include "CompositionHelpers.h"
13
14
  #include "CompositionViewComponentView.h"
@@ -37,6 +38,12 @@ struct ContentIslandComponentView : ContentIslandComponentViewT<ContentIslandCom
37
38
 
38
39
  void prepareForRecycle() noexcept override;
39
40
 
41
+ bool focusable() const noexcept override;
42
+
43
+ winrt::IInspectable EnsureUiaProvider() noexcept override;
44
+
45
+ void onGotFocus(const winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs &args) noexcept override;
46
+
40
47
  ContentIslandComponentView(
41
48
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
42
49
  facebook::react::Tag tag,
@@ -54,9 +61,16 @@ struct ContentIslandComponentView : ContentIslandComponentViewT<ContentIslandCom
54
61
  winrt::event_token m_mountedToken;
55
62
  winrt::event_token m_unmountedToken;
56
63
  std::vector<winrt::Microsoft::ReactNative::ComponentView::LayoutMetricsChanged_revoker> m_layoutMetricChangedRevokers;
57
- #ifdef USE_EXPERIMENTAL_WINUI3
58
64
  winrt::Microsoft::UI::Content::ChildSiteLink m_childSiteLink{nullptr};
59
- #endif
65
+ winrt::Microsoft::UI::Input::InputFocusNavigationHost m_navigationHost{nullptr};
66
+ winrt::event_token m_navigationHostDepartFocusRequestedToken{};
67
+
68
+ // Automation
69
+ void ConfigureChildSiteLinkAutomation() noexcept;
70
+ winrt::event_token m_fragmentRootAutomationProviderRequestedToken{};
71
+ winrt::event_token m_parentAutomationProviderRequestedToken{};
72
+ winrt::event_token m_nextSiblingAutomationProviderRequestedToken{};
73
+ winrt::event_token m_previousSiblingAutomationProviderRequestedToken{};
60
74
  };
61
75
 
62
76
  } // namespace winrt::Microsoft::ReactNative::Composition::implementation
@@ -14,8 +14,10 @@ int32_t LostFocusEventArgs::OriginalSource() noexcept {
14
14
  return m_originalSource;
15
15
  }
16
16
 
17
- GotFocusEventArgs::GotFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource)
18
- : m_originalSource(originalSource ? originalSource.Tag() : -1) {}
17
+ GotFocusEventArgs::GotFocusEventArgs(
18
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
19
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction)
20
+ : m_originalSource(originalSource ? originalSource.Tag() : -1), m_direction(direction) {}
19
21
  int32_t GotFocusEventArgs::OriginalSource() noexcept {
20
22
  return m_originalSource;
21
23
  }
@@ -21,11 +21,19 @@ struct LostFocusEventArgs
21
21
 
22
22
  struct GotFocusEventArgs
23
23
  : winrt::implements<GotFocusEventArgs, winrt::Microsoft::ReactNative::Composition::Input::RoutedEventArgs> {
24
- GotFocusEventArgs(const winrt::Microsoft::ReactNative::ComponentView &originalSource);
24
+ GotFocusEventArgs(
25
+ const winrt::Microsoft::ReactNative::ComponentView &originalSource,
26
+ winrt::Microsoft::ReactNative::FocusNavigationDirection direction);
25
27
  int32_t OriginalSource() noexcept;
26
28
 
29
+ winrt::Microsoft::ReactNative::FocusNavigationDirection Direction() const noexcept {
30
+ return m_direction;
31
+ }
32
+
27
33
  private:
28
34
  const int32_t m_originalSource;
35
+ winrt::Microsoft::ReactNative::FocusNavigationDirection m_direction{
36
+ winrt::Microsoft::ReactNative::FocusNavigationDirection::None};
29
37
  };
30
38
 
31
39
  struct LosingFocusEventArgs