react-native-windows 0.81.0-preview.1 → 0.81.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.
@@ -35,26 +35,44 @@ struct ModalHostState
35
35
  struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::Foundation::IInspectable>,
36
36
  ::Microsoft::ReactNativeSpecs::BaseModalHostView<ModalHostView> {
37
37
  ~ModalHostView() {
38
- if (m_reactNativeIsland) {
39
- m_reactNativeIsland.Island().Close();
40
- }
38
+ if (m_popUp) {
39
+ // Unregister closing event handler
40
+ if (m_appWindow && m_appWindowClosingToken) {
41
+ m_appWindow.Closing(m_appWindowClosingToken);
42
+ m_appWindowClosingToken.value = 0;
43
+ }
41
44
 
42
- // Add AppWindow closing token cleanup
43
- if (m_appWindow && m_appWindowClosingToken) {
44
- m_appWindow.Closing(m_appWindowClosingToken);
45
- m_appWindowClosingToken.value = 0;
46
- }
45
+ // Reset topWindowID before destroying
46
+ if (m_prevWindowID) {
47
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
48
+ m_reactContext.Properties().Handle(), m_prevWindowID);
49
+ m_prevWindowID = 0;
50
+ }
47
51
 
48
- if (m_popUp) {
49
- if (m_departFocusToken && !m_popUp.IsClosed()) {
50
- // WASDK BUG: InputFocusNavigationHost::GetForSiteBridge fails on a DesktopPopupSiteBridge
51
- // https://github.com/microsoft/react-native-windows/issues/14604
52
- /*
53
- auto navHost =
54
- winrt::Microsoft::UI::Input::InputFocusNavigationHost::GetForSiteBridge(m_popUp.as<winrt::Microsoft::UI::Content::IContentSiteBridge>());
55
- navHost.DepartFocusRequested(m_departFocusToken);
56
- */
52
+ // Close island
53
+ if (m_reactNativeIsland) {
54
+ m_reactNativeIsland.Island().Close();
55
+ m_reactNativeIsland = nullptr;
56
+ }
57
+
58
+ // Hide popup
59
+ if (m_popUp.IsVisible()) {
60
+ m_popUp.Hide();
61
+ }
62
+
63
+ // Destroy AppWindow this automatically resumes parent window to receive inputs
64
+ if (m_appWindow) {
65
+ m_appWindow.Destroy();
66
+ m_appWindow = nullptr;
67
+ }
68
+
69
+ // Bring parent window to foreground
70
+ if (m_parentHwnd) {
71
+ SetForegroundWindow(m_parentHwnd);
72
+ SetFocus(m_parentHwnd);
57
73
  }
74
+
75
+ // Close bridge
58
76
  m_popUp.Close();
59
77
  m_popUp = nullptr;
60
78
  }
@@ -88,7 +106,7 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
88
106
  QueueShow(view);
89
107
  } else {
90
108
  m_visible = false;
91
- CloseWindow();
109
+ HideWindow();
92
110
  }
93
111
  }
94
112
 
@@ -219,31 +237,33 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
219
237
  }
220
238
  }
221
239
 
222
- void CloseWindow() noexcept {
223
- // enable input to parent before closing the modal window, so focus can return back to the parent window
224
- EnableWindow(m_parentHwnd, true);
240
+ /*
241
+ HideWindow called on visible=false
242
+ unmounts the modal window using onDismiss event
243
+ */
244
+ void HideWindow() noexcept {
245
+ // Hide popup
225
246
  if (m_popUp) {
226
247
  m_popUp.Hide();
227
248
  }
228
249
 
229
- // Unregister closing event handler
230
- if (m_appWindow && m_appWindowClosingToken) {
231
- m_appWindow.Closing(m_appWindowClosingToken);
232
- m_appWindowClosingToken.value = 0;
250
+ // Restore message routing to parent
251
+ if (m_prevWindowID) {
252
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
253
+ m_reactContext.Properties().Handle(), m_prevWindowID);
233
254
  }
234
255
 
235
- // dispatch onDismiss event
256
+ // Bring parent window to foreground
257
+ if (m_parentHwnd) {
258
+ SetForegroundWindow(m_parentHwnd);
259
+ SetFocus(m_parentHwnd);
260
+ }
261
+
262
+ // Dispatch onDismiss event
236
263
  if (auto eventEmitter = EventEmitter()) {
237
264
  ::Microsoft::ReactNativeSpecs::ModalHostViewEventEmitter::OnDismiss eventArgs;
238
265
  eventEmitter->onDismiss(eventArgs);
239
266
  }
240
-
241
- // reset the topWindowID
242
- if (m_prevWindowID) {
243
- winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
244
- m_reactContext.Properties().Handle(), m_prevWindowID);
245
- m_prevWindowID = 0;
246
- }
247
267
  }
248
268
 
249
269
  // creates a new modal window
@@ -279,9 +299,16 @@ struct ModalHostView : public winrt::implements<ModalHostView, winrt::Windows::F
279
299
  overlappedPresenter.IsModal(true);
280
300
  overlappedPresenter.SetBorderAndTitleBar(true, true);
281
301
 
302
+ // modal should only have close button
303
+ overlappedPresenter.IsMinimizable(false);
304
+ overlappedPresenter.IsMaximizable(false);
305
+
282
306
  // Apply the presenter to the window
283
307
  m_appWindow.SetPresenter(overlappedPresenter);
284
308
 
309
+ // Hide the title bar icon
310
+ m_appWindow.TitleBar().IconShowOptions(winrt::Microsoft::UI::Windowing::IconShowOptions::HideIconAndSystemMenu);
311
+
285
312
  // Set initial title using the stored local props
286
313
  if (m_localProps && m_localProps->title.has_value()) {
287
314
  winrt::hstring titleValue = winrt::to_hstring(m_localProps->title.value());
@@ -814,6 +814,25 @@ void ScrollViewComponentView::updateProps(
814
814
  }
815
815
  m_scrollVisual.SetSnapPoints(newViewProps.snapToStart, newViewProps.snapToEnd, snapToOffsets.GetView());
816
816
  }
817
+
818
+ if (!oldProps || oldViewProps.pagingEnabled != newViewProps.pagingEnabled) {
819
+ m_scrollVisual.PagingEnabled(newViewProps.pagingEnabled);
820
+ }
821
+
822
+ if (!oldProps || oldViewProps.snapToInterval != newViewProps.snapToInterval) {
823
+ m_scrollVisual.SnapToInterval(static_cast<float>(newViewProps.snapToInterval));
824
+ }
825
+
826
+ if (!oldProps || oldViewProps.snapToAlignment != newViewProps.snapToAlignment) {
827
+ using SnapPointsAlignment = winrt::Microsoft::ReactNative::Composition::Experimental::SnapPointsAlignment;
828
+ SnapPointsAlignment alignment = SnapPointsAlignment::Near; // default is "start"
829
+ if (newViewProps.snapToAlignment == facebook::react::ScrollViewSnapToAlignment::Center) {
830
+ alignment = SnapPointsAlignment::Center;
831
+ } else if (newViewProps.snapToAlignment == facebook::react::ScrollViewSnapToAlignment::End) {
832
+ alignment = SnapPointsAlignment::Far;
833
+ }
834
+ m_scrollVisual.SnapToAlignment(alignment);
835
+ }
817
836
  }
818
837
 
819
838
  void ScrollViewComponentView::updateState(
@@ -697,10 +697,17 @@ void WindowsTextInputComponentView::OnPointerPressed(
697
697
  }
698
698
 
699
699
  if (m_textServices && msg) {
700
- LRESULT lresult;
701
- DrawBlock db(*this);
702
- auto hr = m_textServices->TxSendMessage(msg, static_cast<WPARAM>(wParam), static_cast<LPARAM>(lParam), &lresult);
703
- args.Handled(hr != S_FALSE);
700
+ if (msg == WM_RBUTTONUP && !windowsTextInputProps().contextMenuHidden) {
701
+ ShowContextMenu(position);
702
+ args.Handled(true);
703
+ } else if (msg == WM_RBUTTONUP && windowsTextInputProps().contextMenuHidden) {
704
+ args.Handled(true);
705
+ } else {
706
+ LRESULT lresult;
707
+ DrawBlock db(*this);
708
+ auto hr = m_textServices->TxSendMessage(msg, static_cast<WPARAM>(wParam), static_cast<LPARAM>(lParam), &lresult);
709
+ args.Handled(hr != S_FALSE);
710
+ }
704
711
  }
705
712
 
706
713
  // Emits the OnPressIn event
@@ -844,8 +851,8 @@ void WindowsTextInputComponentView::OnPointerWheelChanged(
844
851
  }
845
852
  void WindowsTextInputComponentView::OnKeyDown(
846
853
  const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept {
847
- // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI
848
- // behavior We do forward Ctrl+Tab to the textinput.
854
+ // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with
855
+ // WinUI behavior We do forward Ctrl+Tab to the textinput.
849
856
  if (args.Key() != winrt::Windows::System::VirtualKey::Tab ||
850
857
  (args.KeyboardSource().GetKeyState(winrt::Windows::System::VirtualKey::Control) &
851
858
  winrt::Microsoft::UI::Input::VirtualKeyStates::Down) == winrt::Microsoft::UI::Input::VirtualKeyStates::Down) {
@@ -872,8 +879,8 @@ void WindowsTextInputComponentView::OnKeyDown(
872
879
 
873
880
  void WindowsTextInputComponentView::OnKeyUp(
874
881
  const winrt::Microsoft::ReactNative::Composition::Input::KeyRoutedEventArgs &args) noexcept {
875
- // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI
876
- // behavior We do forward Ctrl+Tab to the textinput.
882
+ // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with
883
+ // WinUI behavior We do forward Ctrl+Tab to the textinput.
877
884
  if (args.Key() != winrt::Windows::System::VirtualKey::Tab ||
878
885
  (args.KeyboardSource().GetKeyState(winrt::Windows::System::VirtualKey::Control) &
879
886
  winrt::Microsoft::UI::Input::VirtualKeyStates::Down) == winrt::Microsoft::UI::Input::VirtualKeyStates::Down) {
@@ -943,8 +950,8 @@ bool WindowsTextInputComponentView::ShouldSubmit(
943
950
 
944
951
  void WindowsTextInputComponentView::OnCharacterReceived(
945
952
  const winrt::Microsoft::ReactNative::Composition::Input::CharacterReceivedRoutedEventArgs &args) noexcept {
946
- // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with WinUI
947
- // behavior We do forward Ctrl+Tab to the textinput.
953
+ // Do not forward tab keys into the TextInput, since we want that to do the tab loop instead. This aligns with
954
+ // WinUI behavior We do forward Ctrl+Tab to the textinput.
948
955
  if ((args.KeyCode() == '\t') &&
949
956
  ((args.KeyboardSource().GetKeyState(winrt::Windows::System::VirtualKey::Control) &
950
957
  winrt::Microsoft::UI::Input::VirtualKeyStates::Down) != winrt::Microsoft::UI::Input::VirtualKeyStates::Down)) {
@@ -1547,25 +1554,59 @@ void WindowsTextInputComponentView::UpdateParaFormat() noexcept {
1547
1554
  m_pf.dwMask = PFM_ALL;
1548
1555
 
1549
1556
  auto &textAlign = windowsTextInputProps().textAlign;
1557
+ auto &baseWritingDirection = windowsTextInputProps().textAttributes.baseWritingDirection;
1558
+
1559
+ // Handle writingDirection (baseWritingDirection)
1560
+ // For WritingDirection::Natural, use the computed layout direction from the layout tree
1561
+ // since direction can be overridden at any point in the tree
1562
+ bool isRTL = false;
1563
+ if (baseWritingDirection.has_value()) {
1564
+ if (*baseWritingDirection == facebook::react::WritingDirection::RightToLeft) {
1565
+ isRTL = true;
1566
+ m_pf.dwMask |= PFM_RTLPARA;
1567
+ m_pf.wEffects |= PFE_RTLPARA;
1568
+ } else if (*baseWritingDirection == facebook::react::WritingDirection::LeftToRight) {
1569
+ isRTL = false;
1570
+ // Ensure RTL flag is not set
1571
+ m_pf.wEffects &= ~PFE_RTLPARA;
1572
+ } else if (*baseWritingDirection == facebook::react::WritingDirection::Natural) {
1573
+ // Natural uses the layout direction computed from the tree
1574
+ isRTL = (layoutMetrics().layoutDirection == facebook::react::LayoutDirection::RightToLeft);
1575
+ if (isRTL) {
1576
+ m_pf.dwMask |= PFM_RTLPARA;
1577
+ m_pf.wEffects |= PFE_RTLPARA;
1578
+ } else {
1579
+ m_pf.wEffects &= ~PFE_RTLPARA;
1580
+ }
1581
+ }
1582
+ } else {
1583
+ // No explicit writing direction set - use layout direction from tree
1584
+ isRTL = (layoutMetrics().layoutDirection == facebook::react::LayoutDirection::RightToLeft);
1585
+ if (isRTL) {
1586
+ m_pf.dwMask |= PFM_RTLPARA;
1587
+ m_pf.wEffects |= PFE_RTLPARA;
1588
+ } else {
1589
+ m_pf.wEffects &= ~PFE_RTLPARA;
1590
+ }
1591
+ }
1550
1592
 
1593
+ // Handle textAlign
1551
1594
  if (textAlign == facebook::react::TextAlignment::Center) {
1552
1595
  m_pf.wAlignment = PFA_CENTER;
1553
1596
  } else if (textAlign == facebook::react::TextAlignment::Right) {
1554
1597
  m_pf.wAlignment = PFA_RIGHT;
1598
+ } else if (textAlign == facebook::react::TextAlignment::Justified) {
1599
+ m_pf.wAlignment = PFA_JUSTIFY;
1600
+ } else if (textAlign == facebook::react::TextAlignment::Natural) {
1601
+ // Natural alignment respects writing direction
1602
+ m_pf.wAlignment = isRTL ? PFA_RIGHT : PFA_LEFT;
1555
1603
  } else {
1604
+ // Default to left alignment
1556
1605
  m_pf.wAlignment = PFA_LEFT;
1557
1606
  }
1558
1607
 
1559
1608
  m_pf.cTabCount = 1;
1560
1609
  m_pf.rgxTabs[0] = lDefaultTab;
1561
-
1562
- /*
1563
- if (m_spcontroller->IsCurrentReadingOrderRTL())
1564
- {
1565
- m_pf.dwMask |= PFM_RTLPARA;
1566
- m_pf.wEffects |= PFE_RTLPARA;
1567
- }
1568
- */
1569
1610
  }
1570
1611
 
1571
1612
  void WindowsTextInputComponentView::OnRenderingDeviceLost() noexcept {
@@ -1826,4 +1867,47 @@ void WindowsTextInputComponentView::updateSpellCheck(bool enable) noexcept {
1826
1867
  winrt::check_hresult(
1827
1868
  m_textServices->TxSendMessage(EM_SETLANGOPTIONS, IMF_SPELLCHECKING, enable ? newLangOptions : 0, &lresult));
1828
1869
  }
1870
+
1871
+ void WindowsTextInputComponentView::ShowContextMenu(const winrt::Windows::Foundation::Point &position) noexcept {
1872
+ HMENU menu = CreatePopupMenu();
1873
+ if (!menu)
1874
+ return;
1875
+
1876
+ CHARRANGE selection;
1877
+ LRESULT res;
1878
+ m_textServices->TxSendMessage(EM_EXGETSEL, 0, reinterpret_cast<LPARAM>(&selection), &res);
1879
+
1880
+ bool hasSelection = selection.cpMin != selection.cpMax;
1881
+ bool isEmpty = GetTextFromRichEdit().empty();
1882
+ bool isReadOnly = windowsTextInputProps().editable == false;
1883
+ bool canPaste = !isReadOnly && IsClipboardFormatAvailable(CF_UNICODETEXT);
1884
+
1885
+ AppendMenuW(menu, MF_STRING | (hasSelection && !isReadOnly ? 0 : MF_GRAYED), 1, L"Cut");
1886
+ AppendMenuW(menu, MF_STRING | (hasSelection ? 0 : MF_GRAYED), 2, L"Copy");
1887
+ AppendMenuW(menu, MF_STRING | (canPaste ? 0 : MF_GRAYED), 3, L"Paste");
1888
+ AppendMenuW(menu, MF_STRING | (!isEmpty && !isReadOnly ? 0 : MF_GRAYED), 4, L"Select All");
1889
+
1890
+ POINT cursorPos;
1891
+ GetCursorPos(&cursorPos);
1892
+
1893
+ HWND hwnd = GetActiveWindow();
1894
+
1895
+ int cmd = TrackPopupMenu(
1896
+ menu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD | TPM_NONOTIFY, cursorPos.x, cursorPos.y, 0, hwnd, NULL);
1897
+
1898
+ if (cmd == 1) { // Cut
1899
+ m_textServices->TxSendMessage(WM_CUT, 0, 0, &res);
1900
+ OnTextUpdated();
1901
+ } else if (cmd == 2) { // Copy
1902
+ m_textServices->TxSendMessage(WM_COPY, 0, 0, &res);
1903
+ } else if (cmd == 3) { // Paste
1904
+ m_textServices->TxSendMessage(WM_PASTE, 0, 0, &res);
1905
+ OnTextUpdated();
1906
+ } else if (cmd == 4) { // Select All
1907
+ m_textServices->TxSendMessage(EM_SETSEL, 0, -1, &res);
1908
+ }
1909
+
1910
+ DestroyMenu(menu);
1911
+ }
1912
+
1829
1913
  } // namespace winrt::Microsoft::ReactNative::Composition::implementation
@@ -118,6 +118,7 @@ struct WindowsTextInputComponentView
118
118
  void updateLetterSpacing(float letterSpacing) noexcept;
119
119
  void updateAutoCorrect(bool value) noexcept;
120
120
  void updateSpellCheck(bool value) noexcept;
121
+ void ShowContextMenu(const winrt::Windows::Foundation::Point &position) noexcept;
121
122
 
122
123
  winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
123
124
  winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr};
@@ -291,9 +291,11 @@ ImageResponseOrImageErrorInfo ImageFailedResponse::ResolveImage() {
291
291
  if (imageOrError.errorInfo->error.empty()) {
292
292
  imageOrError.errorInfo->error = "Failed to load image.";
293
293
  }
294
- for (auto &&[header, value] : m_responseHeaders) {
295
- imageOrError.errorInfo->httpResponseHeaders.push_back(
296
- std::make_pair<std::string, std::string>(winrt::to_string(header), winrt::to_string(value)));
294
+ if (m_responseHeaders) {
295
+ for (auto &&[header, value] : m_responseHeaders) {
296
+ imageOrError.errorInfo->httpResponseHeaders.push_back(
297
+ std::make_pair<std::string, std::string>(winrt::to_string(header), winrt::to_string(value)));
298
+ }
297
299
  }
298
300
  return imageOrError;
299
301
  }
@@ -10,6 +10,7 @@
10
10
  #include <Fabric/Composition/ImageResponseImage.h>
11
11
  #include <Fabric/Composition/UriImageManager.h>
12
12
  #include <Networking/NetworkPropertyIds.h>
13
+ #include <Utils/CppWinrtLessExceptions.h>
13
14
  #include <Utils/ImageUtils.h>
14
15
  #include <fmt/format.h>
15
16
  #include <functional/functor.h>
@@ -131,7 +132,19 @@ WindowsImageManager::GetImageRandomAccessStreamAsync(
131
132
  request.Content(bodyContent);
132
133
  }
133
134
 
134
- winrt::Windows::Web::Http::HttpResponseMessage response(co_await m_httpClient.SendRequestAsync(request));
135
+ auto asyncOp = m_httpClient.SendRequestAsync(request);
136
+ co_await lessthrow_await_adapter<winrt::Windows::Foundation::IAsyncOperationWithProgress<
137
+ winrt::Windows::Web::Http::HttpResponseMessage,
138
+ winrt::Windows::Web::Http::HttpProgress>>{asyncOp};
139
+
140
+ if (asyncOp.Status() == winrt::Windows::Foundation::AsyncStatus::Error ||
141
+ asyncOp.Status() == winrt::Windows::Foundation::AsyncStatus::Canceled) {
142
+ auto errorMessage = FormatHResultError(winrt::hresult_error(asyncOp.ErrorCode()));
143
+ co_return winrt::Microsoft::ReactNative::Composition::ImageFailedResponse(
144
+ winrt::to_hstring("Network request failed: " + errorMessage));
145
+ }
146
+
147
+ winrt::Windows::Web::Http::HttpResponseMessage response = asyncOp.GetResults();
135
148
 
136
149
  if (!response.IsSuccessStatusCode()) {
137
150
  co_return winrt::Microsoft::ReactNative::Composition::ImageFailedResponse(
@@ -136,6 +136,25 @@ void WindowsTextLayoutManager::GetTextLayout(
136
136
  outerFragment.textAttributes.lineHeight * 0.8f));
137
137
  }
138
138
 
139
+ // Set reading direction (RTL/LTR) based on baseWritingDirection
140
+ // Only set reading direction if explicitly specified to avoid breaking existing layouts
141
+ bool isRTL = false;
142
+ if (outerFragment.textAttributes.baseWritingDirection.has_value()) {
143
+ DWRITE_READING_DIRECTION readingDirection = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
144
+ if (*outerFragment.textAttributes.baseWritingDirection == facebook::react::WritingDirection::RightToLeft) {
145
+ readingDirection = DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
146
+ isRTL = true;
147
+ } else if (*outerFragment.textAttributes.baseWritingDirection == facebook::react::WritingDirection::LeftToRight) {
148
+ readingDirection = DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
149
+ isRTL = false;
150
+ } else if (*outerFragment.textAttributes.baseWritingDirection == facebook::react::WritingDirection::Natural) {
151
+ // Natural uses the layout direction from textAttributes
152
+ isRTL = (outerFragment.textAttributes.layoutDirection == facebook::react::LayoutDirection::RightToLeft);
153
+ readingDirection = isRTL ? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT : DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
154
+ }
155
+ winrt::check_hresult(spTextFormat->SetReadingDirection(readingDirection));
156
+ }
157
+
139
158
  // Set text alignment
140
159
  DWRITE_TEXT_ALIGNMENT alignment = DWRITE_TEXT_ALIGNMENT_LEADING;
141
160
  if (outerFragment.textAttributes.alignment) {
@@ -152,9 +171,9 @@ void WindowsTextLayoutManager::GetTextLayout(
152
171
  case facebook::react::TextAlignment::Right:
153
172
  alignment = DWRITE_TEXT_ALIGNMENT_TRAILING;
154
173
  break;
155
- // TODO use LTR values
156
174
  case facebook::react::TextAlignment::Natural:
157
- alignment = DWRITE_TEXT_ALIGNMENT_LEADING;
175
+ // Natural alignment respects reading direction if baseWritingDirection was set
176
+ alignment = isRTL ? DWRITE_TEXT_ALIGNMENT_TRAILING : DWRITE_TEXT_ALIGNMENT_LEADING;
158
177
  break;
159
178
  default:
160
179
  assert(false);
@@ -310,10 +310,6 @@ class ReactNativeWindowsFeatureFlags : public facebook::react::ReactNativeFeatur
310
310
  bool fuseboxEnabledRelease() override {
311
311
  return true; // Enable Fusebox (modern CDP backend) by default for React Native Windows
312
312
  }
313
-
314
- bool fuseboxNetworkInspectionEnabled() override {
315
- return true; // Enable network inspection support in Fusebox
316
- }
317
313
  };
318
314
 
319
315
  //=============================================================================================
@@ -326,10 +322,32 @@ class ReactInspectorHostTargetDelegate : public jsinspector_modern::HostTargetDe
326
322
  ReactInspectorHostTargetDelegate(Mso::WeakPtr<ReactHost> &&reactHost) noexcept : m_reactHost(std::move(reactHost)) {}
327
323
 
328
324
  jsinspector_modern::HostTargetMetadata getMetadata() override {
329
- // TODO: (vmoroz) provide more info
330
- return {
331
- .integrationName = "React Native Windows (Host)",
332
- };
325
+ jsinspector_modern::HostTargetMetadata metadata{};
326
+ metadata.integrationName = "React Native Windows (Host)";
327
+ metadata.platform = "windows";
328
+
329
+ if (Mso::CntPtr<ReactHost> reactHost = m_reactHost.GetStrongPtr()) {
330
+ const ReactOptions &options = reactHost->Options();
331
+ if (!options.Identity.empty()) {
332
+ std::string identity = options.Identity;
333
+ // Replace illegal characters with underscore
334
+ for (char &c : identity) {
335
+ if (c == '\\' || c == '/' || c == ':' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' ||
336
+ c == '|') {
337
+ c = '_';
338
+ }
339
+ }
340
+ metadata.appDisplayName = identity;
341
+ }
342
+ }
343
+
344
+ wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
345
+ DWORD size = MAX_COMPUTERNAME_LENGTH + 1;
346
+ if (GetComputerNameW(computerName, &size)) {
347
+ metadata.deviceName = winrt::to_string(computerName);
348
+ }
349
+
350
+ return metadata;
333
351
  }
334
352
 
335
353
  void onReload(jsinspector_modern::HostTargetDelegate::PageReloadRequest const &request) override {
@@ -630,9 +648,20 @@ void ReactHost::AddInspectorPage() noexcept {
630
648
  jsinspector_modern::InspectorTargetCapabilities capabilities;
631
649
  capabilities.nativePageReloads = true;
632
650
  capabilities.prefersFuseboxFrontend = true;
633
- // TODO: (vmoroz) improve the page name
651
+
652
+ auto metadata = m_inspectorHostTargetDelegate->getMetadata();
653
+ std::string pageName;
654
+ if (metadata.appDisplayName.has_value() && !metadata.appDisplayName.value().empty()) {
655
+ pageName = metadata.appDisplayName.value();
656
+ } else {
657
+ pageName = "React Native Windows (Experimental)";
658
+ }
659
+ if (metadata.deviceName.has_value() && !metadata.deviceName.value().empty()) {
660
+ pageName += " (" + metadata.deviceName.value() + ")";
661
+ }
662
+
634
663
  inspectorPageId = jsinspector_modern::getInspectorInstance().addPage(
635
- "React Native Windows (Experimental)",
664
+ pageName,
636
665
  "Hermes",
637
666
  [weakInspectorHostTarget =
638
667
  std::weak_ptr(m_inspectorHostTarget)](std::unique_ptr<jsinspector_modern::IRemoteConnection> remote)
@@ -10,11 +10,11 @@
10
10
  -->
11
11
  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
12
12
  <PropertyGroup>
13
- <ReactNativeWindowsVersion>0.81.0-preview.1</ReactNativeWindowsVersion>
13
+ <ReactNativeWindowsVersion>0.81.0-preview.10</ReactNativeWindowsVersion>
14
14
  <ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
15
15
  <ReactNativeWindowsMinor>81</ReactNativeWindowsMinor>
16
16
  <ReactNativeWindowsPatch>0</ReactNativeWindowsPatch>
17
17
  <ReactNativeWindowsCanary>false</ReactNativeWindowsCanary>
18
- <ReactNativeWindowsCommitId>c90943314678ce91d624ceba523e50f8d35a5ea5</ReactNativeWindowsCommitId>
18
+ <ReactNativeWindowsCommitId>f8c11e35831ed3a036757abf53f7d3959c186634</ReactNativeWindowsCommitId>
19
19
  </PropertyGroup>
20
20
  </Project>
@@ -146,6 +146,7 @@
146
146
  <AdditionalIncludeDirectories>
147
147
  $(FollyDir);
148
148
  $(FmtDir)include;
149
+ $(FastFloatDir)include;
149
150
  $(ReactNativeDir)\ReactCommon;
150
151
  $(ReactNativeDir)\ReactCommon\callinvoker;
151
152
  $(ReactNativeDir)\ReactCommon\jsi;
@@ -77,8 +77,6 @@ MemoryMappedBuffer::MemoryMappedBuffer(const wchar_t *const filename, uint32_t o
77
77
  throw facebook::jsi::JSINativeException(
78
78
  "MapViewOfFile/MapViewOfFileFromApp failed with last error " + std::to_string(GetLastError()));
79
79
  }
80
-
81
- WerRegisterMemoryBlock(m_fileData.get(), m_fileSize);
82
80
  }
83
81
 
84
82
  size_t MemoryMappedBuffer::size() const {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-windows",
3
- "version": "0.81.0-preview.1",
3
+ "version": "0.81.0-preview.10",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,16 +26,16 @@
26
26
  "@react-native-community/cli": "17.0.0",
27
27
  "@react-native-community/cli-platform-android": "17.0.0",
28
28
  "@react-native-community/cli-platform-ios": "17.0.0",
29
- "@react-native-windows/cli": "0.81.0-preview.1",
29
+ "@react-native-windows/cli": "0.81.0-preview.3",
30
30
  "@react-native/assets": "1.0.0",
31
- "@react-native/assets-registry": "0.81.0-nightly-20250709-6892dde36",
32
- "@react-native/codegen": "0.81.0-nightly-20250709-6892dde36",
33
- "@react-native/community-cli-plugin": "0.81.0-nightly-20250709-6892dde36",
34
- "@react-native/gradle-plugin": "0.81.0-nightly-20250709-6892dde36",
35
- "@react-native/js-polyfills": "0.81.0-nightly-20250709-6892dde36",
36
- "@react-native/normalize-colors": "0.81.0-nightly-20250709-6892dde36",
37
- "@react-native/virtualized-lists": "0.81.0-nightly-20250709-6892dde36",
38
- "@react-native/new-app-screen": "0.81.0-nightly-20250709-6892dde36",
31
+ "@react-native/assets-registry": "0.81.0",
32
+ "@react-native/codegen": "0.81.0",
33
+ "@react-native/community-cli-plugin": "0.81.0",
34
+ "@react-native/gradle-plugin": "0.81.0",
35
+ "@react-native/js-polyfills": "0.81.0",
36
+ "@react-native/normalize-colors": "0.81.0",
37
+ "@react-native/virtualized-lists": "0.81.0",
38
+ "@react-native/new-app-screen": "0.81.0",
39
39
  "abort-controller": "^3.0.0",
40
40
  "anser": "^1.4.9",
41
41
  "ansi-regex": "^5.0.0",
@@ -68,8 +68,8 @@
68
68
  "yargs": "^17.6.2"
69
69
  },
70
70
  "devDependencies": {
71
- "@react-native-windows/codegen": "0.81.0-preview.1",
72
- "@react-native/metro-config": "0.81.0-nightly-20250709-6892dde36",
71
+ "@react-native-windows/codegen": "0.81.0-preview.3",
72
+ "@react-native/metro-config": "0.81.0",
73
73
  "@rnw-scripts/babel-react-native-config": "0.0.0",
74
74
  "@rnw-scripts/eslint-config": "1.2.37",
75
75
  "@rnw-scripts/jest-out-of-tree-snapshot-resolver": "^1.1.41",
@@ -85,14 +85,14 @@
85
85
  "prettier": "2.8.8",
86
86
  "react": "19.1.0",
87
87
  "react-native": "0.81.0-rc.0",
88
- "react-native-platform-override": "^1.9.59",
88
+ "react-native-platform-override": "0.81.0-preview.10",
89
89
  "react-refresh": "^0.14.0",
90
90
  "typescript": "5.0.4"
91
91
  },
92
92
  "peerDependencies": {
93
93
  "@types/react": "^19.1.0",
94
94
  "react": "^19.1.0",
95
- "react-native": "0.81.0-nightly-20250709-6892dde36"
95
+ "react-native": "0.81.0"
96
96
  },
97
97
  "beachball": {
98
98
  "defaultNpmTag": "preview",
@@ -2,8 +2,6 @@ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const exclusionList = require('metro-config/src/defaults/exclusionList');
6
-
7
5
  const rnwPath = fs.realpathSync(
8
6
  path.resolve(require.resolve('react-native-windows/package.json'), '..'),
9
7
  );
@@ -25,7 +23,7 @@ const config = {
25
23
  watchFolders: [rnwPath, rnwRootNodeModules, rnwPackages],
26
24
  // devMode]{{/devMode}}
27
25
  resolver: {
28
- blockList: exclusionList([
26
+ blockList: [
29
27
  // This stops "npx @react-native-community/cli run-windows" from causing the metro server to crash if its already running
30
28
  new RegExp(
31
29
  `${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
@@ -34,7 +32,7 @@ const config = {
34
32
  new RegExp(`${rnwPath}/build/.*`),
35
33
  new RegExp(`${rnwPath}/target/.*`),
36
34
  /.*\.ProjectImports\.zip/,
37
- ]),
35
+ ],
38
36
  //{{#devMode}} [devMode
39
37
  extraNodeModules: {
40
38
  'react-native-windows': rnwPath,
@@ -2,8 +2,6 @@ const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const exclusionList = require('metro-config/src/defaults/exclusionList');
6
-
7
5
  const rnwPath = fs.realpathSync(
8
6
  path.resolve(require.resolve('react-native-windows/package.json'), '..'),
9
7
  );
@@ -25,7 +23,7 @@ const config = {
25
23
  watchFolders: [rnwPath, rnwRootNodeModules, rnwPackages],
26
24
  // devMode]{{/devMode}}
27
25
  resolver: {
28
- blockList: exclusionList([
26
+ blockList: [
29
27
  // This stops "npx @react-native-community/cli run-windows" from causing the metro server to crash if its already running
30
28
  new RegExp(
31
29
  `${path.resolve(__dirname, 'windows').replace(/[/\\]/g, '/')}.*`,
@@ -34,7 +32,7 @@ const config = {
34
32
  new RegExp(`${rnwPath}/build/.*`),
35
33
  new RegExp(`${rnwPath}/target/.*`),
36
34
  /.*\.ProjectImports\.zip/,
37
- ]),
35
+ ],
38
36
  //{{#devMode}} [devMode
39
37
  extraNodeModules: {
40
38
  'react-native-windows': rnwPath,