react-native-windows 0.80.0-preview.1 → 0.80.0-preview.10

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 (39) hide show
  1. package/Directory.Build.props +6 -0
  2. package/Folly/TEMP_UntilFollyUpdate/json/json.cpp +1 -1
  3. package/Microsoft.ReactNative/CompositionSwitcher.idl +3 -8
  4. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +73 -27
  5. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +21 -156
  6. package/Microsoft.ReactNative/Fabric/Composition/CompositionTextRangeProvider.cpp +30 -9
  7. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +24 -0
  8. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +22 -0
  9. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +3 -0
  10. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +30 -65
  11. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +4 -6
  12. package/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp +11 -0
  13. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.cpp +37 -5
  14. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +33 -15
  15. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +225 -0
  16. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +23 -0
  17. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +5 -3
  18. package/Microsoft.ReactNative/Fabric/ImageManager.cpp +1 -1
  19. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorUtils.cpp +64 -0
  20. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorUtils.h +11 -0
  21. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.cpp +2 -2
  22. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/WindowsTextLayoutManager.h +1 -1
  23. package/Microsoft.ReactNative/Modules/AccessibilityInfoModule.cpp +29 -0
  24. package/Microsoft.ReactNative/Utils/ThemeUtils.cpp +49 -0
  25. package/Microsoft.ReactNative/Utils/ThemeUtils.h +31 -0
  26. package/Microsoft.ReactNative.Managed.CodeGen/Microsoft.ReactNative.Managed.CodeGen.csproj +1 -1
  27. package/Microsoft.ReactNative.Managed.CodeGen/Properties/PublishProfiles/DeployAsTool-Debug.pubxml +1 -1
  28. package/Microsoft.ReactNative.Managed.CodeGen/Properties/PublishProfiles/DeployAsTool-Release.pubxml +1 -1
  29. package/PropertySheets/Generated/PackageVersion.g.props +2 -2
  30. package/PropertySheets/JSEngine.props +1 -1
  31. package/PropertySheets/Warnings.props +45 -0
  32. package/README.md +4 -0
  33. package/ReactCommon/TEMP_UntilReactCommonUpdate/react/renderer/componentregistry/ComponentDescriptorRegistry.cpp +1 -1
  34. package/Scripts/rnw-dependencies.ps1 +18 -5
  35. package/package.json +2 -2
  36. package/templates/cpp-app/template.config.js +2 -1
  37. package/templates/cpp-lib/example/metro.config.js +1 -1
  38. package/templates/old/generateWrapper.js +1 -1
  39. package/templates/old/uwp-cpp-app/template.config.js +1 -1
@@ -27,7 +27,6 @@
27
27
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
28
28
 
29
29
  constexpr float c_scrollerLineDelta = 16.0f;
30
- constexpr auto c_maxSnapPoints = 1000;
31
30
 
32
31
  enum class ScrollbarHitRegion : int {
33
32
  Unknown = -1,
@@ -741,15 +740,6 @@ void ScrollViewComponentView::updateBackgroundColor(const facebook::react::Share
741
740
  }
742
741
  }
743
742
 
744
- winrt::Windows::Foundation::Collections::IVector<float> ScrollViewComponentView::CreateSnapToOffsets(
745
- const std::vector<float> &offsets) {
746
- auto snapToOffsets = winrt::single_threaded_vector<float>();
747
- for (const auto &offset : offsets) {
748
- snapToOffsets.Append(offset);
749
- }
750
- return snapToOffsets;
751
- }
752
-
753
743
  void ScrollViewComponentView::updateProps(
754
744
  facebook::react::Props::Shared const &props,
755
745
  facebook::react::Props::Shared const &oldProps) noexcept {
@@ -818,13 +808,11 @@ void ScrollViewComponentView::updateProps(
818
808
 
819
809
  if (oldViewProps.snapToStart != newViewProps.snapToStart || oldViewProps.snapToEnd != newViewProps.snapToEnd ||
820
810
  oldViewProps.snapToOffsets != newViewProps.snapToOffsets) {
821
- if (oldViewProps.snapToInterval != newViewProps.snapToInterval) {
822
- updateSnapPoints();
823
- } else {
824
- const auto snapToOffsets = CreateSnapToOffsets(newViewProps.snapToOffsets);
825
- m_scrollVisual.SetSnapPoints(
826
- newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView(), SnapAlignment::Center);
811
+ const auto snapToOffsets = winrt::single_threaded_vector<float>();
812
+ for (const auto &offset : newViewProps.snapToOffsets) {
813
+ snapToOffsets.Append(static_cast<float>(offset));
827
814
  }
815
+ m_scrollVisual.SetSnapPoints(newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView());
828
816
  }
829
817
  }
830
818
 
@@ -875,9 +863,6 @@ void ScrollViewComponentView::updateContentVisualSize() noexcept {
875
863
  m_verticalScrollbarComponent->ContentSize(contentSize);
876
864
  m_horizontalScrollbarComponent->ContentSize(contentSize);
877
865
  m_scrollVisual.ContentSize(contentSize);
878
-
879
- // Update snap points if snapToInterval is being used, as content size affects the number of snap points
880
- updateSnapPoints();
881
866
  }
882
867
 
883
868
  void ScrollViewComponentView::prepareForRecycle() noexcept {}
@@ -1354,6 +1339,32 @@ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ScrollViewComp
1354
1339
  }
1355
1340
  });
1356
1341
 
1342
+ m_scrollMomentumBeginRevoker = m_scrollVisual.ScrollMomentumBegin(
1343
+ winrt::auto_revoke,
1344
+ [this](
1345
+ winrt::IInspectable const & /*sender*/,
1346
+ winrt::Microsoft::ReactNative::Composition::Experimental::IScrollPositionChangedArgs const &args) {
1347
+ auto eventEmitter = GetEventEmitter();
1348
+ if (eventEmitter) {
1349
+ auto scrollMetrics = getScrollMetrics(eventEmitter, args);
1350
+ std::static_pointer_cast<facebook::react::ScrollViewEventEmitter const>(eventEmitter)
1351
+ ->onMomentumScrollBegin(scrollMetrics);
1352
+ }
1353
+ });
1354
+
1355
+ m_scrollMomentumEndRevoker = m_scrollVisual.ScrollMomentumEnd(
1356
+ winrt::auto_revoke,
1357
+ [this](
1358
+ winrt::IInspectable const & /*sender*/,
1359
+ winrt::Microsoft::ReactNative::Composition::Experimental::IScrollPositionChangedArgs const &args) {
1360
+ auto eventEmitter = GetEventEmitter();
1361
+ if (eventEmitter) {
1362
+ auto scrollMetrics = getScrollMetrics(eventEmitter, args);
1363
+ std::static_pointer_cast<facebook::react::ScrollViewEventEmitter const>(eventEmitter)
1364
+ ->onMomentumScrollEnd(scrollMetrics);
1365
+ }
1366
+ });
1367
+
1357
1368
  return visual;
1358
1369
  }
1359
1370
 
@@ -1450,50 +1461,4 @@ void ScrollViewComponentView::updateShowsVerticalScrollIndicator(bool value) noe
1450
1461
  void ScrollViewComponentView::updateDecelerationRate(float value) noexcept {
1451
1462
  m_scrollVisual.SetDecelerationRate({value, value, value});
1452
1463
  }
1453
-
1454
- SnapAlignment ScrollViewComponentView::convertSnapToAlignment(
1455
- facebook::react::ScrollViewSnapToAlignment alignment) noexcept {
1456
- switch (alignment) {
1457
- case facebook::react::ScrollViewSnapToAlignment::Center:
1458
- return SnapAlignment::Center;
1459
- case facebook::react::ScrollViewSnapToAlignment::End:
1460
- return SnapAlignment::End;
1461
- case facebook::react::ScrollViewSnapToAlignment::Start:
1462
- default:
1463
- return SnapAlignment::Start;
1464
- }
1465
- }
1466
-
1467
- void ScrollViewComponentView::updateSnapPoints() noexcept {
1468
- const auto &viewProps = *std::static_pointer_cast<const facebook::react::ScrollViewProps>(this->viewProps());
1469
- const auto snapToOffsets = CreateSnapToOffsets(viewProps.snapToOffsets);
1470
- // Typically used in combination with snapToAlignment and decelerationRate="fast"
1471
- auto snapAlignment = SnapAlignment::Center;
1472
- auto decelerationRate = viewProps.decelerationRate;
1473
-
1474
- // snapToOffsets has priority over snapToInterval (matches React Native behavior)
1475
- if (viewProps.snapToInterval > 0 && decelerationRate >= 0.99) {
1476
- snapAlignment = convertSnapToAlignment(viewProps.snapToAlignment);
1477
- // Generate snap points based on interval
1478
- // Calculate the content size to determine how many intervals to create
1479
- float contentLength = viewProps.horizontal
1480
- ? std::max(m_contentSize.width, m_layoutMetrics.frame.size.width) * m_layoutMetrics.pointScaleFactor
1481
- : std::max(m_contentSize.height, m_layoutMetrics.frame.size.height) * m_layoutMetrics.pointScaleFactor;
1482
-
1483
- float interval = static_cast<float>(viewProps.snapToInterval) * m_layoutMetrics.pointScaleFactor;
1484
-
1485
- // Ensure we have a reasonable minimum interval to avoid infinite loops or excessive memory usage
1486
- if (interval >= 1.0f && contentLength > 0) {
1487
- // Generate offsets at each interval, but limit the number of snap points to avoid excessive memory usage
1488
- int snapPointCount = 0;
1489
-
1490
- for (float offset = 0; offset <= contentLength && snapPointCount < c_maxSnapPoints; offset += interval) {
1491
- snapToOffsets.Append(offset);
1492
- snapPointCount++;
1493
- }
1494
- }
1495
- }
1496
-
1497
- m_scrollVisual.SetSnapPoints(viewProps.snapToStart, viewProps.snapToEnd, snapToOffsets.GetView(), snapAlignment);
1498
- }
1499
1464
  } // namespace winrt::Microsoft::ReactNative::Composition::implementation
@@ -18,8 +18,6 @@
18
18
 
19
19
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
20
20
 
21
- using namespace Microsoft::ReactNative::Composition::Experimental;
22
-
23
21
  struct ScrollBarComponent;
24
22
 
25
23
  struct ScrollViewComponentView : ScrollViewComponentViewT<ScrollViewComponentView, ViewComponentView> {
@@ -123,7 +121,6 @@ struct ScrollInteractionTrackerOwner : public winrt::implements<
123
121
  private:
124
122
  void updateDecelerationRate(float value) noexcept;
125
123
  void updateContentVisualSize() noexcept;
126
- void updateSnapPoints() noexcept;
127
124
  bool scrollToEnd(bool animate) noexcept;
128
125
  bool scrollToStart(bool animate) noexcept;
129
126
  bool scrollDown(float delta, bool animate) noexcept;
@@ -137,8 +134,6 @@ struct ScrollInteractionTrackerOwner : public winrt::implements<
137
134
  winrt::Microsoft::ReactNative::Composition::Experimental::IScrollPositionChangedArgs const &args) noexcept;
138
135
  void updateShowsHorizontalScrollIndicator(bool value) noexcept;
139
136
  void updateShowsVerticalScrollIndicator(bool value) noexcept;
140
- SnapAlignment convertSnapToAlignment(facebook::react::ScrollViewSnapToAlignment alignment) noexcept;
141
- winrt::Windows::Foundation::Collections::IVector<float> CreateSnapToOffsets(const std::vector<float> &offsets);
142
137
 
143
138
  facebook::react::Size m_contentSize;
144
139
  winrt::Microsoft::ReactNative::Composition::Experimental::IScrollVisual m_scrollVisual{nullptr};
@@ -148,9 +143,12 @@ struct ScrollInteractionTrackerOwner : public winrt::implements<
148
143
  m_scrollPositionChangedRevoker{};
149
144
  winrt::Microsoft::ReactNative::Composition::Experimental::IScrollVisual::ScrollBeginDrag_revoker
150
145
  m_scrollBeginDragRevoker{};
151
-
152
146
  winrt::Microsoft::ReactNative::Composition::Experimental::IScrollVisual::ScrollEndDrag_revoker
153
147
  m_scrollEndDragRevoker{};
148
+ winrt::Microsoft::ReactNative::Composition::Experimental::IScrollVisual::ScrollMomentumBegin_revoker
149
+ m_scrollMomentumBeginRevoker{};
150
+ winrt::Microsoft::ReactNative::Composition::Experimental::IScrollVisual::ScrollMomentumEnd_revoker
151
+ m_scrollMomentumEndRevoker{};
154
152
 
155
153
  float m_zoomFactor{1.0f};
156
154
  bool m_isScrollingFromInertia = false;
@@ -9,6 +9,7 @@
9
9
  #include <Fabric/AbiViewProps.h>
10
10
  #include "CompositionDynamicAutomationProvider.h"
11
11
  #include "RootComponentView.h"
12
+ #include "UiaHelpers.h"
12
13
 
13
14
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
14
15
 
@@ -80,6 +81,16 @@ void SwitchComponentView::updateProps(
80
81
  m_visualUpdateRequired = true;
81
82
  }
82
83
 
84
+ if (oldViewProps.value != newViewProps.value) {
85
+ if (UiaClientsAreListening()) {
86
+ winrt::Microsoft::ReactNative::implementation::UpdateUiaProperty(
87
+ EnsureUiaProvider(),
88
+ UIA_ToggleToggleStatePropertyId,
89
+ oldViewProps.value ? ToggleState_On : ToggleState_Off,
90
+ newViewProps.value ? ToggleState_On : ToggleState_Off);
91
+ }
92
+ }
93
+
83
94
  Super::updateProps(props, oldProps);
84
95
  }
85
96
 
@@ -7,6 +7,7 @@
7
7
  #include "TextDrawing.h"
8
8
 
9
9
  #include <AutoDraw.h>
10
+ #include <Fabric/platform/react/renderer/graphics/PlatformColorUtils.h>
10
11
  #include <Utils/ValueUtils.h>
11
12
  #include <unicode.h>
12
13
  #include <windows.ui.composition.interop.h>
@@ -35,11 +36,27 @@ void RenderText(
35
36
  // to cache and reuse a brush across all text elements instead, taking care to recreate
36
37
  // it in the event of device removed.
37
38
  winrt::com_ptr<ID2D1SolidColorBrush> brush;
39
+
40
+ // Check if we should use theme-aware default color instead of hardcoded black
41
+ bool useDefaultColor = false;
38
42
  if (textAttributes.foregroundColor) {
43
+ auto &color = *textAttributes.foregroundColor;
44
+ // If it's black (or very dark) without explicit PlatformColor, use theme-aware color
45
+ if (color.m_platformColor.empty() && color.m_color.R <= 10 && color.m_color.G <= 10 && color.m_color.B <= 10) {
46
+ useDefaultColor = true;
47
+ }
48
+ } else {
49
+ useDefaultColor = true;
50
+ }
51
+
52
+ if (useDefaultColor) {
53
+ // Use theme-aware TextFillColorPrimary which adapts to light/dark mode
54
+ auto d2dColor = theme.D2DPlatformColor("TextFillColorPrimary");
55
+ winrt::check_hresult(deviceContext.CreateSolidColorBrush(d2dColor, brush.put()));
56
+ } else {
57
+ // User set explicit color or PlatformColor - use it
39
58
  auto color = theme.D2DColor(*textAttributes.foregroundColor);
40
59
  winrt::check_hresult(deviceContext.CreateSolidColorBrush(color, brush.put()));
41
- } else {
42
- winrt::check_hresult(deviceContext.CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, 1.0f), brush.put()));
43
60
  }
44
61
 
45
62
  if (textAttributes.textDecorationLineType) {
@@ -72,12 +89,27 @@ void RenderText(
72
89
  (fragment.textAttributes.foregroundColor != textAttributes.foregroundColor) ||
73
90
  !isnan(fragment.textAttributes.opacity)) {
74
91
  winrt::com_ptr<ID2D1SolidColorBrush> fragmentBrush;
92
+
93
+ // Check if we should use theme-aware default color for this fragment
94
+ bool useFragmentDefaultColor = false;
75
95
  if (fragment.textAttributes.foregroundColor) {
96
+ auto &color = *fragment.textAttributes.foregroundColor;
97
+ // If it's black (or very dark) without explicit PlatformColor, use theme-aware color
98
+ if (color.m_platformColor.empty() && color.m_color.R <= 10 && color.m_color.G <= 10 && color.m_color.B <= 10) {
99
+ useFragmentDefaultColor = true;
100
+ }
101
+ } else {
102
+ useFragmentDefaultColor = true;
103
+ }
104
+
105
+ if (useFragmentDefaultColor) {
106
+ // Use theme-aware TextFillColorPrimary which adapts to light/dark mode
107
+ auto d2dColor = theme.D2DPlatformColor("TextFillColorPrimary");
108
+ winrt::check_hresult(deviceContext.CreateSolidColorBrush(d2dColor, fragmentBrush.put()));
109
+ } else {
110
+ // User set explicit color or PlatformColor - use it
76
111
  auto color = theme.D2DColor(*fragment.textAttributes.foregroundColor);
77
112
  winrt::check_hresult(deviceContext.CreateSolidColorBrush(color, fragmentBrush.put()));
78
- } else {
79
- winrt::check_hresult(
80
- deviceContext.CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, 1.0f), fragmentBrush.put()));
81
113
  }
82
114
 
83
115
  if (fragment.textAttributes.textDecorationLineType) {
@@ -8,8 +8,11 @@
8
8
  #include <AutoDraw.h>
9
9
  #include <Fabric/Composition/CompositionDynamicAutomationProvider.h>
10
10
  #include <Fabric/Composition/UiaHelpers.h>
11
+ #include <Fabric/platform/react/renderer/graphics/PlatformColorUtils.h>
12
+ #include <Utils/ThemeUtils.h>
11
13
  #include <Utils/ValueUtils.h>
12
14
  #include <react/renderer/components/textinput/TextInputState.h>
15
+ #include <react/renderer/graphics/HostPlatformColor.h>
13
16
  #include <react/renderer/textlayoutmanager/WindowsTextLayoutManager.h>
14
17
  #include <tom.h>
15
18
  #include <unicode.h>
@@ -316,8 +319,10 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
316
319
 
317
320
  switch (nIndex) {
318
321
  case COLOR_WINDOWTEXT:
319
- if (m_outer->windowsTextInputProps().textAttributes.foregroundColor)
320
- return (*m_outer->windowsTextInputProps().textAttributes.foregroundColor).AsColorRefNoAlpha();
322
+ if (m_outer->windowsTextInputProps().textAttributes.foregroundColor) {
323
+ auto color = m_outer->theme()->Color(*m_outer->windowsTextInputProps().textAttributes.foregroundColor);
324
+ return RGB(color.R, color.G, color.B);
325
+ }
321
326
  // cr = 0x000000FF;
322
327
  break;
323
328
  case COLOR_WINDOW:
@@ -326,8 +331,10 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
326
331
  break;
327
332
 
328
333
  case COLOR_HIGHLIGHT:
329
- if (m_outer->windowsTextInputProps().selectionColor)
330
- return (*m_outer->windowsTextInputProps().selectionColor).AsColorRefNoAlpha();
334
+ if (m_outer->windowsTextInputProps().selectionColor) {
335
+ auto color = m_outer->theme()->Color(*m_outer->windowsTextInputProps().selectionColor);
336
+ return RGB(color.R, color.G, color.B);
337
+ }
331
338
  break;
332
339
 
333
340
  case COLOR_HIGHLIGHTTEXT:
@@ -340,8 +347,9 @@ struct CompTextHost : public winrt::implements<CompTextHost, ITextHost> {
340
347
  int r = GetRValue(selectionColor);
341
348
  int g = GetGValue(selectionColor);
342
349
  int b = GetBValue(selectionColor);
343
- int brightness = (r * 299 + g * 587 + b * 114) / 1000;
344
- return brightness > 125 ? RGB(0, 0, 0) : RGB(255, 255, 255);
350
+ int brightness = ::Microsoft::ReactNative::CalculateColorBrightness(r, g, b);
351
+ return brightness > ::Microsoft::ReactNative::kCaretSelectionBrightnessThreshold ? RGB(0, 0, 0)
352
+ : RGB(255, 255, 255);
345
353
  }
346
354
  break;
347
355
 
@@ -1077,13 +1085,9 @@ std::string WindowsTextInputComponentView::DefaultHelpText() const noexcept {
1077
1085
  void WindowsTextInputComponentView::updateCursorColor(
1078
1086
  const facebook::react::SharedColor &cursorColor,
1079
1087
  const facebook::react::SharedColor &foregroundColor) noexcept {
1080
- if (cursorColor) {
1081
- m_caretVisual.Brush(theme()->Brush(*cursorColor));
1082
- } else if (foregroundColor) {
1083
- m_caretVisual.Brush(theme()->Brush(*foregroundColor));
1084
- } else {
1085
- m_caretVisual.Brush(theme()->PlatformBrush("TextControlForeground"));
1086
- }
1088
+ const auto &props = windowsTextInputProps();
1089
+ auto caretColor = ::Microsoft::ReactNative::GetCaretColor(cursorColor, foregroundColor, props.backgroundColor);
1090
+ m_caretVisual.Brush(theme()->Brush(*caretColor));
1087
1091
  }
1088
1092
 
1089
1093
  void WindowsTextInputComponentView::updateProps(
@@ -1595,6 +1599,8 @@ void WindowsTextInputComponentView::ensureDrawingSurface() noexcept {
1595
1599
 
1596
1600
  void WindowsTextInputComponentView::ShowCaret(bool show) noexcept {
1597
1601
  ensureVisual();
1602
+ const auto &props = windowsTextInputProps();
1603
+ updateCursorColor(props.cursorColor, props.textAttributes.foregroundColor);
1598
1604
  m_caretVisual.IsVisible(show);
1599
1605
  }
1600
1606
 
@@ -1689,8 +1695,20 @@ void WindowsTextInputComponentView::DrawText() noexcept {
1689
1695
  auto color = theme()->D2DColor(*props.placeholderTextColor);
1690
1696
  winrt::check_hresult(d2dDeviceContext->CreateSolidColorBrush(color, brush.put()));
1691
1697
  } else {
1692
- winrt::check_hresult(
1693
- d2dDeviceContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Gray, 1.0f), brush.put()));
1698
+ // Use theme-aware placeholder color based on focus state and background
1699
+ // Color selection follows Windows 11 design system semantic colors:
1700
+ // - High contrast: System GrayText for accessibility
1701
+ // - Light backgrounds: Darker grays for better contrast
1702
+ // - Dark backgrounds: Lighter grays for readability
1703
+ winrt::Windows::UI::Color backgroundColor = {};
1704
+ if (facebook::react::isColorMeaningful(props.backgroundColor)) {
1705
+ auto bgColor = (*props.backgroundColor).AsWindowsColor();
1706
+ backgroundColor = bgColor;
1707
+ }
1708
+
1709
+ auto placeholderColor = facebook::react::GetTextInputPlaceholderColor(m_hasFocus, backgroundColor);
1710
+ auto d2dColor = theme()->D2DColor(*placeholderColor);
1711
+ winrt::check_hresult(d2dDeviceContext->CreateSolidColorBrush(d2dColor, brush.put()));
1694
1712
  }
1695
1713
 
1696
1714
  // Create placeholder text layout
@@ -166,6 +166,24 @@ void UpdateUiaProperty(winrt::IInspectable provider, PROPERTYID propId, bool old
166
166
  UiaRaiseAutomationPropertyChangedEvent(spProviderSimple.get(), propId, CComVariant(oldValue), CComVariant(newValue));
167
167
  }
168
168
 
169
+ void UpdateUiaProperty(winrt::IInspectable provider, PROPERTYID propId, int oldValue, int newValue) noexcept {
170
+ auto spProviderSimple = provider.try_as<IRawElementProviderSimple>();
171
+
172
+ if (spProviderSimple == nullptr || oldValue == newValue || !WasUiaPropertyAdvised(spProviderSimple, propId))
173
+ return;
174
+
175
+ UiaRaiseAutomationPropertyChangedEvent(spProviderSimple.get(), propId, CComVariant(oldValue), CComVariant(newValue));
176
+ }
177
+
178
+ void UpdateUiaProperty(winrt::IInspectable provider, PROPERTYID propId, long oldValue, long newValue) noexcept {
179
+ auto spProviderSimple = provider.try_as<IRawElementProviderSimple>();
180
+
181
+ if (spProviderSimple == nullptr || oldValue == newValue || !WasUiaPropertyAdvised(spProviderSimple, propId))
182
+ return;
183
+
184
+ UiaRaiseAutomationPropertyChangedEvent(spProviderSimple.get(), propId, CComVariant(oldValue), CComVariant(newValue));
185
+ }
186
+
169
187
  void UpdateUiaProperty(
170
188
  winrt::IInspectable provider,
171
189
  PROPERTYID propId,
@@ -190,6 +208,29 @@ void UpdateUiaProperty(
190
208
  UpdateUiaProperty(provider, propId, oldData, newData);
191
209
  }
192
210
 
211
+ void UpdateUiaPropertiesForAnnotation(
212
+ winrt::IInspectable provider,
213
+ const std::optional<facebook::react::AccessibilityAnnotation> &oldAnnotation,
214
+ const std::optional<facebook::react::AccessibilityAnnotation> &newAnnotation) noexcept {
215
+ // if no value fall back to a default value.
216
+ const auto &old_annotation = oldAnnotation.value_or(facebook::react::AccessibilityAnnotation());
217
+ const auto &new_annotation = newAnnotation.value_or(facebook::react::AccessibilityAnnotation());
218
+
219
+ // Update all annotation properties
220
+ UpdateUiaProperty(
221
+ provider,
222
+ UIA_AnnotationAnnotationTypeIdPropertyId,
223
+ GetAnnotationTypeId(old_annotation.typeID),
224
+ GetAnnotationTypeId(new_annotation.typeID));
225
+
226
+ UpdateUiaProperty(
227
+ provider, UIA_AnnotationAnnotationTypeNamePropertyId, old_annotation.typeName, new_annotation.typeName);
228
+
229
+ UpdateUiaProperty(provider, UIA_AnnotationAuthorPropertyId, old_annotation.author, new_annotation.author);
230
+
231
+ UpdateUiaProperty(provider, UIA_AnnotationDateTimePropertyId, old_annotation.dateTime, new_annotation.dateTime);
232
+ }
233
+
193
234
  long GetLiveSetting(const std::string &liveRegion) noexcept {
194
235
  if (liveRegion == "polite") {
195
236
  return LiveSetting::Polite;
@@ -250,6 +291,190 @@ long GetAnnotationTypeId(const std::string &annotationType) noexcept {
250
291
  return AnnotationType_Unknown;
251
292
  }
252
293
 
294
+ long GetControlTypeFromString(const std::string &role) noexcept {
295
+ if (role == "adjustable") {
296
+ return UIA_SliderControlTypeId;
297
+ } else if (role == "group" || role == "search" || role == "radiogroup" || role == "timer" || role.empty()) {
298
+ return UIA_GroupControlTypeId;
299
+ } else if (role == "button" || role == "imagebutton" || role == "switch" || role == "togglebutton") {
300
+ return UIA_ButtonControlTypeId;
301
+ } else if (role == "checkbox") {
302
+ return UIA_CheckBoxControlTypeId;
303
+ } else if (role == "combobox") {
304
+ return UIA_ComboBoxControlTypeId;
305
+ } else if (role == "alert" || role == "header" || role == "summary" || role == "text") {
306
+ return UIA_TextControlTypeId;
307
+ } else if (role == "image") {
308
+ return UIA_ImageControlTypeId;
309
+ } else if (role == "keyboardkey") {
310
+ return UIA_CustomControlTypeId;
311
+ } else if (role == "link") {
312
+ return UIA_HyperlinkControlTypeId;
313
+ }
314
+ // list and listitem were added by RNW to better support UIA Control Types
315
+ else if (role == "list") {
316
+ return UIA_ListControlTypeId;
317
+ } else if (role == "listitem") {
318
+ return UIA_ListItemControlTypeId;
319
+ } else if (role == "menu") {
320
+ return UIA_MenuControlTypeId;
321
+ } else if (role == "menubar") {
322
+ return UIA_MenuBarControlTypeId;
323
+ } else if (role == "menuitem") {
324
+ return UIA_MenuItemControlTypeId;
325
+ }
326
+ // If role is "none", remove the element from the control tree
327
+ // and expose it as a plain element would in the raw tree.
328
+ else if (role == "none") {
329
+ return UIA_GroupControlTypeId;
330
+ } else if (role == "progressbar") {
331
+ return UIA_ProgressBarControlTypeId;
332
+ } else if (role == "radio") {
333
+ return UIA_RadioButtonControlTypeId;
334
+ } else if (role == "scrollbar") {
335
+ return UIA_ScrollBarControlTypeId;
336
+ } else if (role == "spinbutton") {
337
+ return UIA_SpinnerControlTypeId;
338
+ } else if (role == "splitbutton") {
339
+ return UIA_SplitButtonControlTypeId;
340
+ } else if (role == "tab") {
341
+ return UIA_TabItemControlTypeId;
342
+ } else if (role == "tablist") {
343
+ return UIA_TabControlTypeId;
344
+ } else if (role == "textinput" || role == "searchbox") {
345
+ return UIA_EditControlTypeId;
346
+ } else if (role == "toolbar") {
347
+ return UIA_ToolBarControlTypeId;
348
+ } else if (role == "tree") {
349
+ return UIA_TreeControlTypeId;
350
+ } else if (role == "treeitem") {
351
+ return UIA_TreeItemControlTypeId;
352
+ } else if (role == "pane") {
353
+ return UIA_PaneControlTypeId;
354
+ }
355
+ assert(false);
356
+ return UIA_GroupControlTypeId;
357
+ }
358
+
359
+ long GetControlTypeFromRole(const facebook::react::Role &role) noexcept {
360
+ switch (role) {
361
+ case facebook::react::Role::Alert:
362
+ return UIA_TextControlTypeId;
363
+ case facebook::react::Role::Application:
364
+ return UIA_WindowControlTypeId;
365
+ case facebook::react::Role::Button:
366
+ return UIA_ButtonControlTypeId;
367
+ case facebook::react::Role::Checkbox:
368
+ return UIA_CheckBoxControlTypeId;
369
+ case facebook::react::Role::Columnheader:
370
+ return UIA_HeaderControlTypeId;
371
+ case facebook::react::Role::Combobox:
372
+ return UIA_ComboBoxControlTypeId;
373
+ case facebook::react::Role::Document:
374
+ return UIA_DocumentControlTypeId;
375
+ case facebook::react::Role::Grid:
376
+ return UIA_GroupControlTypeId;
377
+ case facebook::react::Role::Group:
378
+ return UIA_GroupControlTypeId;
379
+ case facebook::react::Role::Heading:
380
+ return UIA_TextControlTypeId;
381
+ case facebook::react::Role::Img:
382
+ return UIA_ImageControlTypeId;
383
+ case facebook::react::Role::Link:
384
+ return UIA_HyperlinkControlTypeId;
385
+ case facebook::react::Role::List:
386
+ return UIA_ListControlTypeId;
387
+ case facebook::react::Role::Listitem:
388
+ return UIA_ListItemControlTypeId;
389
+ case facebook::react::Role::Menu:
390
+ return UIA_MenuControlTypeId;
391
+ case facebook::react::Role::Menubar:
392
+ return UIA_MenuBarControlTypeId;
393
+ case facebook::react::Role::Menuitem:
394
+ return UIA_MenuItemControlTypeId;
395
+ case facebook::react::Role::None:
396
+ return UIA_GroupControlTypeId;
397
+ case facebook::react::Role::Presentation:
398
+ return UIA_GroupControlTypeId;
399
+ case facebook::react::Role::Progressbar:
400
+ return UIA_ProgressBarControlTypeId;
401
+ case facebook::react::Role::Radio:
402
+ return UIA_RadioButtonControlTypeId;
403
+ case facebook::react::Role::Radiogroup:
404
+ return UIA_GroupControlTypeId;
405
+ case facebook::react::Role::Rowgroup:
406
+ return UIA_GroupControlTypeId;
407
+ case facebook::react::Role::Rowheader:
408
+ return UIA_HeaderControlTypeId;
409
+ case facebook::react::Role::Scrollbar:
410
+ return UIA_ScrollBarControlTypeId;
411
+ case facebook::react::Role::Searchbox:
412
+ return UIA_EditControlTypeId;
413
+ case facebook::react::Role::Separator:
414
+ return UIA_SeparatorControlTypeId;
415
+ case facebook::react::Role::Slider:
416
+ return UIA_SliderControlTypeId;
417
+ case facebook::react::Role::Spinbutton:
418
+ return UIA_SpinnerControlTypeId;
419
+ case facebook::react::Role::Status:
420
+ return UIA_StatusBarControlTypeId;
421
+ case facebook::react::Role::Summary:
422
+ return UIA_GroupControlTypeId;
423
+ case facebook::react::Role::Switch:
424
+ return UIA_ButtonControlTypeId;
425
+ case facebook::react::Role::Tab:
426
+ return UIA_TabItemControlTypeId;
427
+ case facebook::react::Role::Table:
428
+ return UIA_TableControlTypeId;
429
+ case facebook::react::Role::Tablist:
430
+ return UIA_TabControlTypeId;
431
+ case facebook::react::Role::Tabpanel:
432
+ return UIA_TabControlTypeId;
433
+ case facebook::react::Role::Timer:
434
+ return UIA_ButtonControlTypeId;
435
+ case facebook::react::Role::Toolbar:
436
+ return UIA_ToolBarControlTypeId;
437
+ case facebook::react::Role::Tooltip:
438
+ return UIA_ToolTipControlTypeId;
439
+ case facebook::react::Role::Tree:
440
+ return UIA_TreeControlTypeId;
441
+ case facebook::react::Role::Treegrid:
442
+ return UIA_TreeControlTypeId;
443
+ case facebook::react::Role::Treeitem:
444
+ return UIA_TreeItemControlTypeId;
445
+ }
446
+ return UIA_GroupControlTypeId;
447
+ }
448
+
449
+ long GetHeadingLevel(int headingLevel, const std::string &strRole, const facebook::react::Role &role) noexcept {
450
+ if (strRole != "header" && role != facebook::react::Role::Heading) {
451
+ return HeadingLevel_None;
452
+ }
453
+
454
+ switch (headingLevel) {
455
+ case 1:
456
+ return HeadingLevel1;
457
+ case 2:
458
+ return HeadingLevel2;
459
+ case 3:
460
+ return HeadingLevel3;
461
+ case 4:
462
+ return HeadingLevel4;
463
+ case 5:
464
+ return HeadingLevel5;
465
+ case 6:
466
+ return HeadingLevel6;
467
+ case 7:
468
+ return HeadingLevel7;
469
+ case 8:
470
+ return HeadingLevel8;
471
+ case 9:
472
+ return HeadingLevel9;
473
+ default:
474
+ return HeadingLevel_None;
475
+ }
476
+ }
477
+
253
478
  bool accessibilityAnnotationHasValue(
254
479
  const std::optional<facebook::react::AccessibilityAnnotation> &annotation) noexcept {
255
480
  return annotation.has_value() &&
@@ -29,6 +29,18 @@ void UpdateUiaProperty(
29
29
  bool oldValue,
30
30
  bool newValue) noexcept;
31
31
 
32
+ void UpdateUiaProperty(
33
+ winrt::Windows::Foundation::IInspectable provider,
34
+ PROPERTYID propId,
35
+ int oldValue,
36
+ int newValue) noexcept;
37
+
38
+ void UpdateUiaProperty(
39
+ winrt::Windows::Foundation::IInspectable provider,
40
+ PROPERTYID propId,
41
+ long oldValue,
42
+ long newValue) noexcept;
43
+
32
44
  void UpdateUiaProperty(
33
45
  winrt::Windows::Foundation::IInspectable provider,
34
46
  PROPERTYID propId,
@@ -41,10 +53,21 @@ void UpdateUiaProperty(
41
53
  const std::optional<std::string> &oldValue,
42
54
  const std::optional<std::string> &newValue) noexcept;
43
55
 
56
+ void UpdateUiaPropertiesForAnnotation(
57
+ winrt::Windows::Foundation::IInspectable provider,
58
+ const std::optional<facebook::react::AccessibilityAnnotation> &oldAnnotation,
59
+ const std::optional<facebook::react::AccessibilityAnnotation> &newAnnotation) noexcept;
60
+
44
61
  long GetLiveSetting(const std::string &liveRegion) noexcept;
45
62
 
46
63
  long GetAnnotationTypeId(const std::string &annotationType) noexcept;
47
64
 
65
+ long GetControlTypeFromRole(const facebook::react::Role &role) noexcept;
66
+
67
+ long GetControlTypeFromString(const std::string &role) noexcept;
68
+
69
+ long GetHeadingLevel(int headingLevel, const std::string &strRole, const facebook::react::Role &role) noexcept;
70
+
48
71
  bool accessibilityAnnotationHasValue(
49
72
  const std::optional<facebook::react::AccessibilityAnnotation> &annotation) noexcept;
50
73
 
@@ -66,7 +66,8 @@ FabricUIManager::~FabricUIManager() {
66
66
  void FabricUIManager::installFabricUIManager() noexcept {
67
67
  std::lock_guard<std::mutex> schedulerLock(m_schedulerMutex);
68
68
 
69
- facebook::react::ContextContainer::Shared contextContainer = std::make_shared<facebook::react::ContextContainer>();
69
+ std::shared_ptr<const facebook::react::ContextContainer> contextContainer =
70
+ std::make_shared<facebook::react::ContextContainer>();
70
71
 
71
72
  // This allows access to our ReactContext from the contextContainer thats passed around the fabric codebase
72
73
  contextContainer->insert("MSRN.ReactContext", m_context);
@@ -97,8 +98,9 @@ void FabricUIManager::installFabricUIManager() noexcept {
97
98
  };
98
99
 
99
100
  toolbox.contextContainer = contextContainer;
100
- toolbox.componentRegistryFactory = [](facebook::react::EventDispatcher::Weak const &eventDispatcher,
101
- facebook::react::ContextContainer::Shared const &contextContainer)
101
+ toolbox.componentRegistryFactory =
102
+ [](facebook::react::EventDispatcher::Weak const &eventDispatcher,
103
+ std::shared_ptr<const facebook::react::ContextContainer> const &contextContainer)
102
104
  -> facebook::react::ComponentDescriptorRegistry::Shared {
103
105
  auto providerRegistry =
104
106
  WindowsComponentDescriptorRegistry::FromProperties(