react-native-windows 0.74.6 → 0.74.8

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 (52) hide show
  1. package/Libraries/ReactNative/AppContainer-dev.js +3 -2
  2. package/Libraries/ReactNative/AppContainer-prod.js +2 -1
  3. package/Libraries/ReactNative/AppContainer.js +2 -0
  4. package/Libraries/ReactNative/AppRegistry.d.ts +7 -0
  5. package/Libraries/ReactNative/AppRegistry.js +8 -0
  6. package/Libraries/ReactNative/renderApplication.js +3 -0
  7. package/Microsoft.ReactNative/AsynchronousEventBeat.cpp +1 -2
  8. package/Microsoft.ReactNative/CompositionHwndHost.idl +1 -1
  9. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +21 -21
  10. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +2 -2
  11. package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.cpp +7 -6
  12. package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.h +1 -1
  13. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +3 -3
  14. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.h +3 -3
  15. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +9 -5
  16. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +2 -0
  17. package/Microsoft.ReactNative/Fabric/Composition/{CompositionRootView.cpp → ReactNativeIsland.cpp} +160 -115
  18. package/Microsoft.ReactNative/Fabric/Composition/{CompositionRootView.h → ReactNativeIsland.h} +25 -20
  19. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +19 -6
  20. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +6 -2
  21. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +2 -2
  22. package/Microsoft.ReactNative/Fabric/Composition/UriImageManager.cpp +82 -17
  23. package/Microsoft.ReactNative/Fabric/Composition/UriImageManager.h +79 -0
  24. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +8 -14
  25. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +4 -3
  26. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +191 -119
  27. package/Microsoft.ReactNative/Fabric/WindowsImageManager.h +11 -0
  28. package/Microsoft.ReactNative/HttpSettings.idl +19 -0
  29. package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +15 -11
  30. package/Microsoft.ReactNative/{CompositionRootView.idl → ReactNativeIsland.idl} +23 -13
  31. package/Microsoft.ReactNative/UriImageManager.idl +35 -17
  32. package/Microsoft.ReactNative/Utils/ImageUtils.cpp +22 -3
  33. package/Microsoft.ReactNative/Utils/ImageUtils.h +3 -1
  34. package/Microsoft.ReactNative/Views/Image/ImageViewManager.cpp +1 -1
  35. package/Microsoft.ReactNative/Views/Image/ReactImage.cpp +13 -4
  36. package/Microsoft.ReactNative/Views/Image/ReactImage.h +4 -2
  37. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  38. package/Shared/Modules/FileReaderModule.cpp +3 -4
  39. package/Shared/Modules/WebSocketModule.cpp +14 -16
  40. package/Shared/Networking/DefaultBlobResource.cpp +6 -14
  41. package/Shared/Networking/NetworkPropertyIds.cpp +60 -0
  42. package/Shared/Networking/NetworkPropertyIds.h +41 -0
  43. package/Shared/Networking/RedirectHttpFilter.cpp +18 -9
  44. package/Shared/Networking/RedirectHttpFilter.h +6 -3
  45. package/Shared/Networking/WinRTHttpResource.cpp +36 -8
  46. package/Shared/Networking/WinRTHttpResource.h +17 -0
  47. package/Shared/Shared.vcxitems +6 -9
  48. package/Shared/Shared.vcxitems.filters +5 -3
  49. package/package.json +1 -1
  50. package/templates/cpp-app/windows/MyApp/MyApp.cpp +5 -4
  51. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootView_emptyimpl.cpp +0 -149
  52. package/Microsoft.ReactNative/Views/ICompositionRootView.h +0 -18
@@ -1,9 +1,10 @@
1
1
  // Copyright (c) Microsoft Corporation.
2
2
  // Licensed under the MIT License.
3
3
  #include "pch.h"
4
- #include "CompositionRootView.h"
5
- #include "CompositionRootView.g.cpp"
4
+ #include "ReactNativeIsland.h"
6
5
  #include "FocusNavigationRequest.g.cpp"
6
+ #include "ReactNativeIsland.g.cpp"
7
+ #include <RootViewSizeChangedEventArgs.g.h>
7
8
 
8
9
  #include <AutoDraw.h>
9
10
  #include <DynamicWriter.h>
@@ -48,7 +49,7 @@ constexpr float loadingTextHorizontalOffset = 48.0f;
48
49
  struct CompositionReactViewInstance
49
50
  : public winrt::implements<CompositionReactViewInstance, winrt::Microsoft::ReactNative::IReactViewInstance> {
50
51
  CompositionReactViewInstance(
51
- winrt::weak_ref<winrt::Microsoft::ReactNative::implementation::CompositionRootView> &&weakRootControl) noexcept;
52
+ winrt::weak_ref<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland> &&weakRootControl) noexcept;
52
53
 
53
54
  void InitRootView(
54
55
  winrt::Microsoft::ReactNative::IReactContext context,
@@ -62,12 +63,12 @@ struct CompositionReactViewInstance
62
63
  Mso::Future<void> PostInUIQueue(TAction &&action) noexcept;
63
64
 
64
65
  private:
65
- winrt::weak_ref<winrt::Microsoft::ReactNative::implementation::CompositionRootView> m_weakRootControl;
66
+ winrt::weak_ref<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland> m_weakRootControl;
66
67
  IReactDispatcher m_uiDispatcher{nullptr};
67
68
  };
68
69
 
69
70
  CompositionReactViewInstance::CompositionReactViewInstance(
70
- winrt::weak_ref<winrt::Microsoft::ReactNative::implementation::CompositionRootView> &&weakRootControl) noexcept
71
+ winrt::weak_ref<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland> &&weakRootControl) noexcept
71
72
  : m_weakRootControl{std::move(weakRootControl)} {}
72
73
 
73
74
  void CompositionReactViewInstance::InitRootView(
@@ -124,14 +125,14 @@ inline Mso::Future<void> CompositionReactViewInstance::PostInUIQueue(TAction &&a
124
125
  return promise.AsFuture();
125
126
  }
126
127
 
127
- CompositionRootView::CompositionRootView() noexcept {}
128
+ ReactNativeIsland::ReactNativeIsland() noexcept {}
128
129
 
129
130
  #ifdef USE_WINUI3
130
- CompositionRootView::CompositionRootView(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept
131
+ ReactNativeIsland::ReactNativeIsland(const winrt::Microsoft::UI::Composition::Compositor &compositor) noexcept
131
132
  : m_compositor(compositor) {}
132
133
  #endif
133
134
 
134
- CompositionRootView::~CompositionRootView() noexcept {
135
+ ReactNativeIsland::~ReactNativeIsland() noexcept {
135
136
  #ifdef USE_WINUI3
136
137
  if (m_island && m_island.IsConnected()) {
137
138
  m_island.AutomationProviderRequested(m_islandAutomationProviderRequestedToken);
@@ -144,11 +145,11 @@ CompositionRootView::~CompositionRootView() noexcept {
144
145
  }
145
146
  }
146
147
 
147
- ReactNative::IReactViewHost CompositionRootView::ReactViewHost() noexcept {
148
+ ReactNative::IReactViewHost ReactNativeIsland::ReactViewHost() noexcept {
148
149
  return m_reactViewHost;
149
150
  }
150
151
 
151
- void CompositionRootView::ReactViewHost(winrt::Microsoft::ReactNative::IReactViewHost const &value) noexcept {
152
+ void ReactNativeIsland::ReactViewHost(winrt::Microsoft::ReactNative::IReactViewHost const &value) noexcept {
152
153
  if (m_reactViewHost == value) {
153
154
  return;
154
155
  }
@@ -165,16 +166,16 @@ void CompositionRootView::ReactViewHost(winrt::Microsoft::ReactNative::IReactVie
165
166
  }
166
167
  }
167
168
 
168
- winrt::Microsoft::UI::Composition::Visual CompositionRootView::RootVisual() noexcept {
169
+ winrt::Microsoft::UI::Composition::Visual ReactNativeIsland::RootVisual() noexcept {
169
170
  return winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::InnerVisual(
170
171
  m_rootVisual);
171
172
  }
172
173
 
173
- winrt::Microsoft::ReactNative::Composition::Experimental::IVisual CompositionRootView::InternalRootVisual() noexcept {
174
+ winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ReactNativeIsland::InternalRootVisual() noexcept {
174
175
  return m_rootVisual;
175
176
  }
176
177
 
177
- void CompositionRootView::InternalRootVisual(
178
+ void ReactNativeIsland::InternalRootVisual(
178
179
  winrt::Microsoft::ReactNative::Composition::Experimental::IVisual const &value) noexcept {
179
180
  if (m_rootVisual != value) {
180
181
  assert(!m_rootVisual);
@@ -183,21 +184,21 @@ void CompositionRootView::InternalRootVisual(
183
184
  }
184
185
  }
185
186
 
186
- void CompositionRootView::AddRenderedVisual(
187
+ void ReactNativeIsland::AddRenderedVisual(
187
188
  const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept {
188
189
  assert(!m_hasRenderedVisual);
189
190
  InternalRootVisual().InsertAt(visual, 0);
190
191
  m_hasRenderedVisual = true;
191
192
  }
192
193
 
193
- void CompositionRootView::RemoveRenderedVisual(
194
+ void ReactNativeIsland::RemoveRenderedVisual(
194
195
  const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept {
195
196
  assert(m_hasRenderedVisual);
196
197
  InternalRootVisual().Remove(visual);
197
198
  m_hasRenderedVisual = false;
198
199
  }
199
200
 
200
- bool CompositionRootView::TrySetFocus() noexcept {
201
+ bool ReactNativeIsland::TrySetFocus() noexcept {
201
202
  #ifdef USE_WINUI3
202
203
  if (m_island && m_island.IsConnected()) {
203
204
  auto focusController = winrt::Microsoft::UI::Input::InputFocusController::GetForIsland(m_island);
@@ -207,23 +208,23 @@ bool CompositionRootView::TrySetFocus() noexcept {
207
208
  return false;
208
209
  }
209
210
 
210
- winrt::Windows::Foundation::Size CompositionRootView::Size() noexcept {
211
+ winrt::Windows::Foundation::Size ReactNativeIsland::Size() noexcept {
211
212
  return m_size;
212
213
  }
213
214
 
214
- void CompositionRootView::Size(winrt::Windows::Foundation::Size value) noexcept {
215
+ void ReactNativeIsland::Size(winrt::Windows::Foundation::Size value) noexcept {
215
216
  m_size = value;
216
217
  UpdateRootVisualSize();
217
218
  }
218
219
 
219
- void CompositionRootView::UpdateRootVisualSize() noexcept {
220
+ void ReactNativeIsland::UpdateRootVisualSize() noexcept {
220
221
  if (m_rootVisual)
221
222
  m_rootVisual.Size({m_size.Width * m_scaleFactor, m_size.Height * m_scaleFactor});
222
223
 
223
224
  UpdateLoadingVisualSize();
224
225
  }
225
226
 
226
- void CompositionRootView::UpdateLoadingVisualSize() noexcept {
227
+ void ReactNativeIsland::UpdateLoadingVisualSize() noexcept {
227
228
  if (m_loadingVisual) {
228
229
  auto drawingSurface = CreateLoadingVisualBrush();
229
230
  m_loadingVisual.Brush(drawingSurface);
@@ -237,11 +238,11 @@ void CompositionRootView::UpdateLoadingVisualSize() noexcept {
237
238
  }
238
239
  }
239
240
 
240
- float CompositionRootView::ScaleFactor() noexcept {
241
+ float ReactNativeIsland::ScaleFactor() noexcept {
241
242
  return m_scaleFactor;
242
243
  }
243
244
 
244
- void CompositionRootView::ScaleFactor(float value) noexcept {
245
+ void ReactNativeIsland::ScaleFactor(float value) noexcept {
245
246
  if (m_scaleFactor != value) {
246
247
  m_scaleFactor = value;
247
248
  // Lifted ContentIslands apply a scale that we need to reverse
@@ -253,15 +254,15 @@ void CompositionRootView::ScaleFactor(float value) noexcept {
253
254
  }
254
255
  }
255
256
 
256
- int64_t CompositionRootView::RootTag() const noexcept {
257
+ int64_t ReactNativeIsland::RootTag() const noexcept {
257
258
  return m_rootTag;
258
259
  }
259
260
 
260
- winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader CompositionRootView::Resources() noexcept {
261
+ winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader ReactNativeIsland::Resources() noexcept {
261
262
  return m_resources;
262
263
  }
263
264
 
264
- void CompositionRootView::Resources(
265
+ void ReactNativeIsland::Resources(
265
266
  const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept {
266
267
  m_resources = resources;
267
268
 
@@ -270,7 +271,7 @@ void CompositionRootView::Resources(
270
271
  }
271
272
  }
272
273
 
273
- winrt::Microsoft::ReactNative::Composition::Theme CompositionRootView::Theme() noexcept {
274
+ winrt::Microsoft::ReactNative::Composition::Theme ReactNativeIsland::Theme() noexcept {
274
275
  if (!m_theme) {
275
276
  assert(m_context);
276
277
  if (m_resources) {
@@ -282,7 +283,7 @@ winrt::Microsoft::ReactNative::Composition::Theme CompositionRootView::Theme() n
282
283
  return m_theme;
283
284
  }
284
285
 
285
- void CompositionRootView::Theme(const winrt::Microsoft::ReactNative::Composition::Theme &value) noexcept {
286
+ void ReactNativeIsland::Theme(const winrt::Microsoft::ReactNative::Composition::Theme &value) noexcept {
286
287
  if (value == m_theme)
287
288
  return;
288
289
 
@@ -314,7 +315,7 @@ void CompositionRootView::Theme(const winrt::Microsoft::ReactNative::Composition
314
315
  }
315
316
  }
316
317
 
317
- winrt::IInspectable CompositionRootView::GetUiaProvider() noexcept {
318
+ winrt::IInspectable ReactNativeIsland::GetUiaProvider() noexcept {
318
319
  if (m_uiaProvider == nullptr) {
319
320
  m_uiaProvider =
320
321
  winrt::make<winrt::Microsoft::ReactNative::implementation::CompositionRootAutomationProvider>(*this);
@@ -330,31 +331,11 @@ winrt::IInspectable CompositionRootView::GetUiaProvider() noexcept {
330
331
  return m_uiaProvider;
331
332
  }
332
333
 
333
- std::string CompositionRootView::JSComponentName() const noexcept {
334
- return to_string(m_reactViewOptions.ComponentName());
335
- }
336
-
337
- int64_t CompositionRootView::GetActualHeight() const noexcept {
338
- return static_cast<int64_t>(m_size.Height);
339
- }
340
-
341
- int64_t CompositionRootView::GetActualWidth() const noexcept {
342
- return static_cast<int64_t>(m_size.Width);
343
- }
344
-
345
- int64_t CompositionRootView::GetTag() const noexcept {
346
- return m_rootTag;
347
- }
348
-
349
- void CompositionRootView::SetTag(int64_t tag) noexcept {
350
- m_rootTag = tag;
351
- }
352
-
353
- void CompositionRootView::SetWindow(uint64_t hwnd) noexcept {
334
+ void ReactNativeIsland::SetWindow(uint64_t hwnd) noexcept {
354
335
  m_hwnd = reinterpret_cast<HWND>(hwnd);
355
336
  }
356
337
 
357
- int64_t CompositionRootView::SendMessage(uint32_t msg, uint64_t wParam, int64_t lParam) noexcept {
338
+ int64_t ReactNativeIsland::SendMessage(uint32_t msg, uint64_t wParam, int64_t lParam) noexcept {
358
339
  if (m_rootTag == -1)
359
340
  return 0;
360
341
 
@@ -370,7 +351,7 @@ int64_t CompositionRootView::SendMessage(uint32_t msg, uint64_t wParam, int64_t
370
351
  return 0;
371
352
  }
372
353
 
373
- bool CompositionRootView::CapturePointer(
354
+ bool ReactNativeIsland::CapturePointer(
374
355
  const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
375
356
  facebook::react::Tag tag) noexcept {
376
357
  if (m_hwnd) {
@@ -379,7 +360,7 @@ bool CompositionRootView::CapturePointer(
379
360
  return m_CompositionEventHandler->CapturePointer(pointer, tag);
380
361
  }
381
362
 
382
- void CompositionRootView::ReleasePointerCapture(
363
+ void ReactNativeIsland::ReleasePointerCapture(
383
364
  const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
384
365
  facebook::react::Tag tag) noexcept {
385
366
  if (m_CompositionEventHandler->ReleasePointerCapture(pointer, tag)) {
@@ -391,7 +372,7 @@ void CompositionRootView::ReleasePointerCapture(
391
372
  }
392
373
  }
393
374
 
394
- void CompositionRootView::InitRootView(
375
+ void ReactNativeIsland::InitRootView(
395
376
  winrt::Microsoft::ReactNative::IReactContext &&context,
396
377
  winrt::Microsoft::ReactNative::ReactViewOptions &&viewOptions) noexcept {
397
378
  m_uiDispatcher = context.Properties()
@@ -412,13 +393,13 @@ void CompositionRootView::InitRootView(
412
393
  m_isInitialized = true;
413
394
  }
414
395
 
415
- void CompositionRootView::UpdateRootView() noexcept {
396
+ void ReactNativeIsland::UpdateRootView() noexcept {
416
397
  VerifyElseCrash(m_uiDispatcher.HasThreadAccess());
417
398
  VerifyElseCrash(m_isInitialized);
418
399
  UpdateRootViewInternal();
419
400
  }
420
401
 
421
- void CompositionRootView::UpdateRootViewInternal() noexcept {
402
+ void ReactNativeIsland::UpdateRootViewInternal() noexcept {
422
403
  switch (m_context.Handle().LoadingState()) {
423
404
  case winrt::Microsoft::ReactNative::LoadingState::Loading:
424
405
  ShowInstanceLoading();
@@ -434,7 +415,7 @@ void CompositionRootView::UpdateRootViewInternal() noexcept {
434
415
  }
435
416
  }
436
417
 
437
- void CompositionRootView::UninitRootView() noexcept {
418
+ void ReactNativeIsland::UninitRootView() noexcept {
438
419
  if (!m_isInitialized) {
439
420
  return;
440
421
  }
@@ -445,7 +426,7 @@ void CompositionRootView::UninitRootView() noexcept {
445
426
 
446
427
  auto uiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
447
428
  winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()));
448
- uiManager->stopSurface(static_cast<facebook::react::SurfaceId>(GetTag()));
429
+ uiManager->stopSurface(static_cast<facebook::react::SurfaceId>(RootTag()));
449
430
 
450
431
  // This is needed to ensure that the unmount JS logic is completed before the the instance is shutdown during
451
432
  // instance destruction. Aligns with similar code in ReactInstanceWin::DetachRootView for paper Future: Instead this
@@ -465,7 +446,7 @@ void CompositionRootView::UninitRootView() noexcept {
465
446
  m_isInitialized = false;
466
447
  }
467
448
 
468
- void CompositionRootView::ClearLoadingUI() noexcept {
449
+ void ReactNativeIsland::ClearLoadingUI() noexcept {
469
450
  if (!m_loadingVisual)
470
451
  return;
471
452
 
@@ -475,37 +456,103 @@ void CompositionRootView::ClearLoadingUI() noexcept {
475
456
  m_loadingActivityVisual = nullptr;
476
457
  }
477
458
 
478
- void CompositionRootView::EnsureLoadingUI() noexcept {}
459
+ void ReactNativeIsland::EnsureLoadingUI() noexcept {}
479
460
 
480
- void CompositionRootView::ShowInstanceLoaded() noexcept {
461
+ void ReactNativeIsland::ShowInstanceLoaded() noexcept {
481
462
  if (m_rootVisual) {
482
463
  ClearLoadingUI();
483
464
 
484
465
  auto uiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
485
466
  winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()));
486
467
 
487
- auto rootTag = ::Microsoft::ReactNative::getNextRootViewTag();
488
- SetTag(rootTag);
468
+ m_rootTag = ::Microsoft::ReactNative::getNextRootViewTag();
489
469
  auto initProps = DynamicWriter::ToDynamic(Mso::Copy(m_reactViewOptions.InitialProps()));
490
470
  if (initProps.isNull()) {
491
471
  initProps = folly::dynamic::object();
492
472
  }
493
473
  initProps["concurrentRoot"] = true;
494
- uiManager->startSurface(*this, rootTag, JSComponentName(), initProps);
474
+ uiManager->startSurface(
475
+ *this,
476
+ static_cast<facebook::react::SurfaceId>(m_rootTag),
477
+ m_layoutConstraints,
478
+ to_string(m_reactViewOptions.ComponentName()),
479
+ initProps);
495
480
 
496
481
  m_isJSViewAttached = true;
497
482
  }
498
483
  }
499
484
 
500
- void CompositionRootView::ShowInstanceError() noexcept {
485
+ facebook::react::AttributedStringBox CreateLoadingAttributedString() noexcept {
486
+ auto attributedString = facebook::react::AttributedString{};
487
+ auto fragment = facebook::react::AttributedString::Fragment{};
488
+ fragment.string = "Loading";
489
+ fragment.textAttributes.fontSize = loadingBarFontSize;
490
+ attributedString.appendFragment(fragment);
491
+ return facebook::react::AttributedStringBox{attributedString};
492
+ }
493
+
494
+ facebook::react::Size MeasureLoading(const facebook::react::LayoutConstraints &layoutConstraints, float scaleFactor) {
495
+ auto attributedStringBox = CreateLoadingAttributedString();
496
+ winrt::com_ptr<::IDWriteTextLayout> textLayout;
497
+ facebook::react::TextLayoutManager::GetTextLayout(
498
+ attributedStringBox, {} /*paragraphAttributes*/, layoutConstraints, textLayout);
499
+
500
+ DWRITE_TEXT_METRICS tm;
501
+ textLayout->GetMetrics(&tm);
502
+
503
+ return layoutConstraints.clamp(
504
+ {loadingActivityHorizontalOffset * scaleFactor + tm.width, loadingBarHeight * scaleFactor});
505
+ }
506
+
507
+ winrt::event_token ReactNativeIsland::SizeChanged(
508
+ winrt::Windows::Foundation::EventHandler<winrt::Microsoft::ReactNative::RootViewSizeChangedEventArgs> const
509
+ &handler) noexcept {
510
+ return m_sizeChangedEvent.add(handler);
511
+ }
512
+
513
+ void ReactNativeIsland::SizeChanged(winrt::event_token const &token) noexcept {
514
+ m_sizeChangedEvent.remove(token);
515
+ }
516
+
517
+ struct RootViewSizeChangedEventArgs : RootViewSizeChangedEventArgsT<RootViewSizeChangedEventArgs> {
518
+ RootViewSizeChangedEventArgs(winrt::Windows::Foundation::Size size) : m_size(size) {}
519
+ winrt::Windows::Foundation::Size Size() const noexcept {
520
+ return m_size;
521
+ }
522
+
523
+ private:
524
+ const winrt::Windows::Foundation::Size m_size;
525
+ };
526
+
527
+ void ReactNativeIsland::NotifySizeChanged() noexcept {
528
+ auto oldSize = m_size;
529
+ facebook::react::Size size;
530
+ auto rootComponentView = GetComponentView();
531
+ if (rootComponentView) {
532
+ size = rootComponentView->layoutMetrics().frame.size;
533
+ } else if (m_loadingVisual) {
534
+ size = MeasureLoading(m_layoutConstraints, m_scaleFactor);
535
+ }
536
+
537
+ m_size = {size.width, size.height};
538
+ UpdateRootVisualSize();
539
+ if (oldSize != m_size) {
540
+ m_sizeChangedEvent(*this, winrt::make<RootViewSizeChangedEventArgs>(m_size));
541
+ }
542
+ }
543
+
544
+ void ReactNativeIsland::ShowInstanceError() noexcept {
501
545
  ClearLoadingUI();
502
546
  }
503
547
 
504
- Composition::Experimental::IDrawingSurfaceBrush CompositionRootView::CreateLoadingVisualBrush() noexcept {
548
+ Composition::Experimental::IDrawingSurfaceBrush ReactNativeIsland::CreateLoadingVisualBrush() noexcept {
505
549
  auto compContext =
506
550
  winrt::Microsoft::ReactNative::Composition::implementation::CompositionUIService::GetCompositionContext(
507
551
  m_context.Properties().Handle());
508
552
 
553
+ if (m_size.Height == 0 || m_size.Width == 0)
554
+ return nullptr;
555
+
509
556
  winrt::Windows::Foundation::Size surfaceSize = {
510
557
  m_size.Width * m_scaleFactor, std::min(m_size.Height, loadingBarHeight) * m_scaleFactor};
511
558
  auto drawingSurface = compContext.CreateDrawingSurfaceBrush(
@@ -523,12 +570,7 @@ Composition::Experimental::IDrawingSurfaceBrush CompositionRootView::CreateLoadi
523
570
  constraints.maximumSize.width = std::max(0.0f, m_size.Width - loadingTextHorizontalOffset);
524
571
  constraints.maximumSize.height = std::max(0.0f, m_size.Height - loadingBarHeight);
525
572
 
526
- auto attributedString = facebook::react::AttributedString{};
527
- auto fragment = facebook::react::AttributedString::Fragment{};
528
- fragment.string = "Loading";
529
- fragment.textAttributes.fontSize = loadingBarFontSize;
530
- attributedString.appendFragment(fragment);
531
- auto attributedStringBox = facebook::react::AttributedStringBox{attributedString};
573
+ auto attributedStringBox = CreateLoadingAttributedString();
532
574
 
533
575
  auto textAttributes = facebook::react::TextAttributes{};
534
576
  textAttributes.foregroundColor = facebook::react::whiteColor();
@@ -558,7 +600,7 @@ Composition::Experimental::IDrawingSurfaceBrush CompositionRootView::CreateLoadi
558
600
  return drawingSurface;
559
601
  }
560
602
 
561
- void CompositionRootView::ShowInstanceLoading() noexcept {
603
+ void ReactNativeIsland::ShowInstanceLoading() noexcept {
562
604
  if (!Mso::React::ReactOptions::UseDeveloperSupport(m_context.Properties().Handle()))
563
605
  return;
564
606
 
@@ -569,10 +611,7 @@ void CompositionRootView::ShowInstanceLoading() noexcept {
569
611
  winrt::Microsoft::ReactNative::Composition::implementation::CompositionUIService::GetCompositionContext(
570
612
  m_context.Properties().Handle());
571
613
 
572
- auto drawingSurface = CreateLoadingVisualBrush();
573
-
574
614
  m_loadingVisual = compContext.CreateSpriteVisual();
575
- m_loadingVisual.Brush(drawingSurface);
576
615
 
577
616
  auto foregroundBrush = compContext.CreateColorBrush({255, 255, 255, 255});
578
617
 
@@ -580,14 +619,28 @@ void CompositionRootView::ShowInstanceLoading() noexcept {
580
619
  m_loadingActivityVisual.Brush(foregroundBrush);
581
620
  m_loadingVisual.InsertAt(m_loadingActivityVisual, 0);
582
621
 
622
+ NotifySizeChanged();
583
623
  UpdateLoadingVisualSize();
584
624
 
585
625
  InternalRootVisual().InsertAt(m_loadingVisual, m_hasRenderedVisual ? 1 : 0);
586
626
  }
587
627
 
588
- winrt::Windows::Foundation::Size CompositionRootView::Measure(
589
- winrt::Windows::Foundation::Size const &availableSize) const {
590
- winrt::Windows::Foundation::Size size{0.0f, 0.0f};
628
+ void ApplyConstraints(
629
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraintsIn,
630
+ facebook::react::LayoutConstraints &layoutConstraintsOut) noexcept {
631
+ layoutConstraintsOut.minimumSize = {layoutConstraintsIn.MinimumSize.Width, layoutConstraintsIn.MinimumSize.Height};
632
+ layoutConstraintsOut.maximumSize = {layoutConstraintsIn.MaximumSize.Width, layoutConstraintsIn.MaximumSize.Height};
633
+ layoutConstraintsOut.layoutDirection =
634
+ static_cast<facebook::react::LayoutDirection>(layoutConstraintsIn.LayoutDirection);
635
+ }
636
+
637
+ winrt::Windows::Foundation::Size ReactNativeIsland::Measure(
638
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
639
+ const winrt::Windows::Foundation::Point &viewportOffset) const noexcept {
640
+ facebook::react::Size size{0, 0};
641
+
642
+ facebook::react::LayoutConstraints constraints;
643
+ ApplyConstraints(layoutConstraints, constraints);
591
644
 
592
645
  if (m_isInitialized && m_rootTag != -1) {
593
646
  if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
@@ -596,65 +649,57 @@ winrt::Windows::Foundation::Size CompositionRootView::Measure(
596
649
  // TODO scaling factor
597
650
  context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
598
651
  context.fontSizeMultiplier = static_cast<facebook::react::Float>(m_scaleFactor);
652
+ context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
599
653
 
600
- facebook::react::LayoutConstraints constraints;
601
- // TODO should support MinHeight/MinWidth
602
- constraints.minimumSize.height = static_cast<facebook::react::Float>(0.0f);
603
- constraints.minimumSize.width = static_cast<facebook::react::Float>(0.0f);
604
-
605
- // TODO should support MaxHeight/MaxWidth props?
606
- constraints.minimumSize.height = constraints.maximumSize.height =
607
- static_cast<facebook::react::Float>(availableSize.Height);
608
- constraints.minimumSize.width = constraints.maximumSize.width =
609
- static_cast<facebook::react::Float>(availableSize.Width);
610
- // TODO get RTL
611
- constraints.layoutDirection = facebook::react::LayoutDirection::LeftToRight;
612
-
613
- auto yogaSize =
614
- fabricuiManager->measureSurface(static_cast<facebook::react::SurfaceId>(m_rootTag), constraints, context);
615
- return {std::min(yogaSize.width, availableSize.Width), std::min(yogaSize.height, availableSize.Height)};
654
+ size = fabricuiManager->measureSurface(static_cast<facebook::react::SurfaceId>(m_rootTag), constraints, context);
616
655
  }
656
+ } else if (m_loadingVisual) {
657
+ size = MeasureLoading(constraints, m_scaleFactor);
617
658
  }
618
659
 
619
- return size;
660
+ auto clampedSize = constraints.clamp(size);
661
+ return {clampedSize.width, clampedSize.height};
620
662
  }
621
663
 
622
- winrt::Windows::Foundation::Size CompositionRootView::Arrange(winrt::Windows::Foundation::Size finalSize) const {
664
+ void ReactNativeIsland::Arrange(
665
+ const winrt::Microsoft::ReactNative::LayoutConstraints &layoutConstraints,
666
+ const winrt::Windows::Foundation::Point &viewportOffset) noexcept {
667
+ ApplyConstraints(layoutConstraints, m_layoutConstraints);
668
+
623
669
  if (m_isInitialized && m_rootTag != -1) {
624
670
  if (auto fabricuiManager = ::Microsoft::ReactNative::FabricUIManager::FromProperties(
625
671
  winrt::Microsoft::ReactNative::ReactPropertyBag(m_context.Properties()))) {
626
672
  facebook::react::LayoutContext context;
627
673
  context.pointScaleFactor = static_cast<facebook::react::Float>(m_scaleFactor);
628
674
  context.fontSizeMultiplier = static_cast<facebook::react::Float>(m_scaleFactor);
629
-
630
- facebook::react::LayoutConstraints constraints;
631
- // TODO should support MinHeight/MinWidth
632
- constraints.minimumSize.height = static_cast<facebook::react::Float>(0.0f);
633
- constraints.minimumSize.width = static_cast<facebook::react::Float>(0.0f);
634
-
635
- // TODO should support MaxHeight/MaxWidth props?
636
- constraints.minimumSize.height = constraints.maximumSize.height =
637
- static_cast<facebook::react::Float>(finalSize.Height);
638
- constraints.minimumSize.width = constraints.maximumSize.width =
639
- static_cast<facebook::react::Float>(finalSize.Width);
640
- // TODO get RTL
641
- constraints.layoutDirection = facebook::react::LayoutDirection::LeftToRight;
675
+ context.viewportOffset = {viewportOffset.X, viewportOffset.Y};
642
676
 
643
677
  fabricuiManager->constraintSurfaceLayout(
644
- static_cast<facebook::react::SurfaceId>(m_rootTag), constraints, context);
678
+ static_cast<facebook::react::SurfaceId>(m_rootTag), m_layoutConstraints, context);
645
679
  }
680
+ } else if (m_loadingVisual) {
681
+ // TODO: Resize to align loading
682
+ auto s = m_layoutConstraints.clamp(MeasureLoading(m_layoutConstraints, m_scaleFactor));
683
+ NotifySizeChanged();
646
684
  }
647
- return finalSize;
648
685
  }
649
686
 
650
687
  #ifdef USE_WINUI3
651
- winrt::Microsoft::UI::Content::ContentIsland CompositionRootView::Island() noexcept {
688
+ winrt::Microsoft::UI::Content::ContentIsland ReactNativeIsland::Island() {
652
689
  if (!m_compositor) {
653
690
  return nullptr;
654
691
  }
655
692
 
656
693
  if (!m_island) {
657
- auto rootVisual = m_compositor.CreateSpriteVisual();
694
+ winrt::Microsoft::UI::Composition::SpriteVisual rootVisual{nullptr};
695
+ try {
696
+ rootVisual = m_compositor.CreateSpriteVisual();
697
+ } catch (const winrt::hresult_error &e) {
698
+ // If the compositor has been shutdown, then we shouldn't attempt to initialize the island
699
+ if (e.code() == RO_E_CLOSED)
700
+ return nullptr;
701
+ throw e;
702
+ }
658
703
 
659
704
  InternalRootVisual(
660
705
  winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::CreateVisual(
@@ -690,7 +735,7 @@ winrt::Microsoft::UI::Content::ContentIsland CompositionRootView::Island() noexc
690
735
  #endif
691
736
 
692
737
  winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *
693
- CompositionRootView::GetComponentView() noexcept {
738
+ ReactNativeIsland::GetComponentView() noexcept {
694
739
  if (!m_context || m_context.Handle().LoadingState() != winrt::Microsoft::ReactNative::LoadingState::Loaded ||
695
740
  m_rootTag == -1)
696
741
  return nullptr;
@@ -706,7 +751,7 @@ CompositionRootView::GetComponentView() noexcept {
706
751
  return nullptr;
707
752
  }
708
753
 
709
- winrt::Microsoft::ReactNative::FocusNavigationResult CompositionRootView::NavigateFocus(
754
+ winrt::Microsoft::ReactNative::FocusNavigationResult ReactNativeIsland::NavigateFocus(
710
755
  const winrt::Microsoft::ReactNative::FocusNavigationRequest &request) noexcept {
711
756
  if (auto view = GetComponentView()) {
712
757
  return winrt::make<winrt::Microsoft::ReactNative::implementation::FocusNavigationResult>(