react-native-windows 0.75.10 → 0.75.12

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 (85) hide show
  1. package/Libraries/Modal/Modal.windows.js +352 -0
  2. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +26 -46
  3. package/Microsoft.ReactNative/Fabric/ComponentView.h +6 -19
  4. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +160 -3
  5. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +7 -0
  6. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +15 -17
  7. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +6 -3
  8. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +9 -2
  9. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +2 -1
  10. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +59 -9
  11. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.h +2 -0
  12. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +78 -30
  13. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +21 -1
  14. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +8 -1
  15. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +3 -0
  16. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +25 -0
  17. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  18. package/PropertySheets/React.Cpp.props +6 -0
  19. package/codegen/NativeAccessibilityInfoSpec.g.h +1 -0
  20. package/codegen/NativeAccessibilityManagerSpec.g.h +1 -0
  21. package/codegen/NativeActionSheetManagerSpec.g.h +1 -0
  22. package/codegen/NativeAlertManagerSpec.g.h +1 -0
  23. package/codegen/NativeAnimatedModuleSpec.g.h +1 -0
  24. package/codegen/NativeAnimatedTurboModuleSpec.g.h +1 -0
  25. package/codegen/NativeAppStateSpec.g.h +1 -0
  26. package/codegen/NativeAppThemeSpec.g.h +1 -0
  27. package/codegen/NativeAppearanceSpec.g.h +1 -0
  28. package/codegen/NativeBlobModuleSpec.g.h +1 -0
  29. package/codegen/NativeBugReportingSpec.g.h +1 -0
  30. package/codegen/NativeClipboardSpec.g.h +1 -0
  31. package/codegen/NativeDOMSpec.g.h +1 -0
  32. package/codegen/NativeDevLoadingViewSpec.g.h +1 -0
  33. package/codegen/NativeDevMenuSpec.g.h +1 -0
  34. package/codegen/NativeDevSettingsSpec.g.h +1 -0
  35. package/codegen/NativeDevToolsSettingsManagerSpec.g.h +1 -0
  36. package/codegen/NativeDeviceEventManagerSpec.g.h +1 -0
  37. package/codegen/NativeDeviceInfoSpec.g.h +1 -0
  38. package/codegen/NativeDialogManagerAndroidSpec.g.h +1 -0
  39. package/codegen/NativeDialogManagerWindowsSpec.g.h +1 -0
  40. package/codegen/NativeExceptionsManagerSpec.g.h +1 -0
  41. package/codegen/NativeFileReaderModuleSpec.g.h +1 -0
  42. package/codegen/NativeFrameRateLoggerSpec.g.h +1 -0
  43. package/codegen/NativeHeadlessJsTaskSupportSpec.g.h +1 -0
  44. package/codegen/NativeI18nManagerSpec.g.h +1 -0
  45. package/codegen/NativeIdleCallbacksSpec.g.h +1 -0
  46. package/codegen/NativeImageEditorSpec.g.h +1 -0
  47. package/codegen/NativeImageLoaderAndroidSpec.g.h +1 -0
  48. package/codegen/NativeImageLoaderIOSSpec.g.h +1 -0
  49. package/codegen/NativeImageStoreAndroidSpec.g.h +1 -0
  50. package/codegen/NativeImageStoreIOSSpec.g.h +1 -0
  51. package/codegen/NativeIntentAndroidSpec.g.h +1 -0
  52. package/codegen/NativeIntersectionObserverSpec.g.h +1 -0
  53. package/codegen/NativeJSCHeapCaptureSpec.g.h +1 -0
  54. package/codegen/NativeJSCSamplingProfilerSpec.g.h +1 -0
  55. package/codegen/NativeKeyboardObserverSpec.g.h +1 -0
  56. package/codegen/NativeLinkingManagerSpec.g.h +1 -0
  57. package/codegen/NativeLogBoxSpec.g.h +1 -0
  58. package/codegen/NativeMicrotasksSpec.g.h +1 -0
  59. package/codegen/NativeModalManagerSpec.g.h +1 -0
  60. package/codegen/NativeMutationObserverSpec.g.h +1 -0
  61. package/codegen/NativeNetworkingAndroidSpec.g.h +1 -0
  62. package/codegen/NativeNetworkingIOSSpec.g.h +1 -0
  63. package/codegen/NativePerformanceObserverSpec.g.h +1 -0
  64. package/codegen/NativePerformanceSpec.g.h +1 -0
  65. package/codegen/NativePermissionsAndroidSpec.g.h +1 -0
  66. package/codegen/NativePlatformConstantsAndroidSpec.g.h +1 -0
  67. package/codegen/NativePlatformConstantsIOSSpec.g.h +1 -0
  68. package/codegen/NativePlatformConstantsWindowsSpec.g.h +1 -0
  69. package/codegen/NativePushNotificationManagerIOSSpec.g.h +1 -0
  70. package/codegen/NativeReactNativeFeatureFlagsSpec.g.h +1 -0
  71. package/codegen/NativeRedBoxSpec.g.h +1 -0
  72. package/codegen/NativeSampleTurboModuleSpec.g.h +1 -0
  73. package/codegen/NativeSegmentFetcherSpec.g.h +1 -0
  74. package/codegen/NativeSettingsManagerSpec.g.h +1 -0
  75. package/codegen/NativeShareModuleSpec.g.h +1 -0
  76. package/codegen/NativeSoundManagerSpec.g.h +1 -0
  77. package/codegen/NativeSourceCodeSpec.g.h +1 -0
  78. package/codegen/NativeStatusBarManagerAndroidSpec.g.h +1 -0
  79. package/codegen/NativeStatusBarManagerIOSSpec.g.h +1 -0
  80. package/codegen/NativeTimingSpec.g.h +1 -0
  81. package/codegen/NativeToastAndroidSpec.g.h +1 -0
  82. package/codegen/NativeUIManagerSpec.g.h +1 -0
  83. package/codegen/NativeVibrationSpec.g.h +1 -0
  84. package/codegen/NativeWebSocketModuleSpec.g.h +1 -0
  85. package/package.json +3 -3
@@ -12,15 +12,18 @@
12
12
  #include <Views/ShadowNodeBase.h>
13
13
  #include <windows.h>
14
14
  #include <windowsx.h>
15
+ #include <winrt/Windows.UI.Core.h>
15
16
  #include <winrt/Windows.UI.Input.h>
16
17
  #include "Composition.Input.h"
17
18
  #include "CompositionViewComponentView.h"
18
19
  #include "ReactNativeIsland.h"
19
20
  #include "RootComponentView.h"
20
21
 
21
- #ifdef USE_WINUI3
22
- #include <winrt/Microsoft.UI.Input.h>
23
- #endif
22
+ namespace ABI::Microsoft::UI::Input {
23
+ struct IInputCursor;
24
+ }
25
+
26
+ #include <Microsoft.UI.Input.InputCursor.Interop.h>
24
27
 
25
28
  namespace Microsoft::ReactNative {
26
29
 
@@ -328,6 +331,11 @@ CompositionEventHandler::~CompositionEventHandler() {
328
331
  }
329
332
  }
330
333
  #endif
334
+
335
+ if (m_hcursorOwned) {
336
+ ::DestroyCursor(m_hcursor);
337
+ m_hcursor = nullptr;
338
+ }
331
339
  }
332
340
 
333
341
  facebook::react::SurfaceId CompositionEventHandler::SurfaceId() const noexcept {
@@ -507,6 +515,10 @@ int64_t CompositionEventHandler::SendMessage(HWND hwnd, uint32_t msg, uint64_t w
507
515
  }
508
516
  break;
509
517
  }
518
+ case WM_SETCURSOR: {
519
+ UpdateCursor();
520
+ return 1;
521
+ }
510
522
  }
511
523
 
512
524
  return 0;
@@ -753,6 +765,151 @@ void CompositionEventHandler::HandleIncomingPointerEvent(
753
765
  hoveredViews.emplace_back(ReactTaggedView(componentViewDescriptor.view));
754
766
  }
755
767
  m_currentlyHoveredViewsPerPointer[pointerId] = std::move(hoveredViews);
768
+
769
+ if (IsMousePointerEvent(event)) {
770
+ UpdateCursor();
771
+ }
772
+ }
773
+
774
+ void CompositionEventHandler::UpdateCursor() noexcept {
775
+ for (auto &taggedView : m_currentlyHoveredViewsPerPointer[MOUSE_POINTER_ID]) {
776
+ if (auto view = taggedView.view()) {
777
+ if (auto viewcomponent =
778
+ view.try_as<winrt::Microsoft::ReactNative::Composition::implementation::ComponentView>()) {
779
+ auto cursorInfo = viewcomponent->cursor();
780
+ if (cursorInfo.first != facebook::react::Cursor::Auto || cursorInfo.second != nullptr) {
781
+ SetCursor(cursorInfo.first, cursorInfo.second);
782
+ return;
783
+ }
784
+ }
785
+ }
786
+ }
787
+
788
+ SetCursor(facebook::react::Cursor::Auto, nullptr);
789
+ }
790
+
791
+ void CompositionEventHandler::SetCursor(facebook::react::Cursor cursor, HCURSOR hcur) noexcept {
792
+ if (m_currentCursor == cursor && m_hcursor == hcur)
793
+ return;
794
+
795
+ if (auto strongRootView = m_wkRootView.get()) {
796
+ if (auto island = strongRootView.Island()) {
797
+ auto pointerSource = winrt::Microsoft::UI::Input::InputPointerSource::GetForIsland(island);
798
+
799
+ if (!hcur) {
800
+ winrt::Windows::UI::Core::CoreCursorType type = winrt::Windows::UI::Core::CoreCursorType::Arrow;
801
+ switch (cursor) {
802
+ case facebook::react::Cursor::Pointer:
803
+ type = winrt::Windows::UI::Core::CoreCursorType::Hand;
804
+ break;
805
+ case facebook::react::Cursor::Help:
806
+ type = winrt::Windows::UI::Core::CoreCursorType::Help;
807
+ break;
808
+ case facebook::react::Cursor::NotAllowed:
809
+ type = winrt::Windows::UI::Core::CoreCursorType::UniversalNo;
810
+ break;
811
+ case facebook::react::Cursor::Wait:
812
+ type = winrt::Windows::UI::Core::CoreCursorType::Wait;
813
+ break;
814
+ case facebook::react::Cursor::Move:
815
+ type = winrt::Windows::UI::Core::CoreCursorType::SizeAll;
816
+ break;
817
+ case facebook::react::Cursor::NESWResize:
818
+ type = winrt::Windows::UI::Core::CoreCursorType::SizeNortheastSouthwest;
819
+ break;
820
+ case facebook::react::Cursor::NSResize:
821
+ type = winrt::Windows::UI::Core::CoreCursorType::SizeNorthSouth;
822
+ break;
823
+ case facebook::react::Cursor::NWSEResize:
824
+ type = winrt::Windows::UI::Core::CoreCursorType::SizeNorthwestSoutheast;
825
+ break;
826
+ case facebook::react::Cursor::EWResize:
827
+ type = winrt::Windows::UI::Core::CoreCursorType::SizeWestEast;
828
+ break;
829
+ case facebook::react::Cursor::Text:
830
+ type = winrt::Windows::UI::Core::CoreCursorType::IBeam;
831
+ break;
832
+ case facebook::react::Cursor::Progress:
833
+ type = winrt::Windows::UI::Core::CoreCursorType::Wait; // IDC_APPSTARTING not mapped to CoreCursor?
834
+ break;
835
+ case facebook::react::Cursor::Crosshair:
836
+ type = winrt::Windows::UI::Core::CoreCursorType::Cross;
837
+ break;
838
+ default:
839
+ break;
840
+ }
841
+
842
+ m_inputCursor = winrt::Microsoft::UI::Input::InputCursor::CreateFromCoreCursor(
843
+ winrt::Windows::UI::Core::CoreCursor(type, 0));
844
+ m_hcursor = hcur;
845
+ } else {
846
+ auto cursorInterop = winrt::get_activation_factory<
847
+ winrt::Microsoft::UI::Input::InputCursor,
848
+ ABI::Microsoft::UI::Input::IInputCursorStaticsInterop>();
849
+ winrt::com_ptr<IUnknown> spunk;
850
+ winrt::check_hresult(cursorInterop->CreateFromHCursor(
851
+ hcur, reinterpret_cast<ABI::Microsoft::UI::Input::IInputCursor **>(spunk.put_void())));
852
+ m_hcursor = hcur;
853
+ m_inputCursor = spunk.as<winrt::Microsoft::UI::Input::InputCursor>();
854
+ }
855
+
856
+ pointerSource.Cursor(m_inputCursor);
857
+ } else {
858
+ if (m_hcursorOwned) {
859
+ ::DestroyCursor(m_hcursor);
860
+ m_hcursorOwned = false;
861
+ }
862
+ if (hcur == nullptr) {
863
+ const WCHAR *idc = IDC_ARROW;
864
+ switch (cursor) {
865
+ case facebook::react::Cursor::Pointer:
866
+ idc = IDC_HAND;
867
+ break;
868
+ case facebook::react::Cursor::Help:
869
+ idc = IDC_HELP;
870
+ break;
871
+ case facebook::react::Cursor::NotAllowed:
872
+ idc = IDC_NO;
873
+ break;
874
+ case facebook::react::Cursor::Wait:
875
+ idc = IDC_WAIT;
876
+ break;
877
+ case facebook::react::Cursor::Move:
878
+ idc = IDC_SIZEALL;
879
+ break;
880
+ case facebook::react::Cursor::NESWResize:
881
+ idc = IDC_SIZENESW;
882
+ break;
883
+ case facebook::react::Cursor::NSResize:
884
+ idc = IDC_SIZENS;
885
+ break;
886
+ case facebook::react::Cursor::NWSEResize:
887
+ idc = IDC_SIZENWSE;
888
+ break;
889
+ case facebook::react::Cursor::EWResize:
890
+ idc = IDC_SIZEWE;
891
+ break;
892
+ case facebook::react::Cursor::Text:
893
+ idc = IDC_IBEAM;
894
+ break;
895
+ case facebook::react::Cursor::Progress:
896
+ idc = IDC_APPSTARTING;
897
+ break;
898
+ case facebook::react::Cursor::Crosshair:
899
+ idc = IDC_CROSS;
900
+ break;
901
+ default:
902
+ break;
903
+ }
904
+ m_hcursor = ::LoadCursor(nullptr, idc);
905
+ m_hcursorOwned = true;
906
+ } else {
907
+ m_hcursor = hcur;
908
+ }
909
+ ::SetCursor(m_hcursor);
910
+ }
911
+ m_currentCursor = cursor;
912
+ }
756
913
  }
757
914
 
758
915
  void CompositionEventHandler::UpdateActiveTouch(
@@ -147,6 +147,9 @@ class CompositionEventHandler : public std::enable_shared_from_this<CompositionE
147
147
  static void
148
148
  UpdateActiveTouch(ActiveTouch &activeTouch, facebook::react::Point ptScaled, facebook::react::Point ptLocal) noexcept;
149
149
 
150
+ void UpdateCursor() noexcept;
151
+ void SetCursor(facebook::react::Cursor cursor, HCURSOR hcur) noexcept;
152
+
150
153
  std::map<PointerId, ActiveTouch> m_activeTouches; // iOS is map of touch event args to ActiveTouch..?
151
154
  PointerId m_touchId = 0;
152
155
  int m_fragmentTag = -1;
@@ -157,6 +160,10 @@ class CompositionEventHandler : public std::enable_shared_from_this<CompositionE
157
160
 
158
161
  facebook::react::Tag m_pointerCapturingComponentTag{-1}; // Component that has captured input
159
162
  std::vector<PointerId> m_capturedPointers;
163
+ HCURSOR m_hcursor{nullptr};
164
+ bool m_hcursorOwned{false}; // If we create the cursor, so we need to destroy it
165
+ facebook::react::Cursor m_currentCursor{facebook::react::Cursor::Auto};
166
+ winrt::Microsoft::UI::Input::InputCursor m_inputCursor{nullptr};
160
167
 
161
168
  #ifdef USE_WINUI3
162
169
  winrt::event_token m_pointerPressedToken;
@@ -53,8 +53,9 @@ ComponentView::ComponentView(
53
53
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
54
54
  facebook::react::Tag tag,
55
55
  winrt::Microsoft::ReactNative::ReactContext const &reactContext,
56
- ComponentViewFeatures flags)
57
- : base_type(tag, reactContext), m_compContext(compContext), m_flags(flags) {
56
+ ComponentViewFeatures flags,
57
+ winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder)
58
+ : base_type(tag, reactContext, builder), m_compContext(compContext), m_flags(flags) {
58
59
  m_outerVisual = compContext.CreateSpriteVisual(); // TODO could be a raw ContainerVisual if we had a
59
60
  // CreateContainerVisual in ICompositionContext
60
61
  }
@@ -791,6 +792,10 @@ void ComponentView::updateClippingPath(
791
792
  }
792
793
  }
793
794
 
795
+ std::pair<facebook::react::Cursor, HCURSOR> ComponentView::cursor() const noexcept {
796
+ return {viewProps()->cursor, nullptr};
797
+ }
798
+
794
799
  void ComponentView::indexOffsetForBorder(uint32_t &index) const noexcept {
795
800
  if (m_borderPrimitive) {
796
801
  index += m_borderPrimitive->numberOfVisuals();
@@ -912,24 +917,15 @@ ViewComponentView::ViewComponentView(
912
917
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
913
918
  facebook::react::Tag tag,
914
919
  winrt::Microsoft::ReactNative::ReactContext const &reactContext,
915
- ComponentViewFeatures flags)
916
- : base_type(compContext, tag, reactContext, flags),
920
+ ComponentViewFeatures flags,
921
+ winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder)
922
+ : base_type(compContext, tag, reactContext, flags, builder),
917
923
  m_props(defaultProps ? defaultProps : ViewComponentView::defaultProps()) {}
918
924
 
919
925
  winrt::Microsoft::ReactNative::Composition::Experimental::IVisual ViewComponentView::createVisual() noexcept {
920
926
  return m_compContext.CreateSpriteVisual();
921
927
  }
922
928
 
923
- void ViewComponentView::CreateVisualHandler(
924
- const winrt::Microsoft::ReactNative::Composition::CreateVisualDelegate &handler) {
925
- m_createVisualHandler = handler;
926
- }
927
-
928
- winrt::Microsoft::ReactNative::Composition::CreateVisualDelegate ViewComponentView::CreateVisualHandler()
929
- const noexcept {
930
- return m_createVisualHandler;
931
- }
932
-
933
929
  void ViewComponentView::CreateInternalVisualHandler(
934
930
  const winrt::Microsoft::ReactNative::Composition::Experimental::CreateInternalVisualDelegate &handler) {
935
931
  m_createInternalVisualHandler = handler;
@@ -944,10 +940,10 @@ void ViewComponentView::ensureVisual() noexcept {
944
940
  if (!m_visual) {
945
941
  if (m_createInternalVisualHandler) {
946
942
  m_visual = m_createInternalVisualHandler(*this);
947
- } else if (m_createVisualHandler) {
943
+ } else if (m_builder && m_builder->CreateVisualHandler()) {
948
944
  m_visual =
949
945
  winrt::Microsoft::ReactNative::Composition::Experimental::MicrosoftCompositionContextHelper::CreateVisual(
950
- m_createVisualHandler(*this));
946
+ m_builder->CreateVisualHandler()(*this));
951
947
  } else {
952
948
  m_visual = createVisual();
953
949
  }
@@ -965,6 +961,8 @@ winrt::Microsoft::ReactNative::ComponentView ViewComponentView::Create(
965
961
 
966
962
  winrt::Microsoft::ReactNative::Composition::Experimental::IVisual
967
963
  ViewComponentView::VisualToMountChildrenInto() noexcept {
964
+ if (m_builder && m_builder->VisualToMountChildrenIntoHandler())
965
+ return m_builder->VisualToMountChildrenIntoHandler()(*this);
968
966
  return Visual();
969
967
  }
970
968
 
@@ -1212,7 +1210,7 @@ winrt::Microsoft::ReactNative::ViewProps ViewComponentView::ViewProps() noexcept
1212
1210
 
1213
1211
  winrt::Microsoft::ReactNative::ViewProps ViewComponentView::ViewPropsInner() noexcept {
1214
1212
  // If we have AbiViewProps, then we dont need to new up a props wrapper
1215
- if (m_customComponent) {
1213
+ if (m_builder) {
1216
1214
  const auto &abiViewProps = *std::static_pointer_cast<const ::Microsoft::ReactNative::AbiViewProps>(m_props);
1217
1215
  return abiViewProps.ViewProps();
1218
1216
  }
@@ -35,7 +35,8 @@ struct ComponentView : public ComponentViewT<
35
35
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
36
36
  facebook::react::Tag tag,
37
37
  winrt::Microsoft::ReactNative::ReactContext const &reactContext,
38
- ComponentViewFeatures flags);
38
+ ComponentViewFeatures flags,
39
+ winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder);
39
40
  virtual ~ComponentView();
40
41
 
41
42
  virtual winrt::Microsoft::ReactNative::Composition::Experimental::IVisual Visual() const noexcept {
@@ -106,6 +107,8 @@ struct ComponentView : public ComponentViewT<
106
107
  void Toggle() noexcept override;
107
108
  virtual winrt::Microsoft::ReactNative::implementation::ClipState getClipState() noexcept;
108
109
 
110
+ virtual std::pair<facebook::react::Cursor, HCURSOR> cursor() const noexcept;
111
+
109
112
  const facebook::react::LayoutMetrics &layoutMetrics() const noexcept;
110
113
 
111
114
  virtual std::string DefaultControlType() const noexcept;
@@ -206,7 +209,8 @@ struct ViewComponentView : public ViewComponentViewT<
206
209
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
207
210
  facebook::react::Tag tag,
208
211
  winrt::Microsoft::ReactNative::ReactContext const &reactContext,
209
- ComponentViewFeatures flags);
212
+ ComponentViewFeatures flags,
213
+ winrt::Microsoft::ReactNative::Composition::ReactCompositionViewComponentBuilder *builder = nullptr);
210
214
 
211
215
  virtual winrt::Microsoft::ReactNative::Composition::Experimental::IVisual createVisual() noexcept;
212
216
 
@@ -224,7 +228,6 @@ struct ViewComponentView : public ViewComponentViewT<
224
228
  bool m_hasNonVisualChildren{false};
225
229
  facebook::react::SharedViewProps m_props;
226
230
  winrt::Microsoft::ReactNative::Composition::Experimental::IVisual m_visual{nullptr};
227
- winrt::Microsoft::ReactNative::Composition::CreateVisualDelegate m_createVisualHandler{nullptr};
228
231
  winrt::Microsoft::ReactNative::Composition::Experimental::CreateInternalVisualDelegate m_createInternalVisualHandler{
229
232
  nullptr};
230
233
  };
@@ -22,8 +22,15 @@ namespace winrt::Microsoft::ReactNative::Composition::implementation {
22
22
  ContentIslandComponentView::ContentIslandComponentView(
23
23
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
24
24
  facebook::react::Tag tag,
25
- winrt::Microsoft::ReactNative::ReactContext const &reactContext)
26
- : base_type(ViewComponentView::defaultProps(), compContext, tag, reactContext, ComponentViewFeatures::Default) {
25
+ winrt::Microsoft::ReactNative::ReactContext const &reactContext,
26
+ ReactCompositionViewComponentBuilder *builder)
27
+ : base_type(
28
+ ViewComponentView::defaultProps(),
29
+ compContext,
30
+ tag,
31
+ reactContext,
32
+ ComponentViewFeatures::Default,
33
+ builder) {
27
34
  m_mountedToken = Mounted([](const winrt::IInspectable &, const winrt::Microsoft::ReactNative::ComponentView &view) {
28
35
  view.as<ContentIslandComponentView>()->OnMounted();
29
36
  });
@@ -40,7 +40,8 @@ struct ContentIslandComponentView : ContentIslandComponentViewT<ContentIslandCom
40
40
  ContentIslandComponentView(
41
41
  const winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext &compContext,
42
42
  facebook::react::Tag tag,
43
- winrt::Microsoft::ReactNative::ReactContext const &reactContext);
43
+ winrt::Microsoft::ReactNative::ReactContext const &reactContext,
44
+ ReactCompositionViewComponentBuilder *builder);
44
45
  ~ContentIslandComponentView() noexcept;
45
46
 
46
47
  private:
@@ -24,6 +24,7 @@
24
24
  #include "IReactContext.h"
25
25
  #include "ReactHost/ReactInstanceWin.h"
26
26
  #include "ReactNativeHost.h"
27
+ #include "WindowsModalHostViewShadowNode.h"
27
28
 
28
29
  namespace winrt::Microsoft::ReactNative::Composition::implementation {
29
30
  WindowsModalHostComponentView::WindowsModalHostComponentView(
@@ -33,6 +34,23 @@ WindowsModalHostComponentView::WindowsModalHostComponentView(
33
34
  : Super(compContext, tag, reactContext) {}
34
35
 
35
36
  WindowsModalHostComponentView::~WindowsModalHostComponentView() {
37
+ // dispatch onDismiss event
38
+ auto emitter = std::static_pointer_cast<const facebook::react::ModalHostViewEventEmitter>(m_eventEmitter);
39
+ facebook::react::ModalHostViewEventEmitter::OnDismiss onDismissArgs;
40
+ emitter->onDismiss(onDismissArgs);
41
+
42
+ // reset the topWindowID
43
+ if (m_prevWindowID) {
44
+ auto host =
45
+ winrt::Microsoft::ReactNative::implementation::ReactNativeHost::GetReactNativeHost(m_reactContext.Properties());
46
+ winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
47
+ host.InstanceSettings().Properties(), m_prevWindowID);
48
+ m_prevWindowID = 0;
49
+ }
50
+
51
+ // enable input to parent
52
+ EnableWindow(m_parentHwnd, true);
53
+
36
54
  // Check if the window handle (m_hwnd) exists and destroy it if necessary
37
55
  if (m_hwnd) {
38
56
  // Close/Destroy the modal window
@@ -77,17 +95,19 @@ void WindowsModalHostComponentView::EnsureModalCreated() {
77
95
  m_prevWindowID =
78
96
  winrt::Microsoft::ReactNative::ReactCoreInjection::GetTopLevelWindowId(m_reactContext.Properties().Handle());
79
97
 
80
- auto roothwnd = GetHwndForParenting();
98
+ m_parentHwnd = GetHwndForParenting();
99
+
100
+ auto windowsStyle = m_showTitleBar ? WS_OVERLAPPEDWINDOW : WS_POPUP;
81
101
 
82
102
  m_hwnd = CreateWindow(
83
103
  c_modalWindowClassName,
84
104
  L"React-Native Modal",
85
- WS_OVERLAPPEDWINDOW,
105
+ windowsStyle,
86
106
  CW_USEDEFAULT,
87
107
  CW_USEDEFAULT,
88
108
  MODAL_MIN_WIDTH,
89
109
  MODAL_MIN_HEIGHT,
90
- roothwnd, // parent
110
+ m_parentHwnd, // parent
91
111
  nullptr,
92
112
  hInstance,
93
113
  spunk.get());
@@ -126,7 +146,7 @@ void WindowsModalHostComponentView::EnsureModalCreated() {
126
146
  constraints.LayoutDirection = winrt::Microsoft::ReactNative::LayoutDirection::Undefined;
127
147
 
128
148
  RECT rc;
129
- GetClientRect(roothwnd, &rc);
149
+ GetClientRect(m_parentHwnd, &rc);
130
150
  // Maximum size is set to size of parent hwnd
131
151
  constraints.MaximumSize = {(rc.right - rc.left) * ScaleFactor(m_hwnd), (rc.bottom - rc.top) / ScaleFactor(m_hwnd)};
132
152
  constraints.MinimumSize = {MODAL_MIN_WIDTH * ScaleFactor(m_hwnd), MODAL_MIN_HEIGHT * ScaleFactor(m_hwnd)};
@@ -141,6 +161,14 @@ void WindowsModalHostComponentView::ShowOnUIThread() {
141
161
  ShowWindow(m_hwnd, SW_NORMAL);
142
162
  BringWindowToTop(m_hwnd);
143
163
  SetFocus(m_hwnd);
164
+
165
+ // disable input to parent
166
+ EnableWindow(m_parentHwnd, false);
167
+
168
+ // dispatch onShow event
169
+ auto emitter = std::static_pointer_cast<const facebook::react::ModalHostViewEventEmitter>(m_eventEmitter);
170
+ facebook::react::ModalHostViewEventEmitter::OnShow onShowArgs;
171
+ emitter->onShow(onShowArgs);
144
172
  }
145
173
  }
146
174
 
@@ -149,12 +177,21 @@ void WindowsModalHostComponentView::HideOnUIThread() noexcept {
149
177
  SendMessage(m_hwnd, WM_CLOSE, 0, 0);
150
178
  }
151
179
 
180
+ // dispatch onDismiss event
181
+ auto emitter = std::static_pointer_cast<const facebook::react::ModalHostViewEventEmitter>(m_eventEmitter);
182
+ facebook::react::ModalHostViewEventEmitter::OnDismiss onDismissArgs;
183
+ emitter->onDismiss(onDismissArgs);
184
+
185
+ // enable input to parent
186
+ EnableWindow(m_parentHwnd, true);
187
+
152
188
  // reset the topWindowID
153
189
  if (m_prevWindowID) {
154
190
  auto host =
155
191
  winrt::Microsoft::ReactNative::implementation::ReactNativeHost::GetReactNativeHost(m_reactContext.Properties());
156
192
  winrt::Microsoft::ReactNative::ReactCoreInjection::SetTopLevelWindowId(
157
193
  host.InstanceSettings().Properties(), m_prevWindowID);
194
+ m_prevWindowID = 0;
158
195
  }
159
196
  }
160
197
 
@@ -266,22 +303,32 @@ void WindowsModalHostComponentView::AdjustWindowSize() noexcept {
266
303
  if (m_layoutMetrics.overflowInset.right == 0 && m_layoutMetrics.overflowInset.bottom == 0) {
267
304
  return;
268
305
  }
306
+
269
307
  // Modal's size is based on it's children, use the overflow to calculate the width/height
270
308
  float xPos = (-m_layoutMetrics.overflowInset.right * (m_layoutMetrics.pointScaleFactor));
271
309
  float yPos = (-m_layoutMetrics.overflowInset.bottom * (m_layoutMetrics.pointScaleFactor));
272
310
  RECT rc;
273
311
  GetClientRect(m_hwnd, &rc);
274
312
  RECT rect = {0, 0, (int)xPos, (int)yPos};
275
- AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); // Adjust for title bar and borders
276
- MoveWindow(m_hwnd, 0, 0, (int)(rect.right - rect.left), (int)(rect.bottom - rect.top), true);
313
+
314
+ if (m_showTitleBar) {
315
+ AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); // Adjust for title bar and borders
316
+ }
277
317
 
278
318
  // set the layoutMetrics
279
- m_layoutMetrics.frame.size = {
280
- (float)rect.right - rect.left + m_layoutMetrics.frame.origin.x,
281
- (float)rect.bottom - rect.top + m_layoutMetrics.frame.origin.y};
319
+ m_layoutMetrics.frame.size = {(float)rect.right - rect.left, (float)rect.bottom - rect.top};
282
320
  m_layoutMetrics.overflowInset.right = 0;
283
321
  m_layoutMetrics.overflowInset.bottom = 0;
284
322
 
323
+ // get Modal's position based on parent
324
+ RECT parentRC;
325
+ GetWindowRect(m_parentHwnd, &parentRC);
326
+ float xCor = (parentRC.left + parentRC.right - m_layoutMetrics.frame.size.width) / 2; // midpointx - width / 2
327
+ float yCor = (parentRC.top + parentRC.bottom - m_layoutMetrics.frame.size.height) / 2; // midpointy - height / 2
328
+
329
+ // Adjust window position and size
330
+ MoveWindow(m_hwnd, (int)xCor, (int)yCor, (int)(rect.right - rect.left), (int)(rect.bottom - rect.top), true);
331
+
285
332
  // Let RNWIsland know that Modal's size has changed
286
333
  winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(m_reactNativeIsland)
287
334
  ->NotifySizeChanged();
@@ -294,6 +341,9 @@ void WindowsModalHostComponentView::updateProps(
294
341
  *std::static_pointer_cast<const facebook::react::ModalHostViewProps>(oldProps ? oldProps : viewProps());
295
342
  const auto &newModalProps = *std::static_pointer_cast<const facebook::react::ModalHostViewProps>(props);
296
343
  newModalProps.visible ? m_isVisible = true : m_isVisible = false;
344
+ if (!m_isVisible) {
345
+ HideOnUIThread();
346
+ }
297
347
  base_type::updateProps(props, oldProps);
298
348
  }
299
349
 
@@ -60,9 +60,11 @@ struct WindowsModalHostComponentView
60
60
  static void RegisterWndClass() noexcept;
61
61
 
62
62
  private:
63
+ HWND m_parentHwnd{nullptr};
63
64
  HWND m_hwnd{nullptr};
64
65
  uint64_t m_prevWindowID;
65
66
  bool m_isVisible{false};
67
+ bool m_showTitleBar{false};
66
68
  winrt::Microsoft::ReactNative::ReactNativeIsland m_reactNativeIsland;
67
69
  };
68
70