react-native-windows 0.76.0-preview.2 → 0.76.0-preview.4

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 (58) hide show
  1. package/Libraries/Components/AccessibilityInfo/AccessibilityInfo.windows.js +15 -15
  2. package/Libraries/Components/Button.windows.js +18 -18
  3. package/Libraries/Components/Flyout/FlyoutNativeComponent.js +5 -1
  4. package/Libraries/Components/Keyboard/KeyboardExt.js +1 -1
  5. package/Libraries/Components/Keyboard/KeyboardExt.js.map +1 -1
  6. package/Libraries/Components/TextInput/TextInput.windows.js +16 -11
  7. package/Libraries/Components/Touchable/Touchable.windows.js +2 -2
  8. package/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +5 -3
  9. package/Libraries/Components/View/View.windows.js +1 -3
  10. package/Libraries/Core/ReactNativeVersion.js +1 -1
  11. package/Libraries/Text/Text.windows.js +13 -9
  12. package/Libraries/Utilities/Platform.windows.js +4 -4
  13. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +12 -0
  14. package/Microsoft.ReactNative/Fabric/ComponentView.h +3 -0
  15. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +66 -0
  16. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +8 -2
  17. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +24 -0
  18. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +2 -0
  19. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +8 -3
  20. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +1 -0
  21. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +11 -0
  22. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +2 -0
  23. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.cpp +1 -2
  24. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.h +1 -1
  25. package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +12 -4
  26. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +338 -0
  27. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.h +66 -0
  28. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +8 -0
  29. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +1 -0
  30. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +3 -0
  31. package/Microsoft.ReactNative/Fabric/ReactTaggedView.h +4 -0
  32. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +5 -0
  33. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +1 -1
  34. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +1 -1
  35. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -1
  36. package/Microsoft.ReactNative/ReactCoreInjection.h +0 -1
  37. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +15 -4
  38. package/Microsoft.ReactNative/ReactNativeAppBuilder.cpp +25 -129
  39. package/Microsoft.ReactNative/ReactNativeAppBuilder.h +5 -13
  40. package/Microsoft.ReactNative/ReactNativeAppBuilder.idl +13 -34
  41. package/Microsoft.ReactNative/ReactNativeWin32App.cpp +129 -18
  42. package/Microsoft.ReactNative/ReactNativeWin32App.h +14 -5
  43. package/PropertySheets/External/Microsoft.ReactNative.CppLib.props +17 -0
  44. package/PropertySheets/External/Microsoft.ReactNative.CppLib.targets +17 -0
  45. package/PropertySheets/Generated/PackageVersion.g.props +2 -2
  46. package/PropertySheets/WebView2.props +7 -0
  47. package/PropertySheets/WinUI.props +1 -1
  48. package/Shared/Shared.vcxitems +3 -10
  49. package/Shared/Shared.vcxitems.filters +1 -0
  50. package/just-task.js +1 -1
  51. package/package.json +15 -16
  52. package/templates/cpp-app/template.config.js +8 -3
  53. package/templates/cpp-app/windows/MyApp/MyApp.cpp +46 -131
  54. package/templates/cpp-lib/template.config.js +8 -3
  55. package/templates/cpp-lib/windows/MyLib/MyLib.vcxproj +4 -4
  56. package/templates/templateUtils.js +2 -3
  57. package/Microsoft.ReactNative/ReactInstanceSettingsBuilder.cpp +0 -59
  58. package/Microsoft.ReactNative/ReactInstanceSettingsBuilder.h +0 -23
@@ -296,7 +296,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
296
296
  {"ScrollBarThumbFillDisabled", "ControlStrongFillColorDisabled"},
297
297
  {"ScrollBarTrackFill",
298
298
  "AcrylicInAppFillColorDefault"}, // TODO make AcrylicInAppFillColorDefault a real acrylic brush
299
- };
299
+ {"ToolTipBackground", "SystemChromeMediumLowColor"},
300
+ {"ToolTipForeground", "SystemControlForegroundBaseHighColor"},
301
+ {"ToolTipBorderBrush", "SystemControlTransientBorderColor"}};
300
302
 
301
303
  static std::unordered_map<std::string, winrt::Windows::UI::Color, std::hash<std::string_view>, std::equal_to<>>
302
304
  s_lightColors = {
@@ -326,7 +328,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
326
328
  {"ControlStrongFillColorDefault", {0x72, 0x00, 0x00, 0x00}},
327
329
  {"ControlStrongFillColorDisabled", {0x51, 0x00, 0x00, 0x00}},
328
330
  {"AcrylicInAppFillColorDefault", {0x9E, 0xFF, 0xFF, 0xFF}},
329
- };
331
+ {"SystemChromeMediumLowColor", {0xFF, 0xF2, 0xF2, 0xF2}},
332
+ {"SystemControlForegroundBaseHighColor", {0xFF, 0x00, 0x00, 0x00}},
333
+ {"SystemControlTransientBorderColor", {0x24, 0x00, 0x00, 0x00}}};
330
334
 
331
335
  static std::unordered_map<std::string, winrt::Windows::UI::Color, std::hash<std::string_view>, std::equal_to<>>
332
336
  s_darkColors = {
@@ -356,7 +360,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
356
360
  {"ControlStrongFillColorDefault", {0x8B, 0xFF, 0xFF, 0xFF}},
357
361
  {"ControlStrongFillColorDisabled", {0x3F, 0xFF, 0xFF, 0xFF}},
358
362
  {"AcrylicInAppFillColorDefault", {0x9E, 0x00, 0x00, 0x00}},
359
- };
363
+ {"SystemChromeMediumLowColor", {0xFF, 0x2B, 0x2B, 0x2B}},
364
+ {"SystemControlForegroundBaseHighColor", {0xFF, 0xFF, 0xFF, 0xFF}},
365
+ {"SystemControlTransientBorderColor", {0x5C, 0x00, 0x00, 0x00}}};
360
366
 
361
367
  static std::unordered_map<
362
368
  std::string,
@@ -391,7 +397,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
391
397
  {"SubtleFillColorSecondary", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
392
398
  {"ControlStrongFillColorDefault", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
393
399
  {"ControlStrongFillColorDisabled", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
394
- };
400
+ {"SystemChromeMediumLowColor", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
401
+ {"SystemControlForegroundBaseHighColor", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonText, {}}},
402
+ {"SystemControlTransientBorderColor", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonText, {}}}};
395
403
 
396
404
  auto alias = s_xamlAliasedColors.find(platformColor);
397
405
  if (alias != s_xamlAliasedColors.end()) {
@@ -0,0 +1,338 @@
1
+
2
+ // Copyright (c) Microsoft Corporation.
3
+ // Licensed under the MIT License.
4
+
5
+ #include "TooltipService.h"
6
+
7
+ #include <CompositionSwitcher.Experimental.interop.h>
8
+ #include <Fabric/Composition/CompositionViewComponentView.h>
9
+ #include <react/renderer/attributedstring/AttributedStringBox.h>
10
+ #include <react/renderer/core/LayoutConstraints.h>
11
+ #include <react/renderer/textlayoutmanager/TextLayoutManager.h>
12
+ #include <winrt/Microsoft.ReactNative.Composition.h>
13
+ #include "TextDrawing.h"
14
+ #include "dwmapi.h"
15
+
16
+ namespace winrt::Microsoft::ReactNative {
17
+
18
+ constexpr PCWSTR c_tooltipWindowClassName = L"RN_TOOLTIP";
19
+ constexpr auto TooltipDataProperty = L"TooltipData";
20
+ constexpr float tooltipFontSize = 12;
21
+ constexpr float tooltipMaxHeight = 1000;
22
+ constexpr float tooltipMaxWidth = 320;
23
+ constexpr float tooltipHorizontalPadding = 8;
24
+ constexpr float tooltipTopPadding = 5;
25
+ constexpr float tooltipBottomPadding = 7;
26
+ constexpr float toolTipBorderThickness = 1;
27
+ constexpr int toolTipPlacementMargin = 12;
28
+ constexpr int toolTipAnimationTimeMs = 200;
29
+ constexpr int toolTipTimeToShowMs = 1000;
30
+
31
+ struct TooltipData {
32
+ TooltipData(const winrt::Microsoft::ReactNative::ComponentView &view) : view(view) {}
33
+
34
+ static TooltipData *GetFromWindow(HWND hwnd) {
35
+ auto data = reinterpret_cast<TooltipData *>(GetProp(hwnd, TooltipDataProperty));
36
+ return data;
37
+ }
38
+
39
+ int width;
40
+ int height;
41
+ ::Microsoft::ReactNative::ReactTaggedView view;
42
+ winrt::com_ptr<::IDWriteTextLayout> textLayout;
43
+ facebook::react::AttributedStringBox attributedString;
44
+ winrt::Microsoft::ReactNative::Composition::Experimental::ICompositionContext compositionContext;
45
+ };
46
+
47
+ facebook::react::AttributedStringBox CreateTooltipAttributedString(const std::string &tooltip) noexcept {
48
+ auto attributedString = facebook::react::AttributedString{};
49
+ auto fragment = facebook::react::AttributedString::Fragment{};
50
+ fragment.string = tooltip;
51
+ fragment.textAttributes.fontSize = tooltipFontSize;
52
+ attributedString.appendFragment(fragment);
53
+ return facebook::react::AttributedStringBox{attributedString};
54
+ }
55
+
56
+ LRESULT CALLBACK TooltipWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) noexcept {
57
+ switch (message) {
58
+ case WM_DESTROY: {
59
+ delete TooltipData::GetFromWindow(hwnd);
60
+ SetProp(hwnd, TooltipDataProperty, 0);
61
+ return 0;
62
+ }
63
+ case WM_PRINTCLIENT:
64
+ case WM_PAINT: {
65
+ HDC hdc;
66
+ PAINTSTRUCT ps;
67
+
68
+ if (message != WM_PRINTCLIENT)
69
+ hdc = BeginPaint(hwnd, &ps);
70
+ else
71
+ hdc = (HDC)wparam;
72
+ auto data = TooltipData::GetFromWindow(hwnd);
73
+
74
+ if (auto view = data->view.view()) {
75
+ auto scaleFactor = view.LayoutMetrics().PointScaleFactor;
76
+
77
+ auto ccInterop = data->compositionContext
78
+ .as<::Microsoft::ReactNative::Composition::Experimental::ICompositionContextInterop>();
79
+ winrt::com_ptr<ID2D1Factory1> factory;
80
+ ccInterop->D2DFactory(factory.put());
81
+
82
+ winrt::com_ptr<ID2D1DCRenderTarget> renderTarget;
83
+
84
+ D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
85
+ D2D1_RENDER_TARGET_TYPE_DEFAULT,
86
+ D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
87
+ 0,
88
+ 0,
89
+ D2D1_RENDER_TARGET_USAGE_NONE,
90
+ D2D1_FEATURE_LEVEL_DEFAULT);
91
+ winrt::check_hresult(factory->CreateDCRenderTarget(&props, renderTarget.put()));
92
+ RECT rc;
93
+ GetClientRect(hwnd, &rc);
94
+ winrt::check_hresult(renderTarget->BindDC(hdc, &rc));
95
+ auto theme = view.as<winrt::Microsoft::ReactNative::Composition::ComponentView>().Theme();
96
+ auto selfTheme = winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::Theme>(theme);
97
+
98
+ renderTarget->BeginDraw();
99
+ renderTarget->Clear(selfTheme->D2DPlatformColor("ToolTipBackground"));
100
+
101
+ auto textAttributes = facebook::react::TextAttributes{};
102
+ facebook::react::Color fgColor;
103
+ fgColor.m_platformColor.push_back("ToolTipForeground");
104
+ textAttributes.foregroundColor = fgColor;
105
+
106
+ winrt::Microsoft::ReactNative::Composition::RenderText(
107
+ *renderTarget,
108
+ *data->textLayout,
109
+ data->attributedString.getValue(),
110
+ textAttributes,
111
+ {std::round(tooltipHorizontalPadding * scaleFactor), std::round(tooltipTopPadding * scaleFactor)},
112
+ scaleFactor,
113
+ *selfTheme);
114
+
115
+ auto hr = renderTarget->EndDraw();
116
+ }
117
+
118
+ if (message != WM_PRINTCLIENT)
119
+ EndPaint(hwnd, &ps);
120
+ return 0;
121
+ }
122
+ case WM_NCCREATE: {
123
+ auto cs = reinterpret_cast<CREATESTRUCT *>(lparam);
124
+ auto data = static_cast<TooltipData *>(cs->lpCreateParams);
125
+ WINRT_ASSERT(data);
126
+ SetProp(hwnd, TooltipDataProperty, reinterpret_cast<HANDLE>(data));
127
+ break;
128
+ }
129
+ }
130
+
131
+ return DefWindowProc(hwnd, message, wparam, lparam);
132
+ }
133
+
134
+ void RegisterTooltipWndClass() noexcept {
135
+ static bool registered = false;
136
+ if (registered) {
137
+ return;
138
+ }
139
+
140
+ HINSTANCE hInstance =
141
+ GetModuleHandle(NULL); // returns a handle to the file used to create the calling process (.exe file)
142
+
143
+ WNDCLASSEX wcex = {}; // contains window class information
144
+ wcex.cbSize = sizeof(wcex); // size of windows class (bytes)
145
+ wcex.style = CS_HREDRAW | CS_VREDRAW; // class style (redraw window on size adjustment)
146
+ wcex.lpfnWndProc = &TooltipWndProc; // pointer to windows procedure
147
+ wcex.cbClsExtra = DLGWINDOWEXTRA; // extra bytes to allocate
148
+ wcex.cbWndExtra = sizeof(TooltipData *); // extra bytes to allocate
149
+ wcex.hInstance = hInstance;
150
+ wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); // handle to class cursor
151
+ wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); // background color
152
+ wcex.lpszClassName = c_tooltipWindowClassName; // specify resource name
153
+ ATOM classId = RegisterClassEx(&wcex); // register new windows class
154
+ WINRT_VERIFY(classId); // 0 = fail
155
+ winrt::check_win32(!classId);
156
+
157
+ registered = true;
158
+ }
159
+
160
+ TooltipTracker::TooltipTracker(
161
+ const winrt::Microsoft::ReactNative::ComponentView &view,
162
+ const winrt::Microsoft::ReactNative::ReactPropertyBag &properties,
163
+ TooltipService *outer)
164
+ : m_view(view), m_properties(properties), m_outer(outer) {
165
+ view.PointerEntered({this, &TooltipTracker::OnPointerEntered});
166
+ view.PointerExited({this, &TooltipTracker::OnPointerExited});
167
+ view.PointerMoved({this, &TooltipTracker::OnPointerMoved});
168
+ view.Unmounted({this, &TooltipTracker::OnUnmounted});
169
+ }
170
+
171
+ TooltipTracker::~TooltipTracker() {
172
+ DestroyTimer();
173
+ DestroyTooltip();
174
+ }
175
+
176
+ facebook::react::Tag TooltipTracker::Tag() const noexcept {
177
+ return m_view.Tag();
178
+ }
179
+
180
+ void TooltipTracker::OnPointerEntered(
181
+ const winrt::Windows::Foundation::IInspectable &sender,
182
+ const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept {
183
+ if (args.Pointer().PointerDeviceType() !=
184
+ winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType::Mouse &&
185
+ args.Pointer().PointerDeviceType() != winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType::Pen)
186
+ return;
187
+
188
+ auto pp = args.GetCurrentPoint(-1);
189
+ m_pos = pp.Position();
190
+
191
+ m_timer = winrt::Microsoft::ReactNative::Timer::Create(m_properties.Handle());
192
+ m_timer.Interval(std::chrono::milliseconds(toolTipTimeToShowMs));
193
+ m_timer.Tick({this, &TooltipTracker::OnTick});
194
+ m_timer.Start();
195
+ }
196
+
197
+ void TooltipTracker::OnPointerMoved(
198
+ const winrt::Windows::Foundation::IInspectable &sender,
199
+ const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept {
200
+ if (args.Pointer().PointerDeviceType() !=
201
+ winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType::Mouse &&
202
+ args.Pointer().PointerDeviceType() != winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType::Pen)
203
+ return;
204
+
205
+ auto pp = args.GetCurrentPoint(-1);
206
+ m_pos = pp.Position();
207
+ }
208
+
209
+ void TooltipTracker::OnTick(
210
+ const winrt::Windows::Foundation::IInspectable &,
211
+ const winrt::Windows::Foundation::IInspectable &) noexcept {
212
+ ShowTooltip(m_view.view());
213
+ }
214
+
215
+ void TooltipTracker::OnPointerExited(
216
+ const winrt::Windows::Foundation::IInspectable &sender,
217
+ const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept {
218
+ if (args.Pointer().PointerDeviceType() !=
219
+ winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType::Mouse &&
220
+ args.Pointer().PointerDeviceType() != winrt::Microsoft::ReactNative::Composition::Input::PointerDeviceType::Pen)
221
+ return;
222
+ DestroyTimer();
223
+ DestroyTooltip();
224
+ }
225
+
226
+ void TooltipTracker::OnUnmounted(
227
+ const winrt::Windows::Foundation::IInspectable &,
228
+ const winrt::Microsoft::ReactNative::ComponentView &) noexcept {
229
+ DestroyTimer();
230
+ DestroyTooltip();
231
+ }
232
+
233
+ void TooltipTracker::ShowTooltip(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
234
+ auto viewCompView = view.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();
235
+
236
+ auto selfView =
237
+ winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView>(viewCompView);
238
+ auto parentHwnd = selfView->GetHwndForParenting();
239
+ DestroyTimer();
240
+
241
+ if (!m_hwndTip) {
242
+ auto tooltipData = std::make_unique<TooltipData>(view);
243
+ tooltipData->attributedString = CreateTooltipAttributedString(*selfView->viewProps()->tooltip);
244
+
245
+ tooltipData->compositionContext = selfView->CompositionContext();
246
+ tooltipData->view = view;
247
+
248
+ auto scaleFactor = view.LayoutMetrics().PointScaleFactor;
249
+ facebook::react::LayoutConstraints layoutConstraints;
250
+ layoutConstraints.layoutDirection = facebook::react::LayoutDirection::Undefined;
251
+ layoutConstraints.maximumSize.height = tooltipMaxHeight * scaleFactor;
252
+ layoutConstraints.maximumSize.width = tooltipMaxWidth * scaleFactor;
253
+ layoutConstraints.minimumSize.height = 0;
254
+ layoutConstraints.minimumSize.width = 0;
255
+
256
+ facebook::react::TextLayoutManager::GetTextLayout(
257
+ tooltipData->attributedString, {} /*paragraphAttributes*/, layoutConstraints, tooltipData->textLayout);
258
+
259
+ DWRITE_TEXT_METRICS tm;
260
+ winrt::check_hresult(tooltipData->textLayout->GetMetrics(&tm));
261
+
262
+ tooltipData->width =
263
+ static_cast<int>(tm.width + ((tooltipHorizontalPadding + tooltipHorizontalPadding) * scaleFactor));
264
+ tooltipData->height = static_cast<int>(tm.height + ((tooltipTopPadding + tooltipBottomPadding) * scaleFactor));
265
+
266
+ POINT pt = {static_cast<LONG>(m_pos.X), static_cast<LONG>(m_pos.Y)};
267
+ ClientToScreen(parentHwnd, &pt);
268
+
269
+ RegisterTooltipWndClass();
270
+ HINSTANCE hInstance = GetModuleHandle(NULL);
271
+ m_hwndTip = CreateWindow(
272
+ c_tooltipWindowClassName,
273
+ L"Tooltip",
274
+ WS_POPUP,
275
+ pt.x - tooltipData->width / 2,
276
+ static_cast<int>(pt.y - tooltipData->height - (toolTipPlacementMargin * scaleFactor)),
277
+ tooltipData->width,
278
+ tooltipData->height,
279
+ parentHwnd,
280
+ NULL,
281
+ hInstance,
282
+ tooltipData.get());
283
+
284
+ DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUNDSMALL;
285
+ UINT borderThickness = 0;
286
+ DwmSetWindowAttribute(m_hwndTip, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));
287
+
288
+ tooltipData.release();
289
+ AnimateWindow(m_hwndTip, toolTipAnimationTimeMs, AW_BLEND);
290
+ }
291
+ }
292
+
293
+ void TooltipTracker::DestroyTooltip() noexcept {
294
+ if (m_hwndTip) {
295
+ AnimateWindow(m_hwndTip, toolTipAnimationTimeMs, AW_BLEND | AW_HIDE);
296
+ DestroyWindow(m_hwndTip);
297
+ m_hwndTip = nullptr;
298
+ }
299
+ }
300
+
301
+ void TooltipTracker::DestroyTimer() noexcept {
302
+ if (m_timer) {
303
+ m_timer.Stop();
304
+ m_timer = nullptr;
305
+ }
306
+ }
307
+
308
+ TooltipService::TooltipService(const winrt::Microsoft::ReactNative::ReactPropertyBag &properties)
309
+ : m_properties(properties) {}
310
+
311
+ void TooltipService::StartTracking(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
312
+ m_trackers.push_back(std::make_shared<TooltipTracker>(view, m_properties, this));
313
+ }
314
+
315
+ void TooltipService::StopTracking(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
316
+ for (auto it = m_trackers.begin(); it != m_trackers.end();) {
317
+ if ((*it)->Tag() == view.Tag())
318
+ it = m_trackers.erase(it);
319
+ else
320
+ ++it;
321
+ }
322
+ }
323
+
324
+ static const ReactPropertyId<winrt::Microsoft::ReactNative::ReactNonAbiValue<std::shared_ptr<TooltipService>>>
325
+ &TooltipServicePropertyId() noexcept {
326
+ static const ReactPropertyId<winrt::Microsoft::ReactNative::ReactNonAbiValue<std::shared_ptr<TooltipService>>> prop{
327
+ L"ReactNative", L"TooltipService"};
328
+ return prop;
329
+ }
330
+
331
+ std::shared_ptr<TooltipService> TooltipService::GetCurrent(
332
+ const winrt::Microsoft::ReactNative::ReactPropertyBag &properties) noexcept {
333
+ return *properties.GetOrCreate(TooltipServicePropertyId(), [properties]() -> std::shared_ptr<TooltipService> {
334
+ return std::make_shared<TooltipService>(properties);
335
+ });
336
+ }
337
+
338
+ } // namespace winrt::Microsoft::ReactNative
@@ -0,0 +1,66 @@
1
+
2
+ // Copyright (c) Microsoft Corporation.
3
+ // Licensed under the MIT License.
4
+
5
+ #pragma once
6
+
7
+ #include <Fabric/ReactTaggedView.h>
8
+ #include <winrt/Microsoft.ReactNative.h>
9
+
10
+ namespace winrt::Microsoft::ReactNative {
11
+
12
+ struct TooltipService;
13
+
14
+ struct TooltipTracker {
15
+ TooltipTracker(
16
+ const winrt::Microsoft::ReactNative::ComponentView &view,
17
+ const winrt::Microsoft::ReactNative::ReactPropertyBag &properties,
18
+ TooltipService *outer);
19
+ ~TooltipTracker();
20
+
21
+ void OnPointerEntered(
22
+ const winrt::Windows::Foundation::IInspectable &sender,
23
+ const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept;
24
+ void OnPointerMoved(
25
+ const winrt::Windows::Foundation::IInspectable &sender,
26
+ const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept;
27
+ void OnPointerExited(
28
+ const winrt::Windows::Foundation::IInspectable &sender,
29
+ const winrt::Microsoft::ReactNative::Composition::Input::PointerRoutedEventArgs &args) noexcept;
30
+ void OnTick(
31
+ const winrt::Windows::Foundation::IInspectable &,
32
+ const winrt::Windows::Foundation::IInspectable &) noexcept;
33
+ void OnUnmounted(
34
+ const winrt::Windows::Foundation::IInspectable &,
35
+ const winrt::Microsoft::ReactNative::ComponentView &) noexcept;
36
+
37
+ facebook::react::Tag Tag() const noexcept;
38
+
39
+ private:
40
+ void ShowTooltip(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept;
41
+ void DestroyTimer() noexcept;
42
+ void DestroyTooltip() noexcept;
43
+
44
+ TooltipService *m_outer;
45
+ winrt::Windows::Foundation::Point m_pos;
46
+ ::Microsoft::ReactNative::ReactTaggedView m_view;
47
+ winrt::Microsoft::ReactNative::ITimer m_timer;
48
+ HWND m_hwndTip{nullptr};
49
+ winrt::Microsoft::ReactNative::ReactPropertyBag m_properties;
50
+ };
51
+
52
+ struct TooltipService {
53
+ TooltipService(const winrt::Microsoft::ReactNative::ReactPropertyBag &properties);
54
+ void StartTracking(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept;
55
+ void StopTracking(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept;
56
+
57
+ static std::shared_ptr<TooltipService> GetCurrent(
58
+ const winrt::Microsoft::ReactNative::ReactPropertyBag &properties) noexcept;
59
+
60
+ private:
61
+ std::vector<std::shared_ptr<TooltipTracker>> m_enteredTrackers;
62
+ std::vector<std::shared_ptr<TooltipTracker>> m_trackers;
63
+ winrt::Microsoft::ReactNative::ReactPropertyBag m_properties;
64
+ };
65
+
66
+ } // namespace winrt::Microsoft::ReactNative
@@ -206,4 +206,12 @@ void DispatchAccessibilityAction(::Microsoft::ReactNative::ReactTaggedView &view
206
206
  }
207
207
  }
208
208
 
209
+ ExpandCollapseState GetExpandCollapseState(const bool &expanded) noexcept {
210
+ if (expanded) {
211
+ return ExpandCollapseState_Expanded;
212
+ } else {
213
+ return ExpandCollapseState_Collapsed;
214
+ }
215
+ }
216
+
209
217
  } // namespace winrt::Microsoft::ReactNative::implementation
@@ -35,4 +35,5 @@ std::string extractAccessibilityValue(const facebook::react::AccessibilityValue
35
35
 
36
36
  void DispatchAccessibilityAction(::Microsoft::ReactNative::ReactTaggedView &view, const std::string &action) noexcept;
37
37
 
38
+ ExpandCollapseState GetExpandCollapseState(const bool &expanded) noexcept;
38
39
  } // namespace winrt::Microsoft::ReactNative::implementation
@@ -155,6 +155,9 @@ void FabricUIManager::startSurface(
155
155
 
156
156
  void FabricUIManager::stopSurface(facebook::react::SurfaceId surfaceId) noexcept {
157
157
  m_surfaceManager->stopSurface(surfaceId);
158
+ auto &rootDescriptor = m_registry.componentViewDescriptorWithTag(surfaceId);
159
+ m_registry.enqueueComponentViewWithComponentHandle(
160
+ facebook::react::RootShadowNode::Handle(), surfaceId, rootDescriptor);
158
161
  }
159
162
 
160
163
  winrt::Microsoft::ReactNative::ReactNativeIsland FabricUIManager::GetReactNativeIsland(
@@ -31,6 +31,10 @@ struct ReactTaggedView {
31
31
  return strongView;
32
32
  }
33
33
 
34
+ facebook::react::Tag Tag() const noexcept {
35
+ return m_tag;
36
+ }
37
+
34
38
  private:
35
39
  facebook::react::Tag m_tag;
36
40
  winrt::weak_ref<winrt::Microsoft::ReactNative::ComponentView> m_view;
@@ -27,6 +27,10 @@ HostPlatformViewProps::HostPlatformViewProps(
27
27
  CoreFeatures::enablePropIteratorSetter
28
28
  ? sourceProps.focusable
29
29
  : convertRawProp(context, rawProps, "focusable", sourceProps.focusable, {})),
30
+ tooltip(
31
+ CoreFeatures::enablePropIteratorSetter
32
+ ? sourceProps.tooltip
33
+ : convertRawProp(context, rawProps, "tooltip", sourceProps.tooltip, {})),
30
34
  accessibilityPosInSet(
31
35
  CoreFeatures::enablePropIteratorSetter
32
36
  ? sourceProps.accessibilityPosInSet
@@ -82,6 +86,7 @@ void HostPlatformViewProps::setProp(
82
86
  RAW_SET_PROP_SWITCH_CASE_BASIC(accessibilityLiveRegion);
83
87
  RAW_SET_PROP_SWITCH_CASE_BASIC(keyDownEvents);
84
88
  RAW_SET_PROP_SWITCH_CASE_BASIC(keyUpEvents);
89
+ RAW_SET_PROP_SWITCH_CASE_BASIC(tooltip);
85
90
  }
86
91
  }
87
92
 
@@ -29,7 +29,7 @@ class HostPlatformViewProps : public BaseViewProps {
29
29
  std::string accessibilityLiveRegion{"none"};
30
30
 
31
31
  // std::optional<std::string> overflowAnchor{};
32
- // std::optional<std::string> tooltip{};
32
+ std::optional<std::string> tooltip{};
33
33
  std::vector<HandledKeyEvent> keyDownEvents{};
34
34
  std::vector<HandledKeyEvent> keyUpEvents{};
35
35
  };
@@ -13,7 +13,7 @@ inline bool formsStackingContext(ViewProps const &viewProps) {
13
13
  // Only Views which are marked as focusable can actually trigger the events, which will already avoid being collapsed.
14
14
  constexpr decltype(WindowsViewEvents::bits) focusEventsMask = {
15
15
  (1 << (int)WindowsViewEvents::Offset::Focus) & (1 << (int)WindowsViewEvents::Offset::Blur)};
16
- return (viewProps.windowsEvents.bits & focusEventsMask).any();
16
+ return (viewProps.windowsEvents.bits & focusEventsMask).any() || viewProps.tooltip;
17
17
  }
18
18
 
19
19
  inline bool formsView(ViewProps const &viewProps) {
@@ -144,7 +144,7 @@
144
144
  <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
145
145
  </ClCompile>
146
146
  <Link>
147
- <AdditionalDependencies>winsqlite3.lib;ChakraRT.lib;dxguid.lib;dloadhelper.lib;OneCoreUap_apiset.lib;%(AdditionalDependencies)</AdditionalDependencies>
147
+ <AdditionalDependencies>winsqlite3.lib;ChakraRT.lib;dxguid.lib;dloadhelper.lib;OneCoreUap_apiset.lib;Dwmapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
148
148
  <DelayLoadDLLs>
149
149
  api-ms-win-core-file-l1-2-0.dll;
150
150
  api-ms-win-core-windowserrorreporting-l1-1-0.dll;
@@ -53,7 +53,6 @@ struct ReactCoreInjection : ReactCoreInjectionT<ReactCoreInjection> {
53
53
  static uint64_t GetTopLevelWindowId(const IReactPropertyBag &properties) noexcept;
54
54
  static void SetTopLevelWindowId(const IReactPropertyBag &properties, uint64_t windowId) noexcept;
55
55
 
56
- static ITimer CreateTimer(const IReactPropertyBag &properties);
57
56
  static TimerFactory GetTimerFactory(const IReactPropertyBag &properties) noexcept;
58
57
  static void SetTimerFactory(const IReactPropertyBag &properties, const TimerFactory &timerFactory) noexcept;
59
58
  };
@@ -400,9 +400,12 @@ void ReactInstanceWin::LoadModules(
400
400
  }
401
401
  #endif
402
402
 
403
- registerTurboModule(
404
- L"SampleTurboModule",
405
- winrt::Microsoft::ReactNative::MakeTurboModuleProvider<::Microsoft::ReactNative::SampleTurboModule>());
403
+ if (!m_options.UseWebDebugger()) {
404
+ turboModulesProvider->AddModuleProvider(
405
+ L"SampleTurboModule",
406
+ winrt::Microsoft::ReactNative::MakeTurboModuleProvider<::Microsoft::ReactNative::SampleTurboModule>(),
407
+ false);
408
+ }
406
409
 
407
410
  if (devSettings->useTurboModulesOnly) {
408
411
  ::Microsoft::ReactNative::ExceptionsManager::SetRedBoxHander(
@@ -680,8 +683,16 @@ void ReactInstanceWin::InitializeBridgeless() noexcept {
680
683
  return turboModuleManager->getModule(name);
681
684
  };
682
685
 
686
+ // Use a legacy native module binding that always returns null
687
+ // This means that calls to NativeModules.XXX will always return null, rather than crashing on access
688
+ auto legacyNativeModuleBinding =
689
+ [](const std::string & /*name*/) -> std::shared_ptr<facebook::react::TurboModule> { return nullptr; };
690
+
683
691
  facebook::react::TurboModuleBinding::install(
684
- runtime, std::function(binding), nullptr, m_options.TurboModuleProvider->LongLivedObjectCollection());
692
+ runtime,
693
+ std::function(binding),
694
+ std::function(legacyNativeModuleBinding),
695
+ m_options.TurboModuleProvider->LongLivedObjectCollection());
685
696
 
686
697
  auto componentDescriptorRegistry =
687
698
  Microsoft::ReactNative::WindowsComponentDescriptorRegistry::FromProperties(