react-native-windows 0.74.20 → 0.74.22

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 (94) hide show
  1. package/Microsoft.ReactNative/ComponentView.idl +44 -32
  2. package/Microsoft.ReactNative/Composition.Input.idl +3 -0
  3. package/Microsoft.ReactNative/CompositionComponentView.idl +43 -24
  4. package/Microsoft.ReactNative/CompositionSwitcher.idl +3 -0
  5. package/Microsoft.ReactNative/Fabric/AbiEventEmitter.cpp +21 -0
  6. package/Microsoft.ReactNative/Fabric/AbiEventEmitter.h +23 -0
  7. package/Microsoft.ReactNative/Fabric/AbiShadowNode.cpp +7 -0
  8. package/Microsoft.ReactNative/Fabric/AbiShadowNode.h +3 -0
  9. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +334 -65
  10. package/Microsoft.ReactNative/Fabric/ComponentView.h +162 -38
  11. package/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp +2 -2
  12. package/Microsoft.ReactNative/Fabric/Composition/ComponentViewRegistry.cpp +3 -0
  13. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.cpp +29 -7
  14. package/Microsoft.ReactNative/Fabric/Composition/Composition.Input.h +23 -4
  15. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +44 -13
  16. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +118 -0
  17. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +12 -1
  18. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +147 -119
  19. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +4 -8
  20. package/Microsoft.ReactNative/Fabric/Composition/CompositionHwndHost.cpp +1 -0
  21. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +129 -106
  22. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +31 -54
  23. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +133 -0
  24. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +61 -0
  25. package/Microsoft.ReactNative/Fabric/Composition/DebuggingOverlayComponentView.cpp +9 -8
  26. package/Microsoft.ReactNative/Fabric/Composition/DebuggingOverlayComponentView.h +1 -2
  27. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +20 -6
  28. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +13 -6
  29. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +1 -4
  30. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +3 -5
  31. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.h +1 -2
  32. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +1 -6
  33. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.h +0 -1
  34. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.cpp +108 -18
  35. package/Microsoft.ReactNative/Fabric/Composition/ReactCompositionViewComponentBuilder.h +33 -5
  36. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +137 -56
  37. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +21 -4
  38. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +45 -10
  39. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +9 -2
  40. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +209 -189
  41. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +2 -5
  42. package/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.cpp +22 -10
  43. package/Microsoft.ReactNative/Fabric/Composition/SwitchComponentView.h +4 -5
  44. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.cpp +1 -2
  45. package/Microsoft.ReactNative/Fabric/Composition/TextDrawing.h +1 -1
  46. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +115 -168
  47. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +11 -14
  48. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +14 -11
  49. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +4 -4
  50. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.cpp +0 -13
  51. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputState.h +0 -3
  52. package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +12 -4
  53. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +338 -0
  54. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.h +66 -0
  55. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +56 -4
  56. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +7 -0
  57. package/Microsoft.ReactNative/Fabric/Composition/UnimplementedNativeViewComponentView.cpp +2 -4
  58. package/Microsoft.ReactNative/Fabric/Composition/UnimplementedNativeViewComponentView.h +1 -2
  59. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +40 -9
  60. package/Microsoft.ReactNative/Fabric/ReactTaggedView.h +4 -0
  61. package/Microsoft.ReactNative/Fabric/WindowsComponentDescriptorRegistry.cpp +1 -3
  62. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +25 -1
  63. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +4 -1
  64. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewTraitsInitializer.h +1 -1
  65. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +9 -2
  66. package/Microsoft.ReactNative/IReactCompositionViewComponentBuilder.idl +13 -3
  67. package/Microsoft.ReactNative/IReactViewComponentBuilder.idl +64 -4
  68. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -1
  69. package/Microsoft.ReactNative/Modules/LogBoxModule.cpp +9 -0
  70. package/Microsoft.ReactNative/Modules/LogBoxModule.h +2 -0
  71. package/Microsoft.ReactNative/Modules/SampleTurboModule.cpp +104 -0
  72. package/Microsoft.ReactNative/Modules/SampleTurboModule.h +78 -0
  73. package/Microsoft.ReactNative/ReactCoreInjection.h +0 -1
  74. package/Microsoft.ReactNative/ReactHost/MsoReactContext.cpp +0 -7
  75. package/Microsoft.ReactNative/ReactHost/MsoReactContext.h +0 -5
  76. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +17 -1
  77. package/Microsoft.ReactNative/ReactInstanceSettingsBuilder.cpp +59 -0
  78. package/Microsoft.ReactNative/ReactInstanceSettingsBuilder.h +23 -0
  79. package/Microsoft.ReactNative/ReactNativeAppBuilder.cpp +179 -0
  80. package/Microsoft.ReactNative/ReactNativeAppBuilder.h +35 -0
  81. package/Microsoft.ReactNative/ReactNativeAppBuilder.idl +69 -0
  82. package/Microsoft.ReactNative/ReactNativeIsland.idl +5 -0
  83. package/Microsoft.ReactNative/ReactNativeWin32App.cpp +82 -0
  84. package/Microsoft.ReactNative/ReactNativeWin32App.h +38 -0
  85. package/Microsoft.ReactNative/Timer.idl +1 -1
  86. package/Microsoft.ReactNative/packages.lock.json +0 -10
  87. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  88. package/PropertySheets/WinUI.props +1 -1
  89. package/Shared/Shared.vcxitems +43 -0
  90. package/Shared/Shared.vcxitems.filters +3 -0
  91. package/Shared/TurboModuleManager.cpp +0 -3
  92. package/just-task.js +1 -1
  93. package/package.json +3 -3
  94. package/templates/cpp-app/windows/MyApp/MyApp.cpp +1 -0
@@ -23,10 +23,11 @@ void WindowsTextInputShadowNode::setContextContainer(ContextContainer *contextCo
23
23
  m_contextContainer = contextContainer;
24
24
  }
25
25
 
26
- AttributedString WindowsTextInputShadowNode::getAttributedString() const {
26
+ AttributedString WindowsTextInputShadowNode::getAttributedString(const LayoutContext &layoutContext) const {
27
27
  // Use BaseTextShadowNode to get attributed string from children
28
28
 
29
29
  auto childTextAttributes = TextAttributes::defaultTextAttributes();
30
+ childTextAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
30
31
 
31
32
  childTextAttributes.apply(getConcreteProps().textAttributes);
32
33
 
@@ -38,6 +39,7 @@ AttributedString WindowsTextInputShadowNode::getAttributedString() const {
38
39
  // value attributes manually.
39
40
  if (!getConcreteProps().text.empty()) {
40
41
  auto textAttributes = TextAttributes::defaultTextAttributes();
42
+ textAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
41
43
  textAttributes.apply(getConcreteProps().textAttributes);
42
44
  auto fragment = AttributedString::Fragment{};
43
45
  fragment.string = getConcreteProps().text;
@@ -59,7 +61,7 @@ AttributedString WindowsTextInputShadowNode::getAttributedString() const {
59
61
  // display at all.
60
62
  // TODO T67606511: We will redefine the measurement of empty strings as part
61
63
  // of T67606511
62
- AttributedString WindowsTextInputShadowNode::getPlaceholderAttributedString() const {
64
+ AttributedString WindowsTextInputShadowNode::getPlaceholderAttributedString(const LayoutContext &layoutContext) const {
63
65
  // Return placeholder text, since text and children are empty.
64
66
  auto textAttributedString = AttributedString{};
65
67
  auto fragment = AttributedString::Fragment{};
@@ -70,6 +72,7 @@ AttributedString WindowsTextInputShadowNode::getPlaceholderAttributedString() co
70
72
  }
71
73
 
72
74
  auto textAttributes = TextAttributes::defaultTextAttributes();
75
+ textAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
73
76
  textAttributes.apply(getConcreteProps().textAttributes);
74
77
 
75
78
  // If there's no text, it's possible that this Fragment isn't actually
@@ -86,10 +89,10 @@ void WindowsTextInputShadowNode::setTextLayoutManager(SharedTextLayoutManager te
86
89
  m_textLayoutManager = std::move(textLayoutManager);
87
90
  }
88
91
 
89
- AttributedString WindowsTextInputShadowNode::getMostRecentAttributedString() const {
92
+ AttributedString WindowsTextInputShadowNode::getMostRecentAttributedString(const LayoutContext &layoutContext) const {
90
93
  const auto &state = getStateData();
91
94
 
92
- auto reactTreeAttributedString = getAttributedString();
95
+ auto reactTreeAttributedString = getAttributedString(layoutContext);
93
96
 
94
97
  // Sometimes the treeAttributedString will only differ from the state
95
98
  // not by inherent properties (string or prop attributes), but by the frame of
@@ -101,10 +104,10 @@ AttributedString WindowsTextInputShadowNode::getMostRecentAttributedString() con
101
104
  return (!treeAttributedStringChanged ? state.attributedString : reactTreeAttributedString);
102
105
  }
103
106
 
104
- void WindowsTextInputShadowNode::updateStateIfNeeded() {
107
+ void WindowsTextInputShadowNode::updateStateIfNeeded(const LayoutContext &layoutContext) {
105
108
  ensureUnsealed();
106
109
 
107
- auto reactTreeAttributedString = getAttributedString();
110
+ auto reactTreeAttributedString = getAttributedString(layoutContext);
108
111
  const auto &state = getStateData();
109
112
 
110
113
  // Tree is often out of sync with the value of the TextInput.
@@ -125,13 +128,13 @@ void WindowsTextInputShadowNode::updateStateIfNeeded() {
125
128
  // in the AttributedString, and when State is updated, it needs some way to
126
129
  // reconstruct a Fragment with default TextAttributes.
127
130
  auto defaultTextAttributes = TextAttributes::defaultTextAttributes();
128
-
131
+ defaultTextAttributes.fontSizeMultiplier = layoutContext.fontSizeMultiplier;
129
132
  defaultTextAttributes.apply(getConcreteProps().textAttributes);
130
133
 
131
134
  auto newEventCount = state.reactTreeAttributedString.isContentEqual(reactTreeAttributedString)
132
135
  ? 0
133
136
  : getConcreteProps().mostRecentEventCount;
134
- auto newAttributedString = getMostRecentAttributedString();
137
+ auto newAttributedString = getMostRecentAttributedString(layoutContext);
135
138
 
136
139
  // Even if we're here and updating state, it may be only to update the layout
137
140
  // manager If that is the case, make sure we don't update text: pass in the
@@ -168,10 +171,10 @@ Size WindowsTextInputShadowNode::measureContent(
168
171
  // during layout, but not during `measure`. If State is out-of-date in layout,
169
172
  // it's too late: measure will have already operated on old State. Thus, we
170
173
  // use the same value here that we *will* use in layout to update the state.
171
- AttributedString attributedString = getMostRecentAttributedString();
174
+ AttributedString attributedString = getMostRecentAttributedString(layoutContext);
172
175
 
173
176
  if (attributedString.isEmpty()) {
174
- attributedString = getPlaceholderAttributedString();
177
+ attributedString = getPlaceholderAttributedString(layoutContext);
175
178
  }
176
179
 
177
180
  if (attributedString.isEmpty() && getStateData().mostRecentEventCount != 0) {
@@ -191,7 +194,7 @@ Size WindowsTextInputShadowNode::measureContent(
191
194
  }
192
195
 
193
196
  void WindowsTextInputShadowNode::layout(LayoutContext layoutContext) {
194
- updateStateIfNeeded();
197
+ updateStateIfNeeded(layoutContext);
195
198
  ConcreteViewShadowNode::layout(layoutContext);
196
199
  }
197
200
 
@@ -41,8 +41,8 @@ class WindowsTextInputShadowNode final : public ConcreteViewShadowNode<
41
41
  /*
42
42
  * Returns a `AttributedString` which represents text content of the node.
43
43
  */
44
- AttributedString getAttributedString() const;
45
- AttributedString getPlaceholderAttributedString() const;
44
+ AttributedString getAttributedString(const LayoutContext &layoutContext) const;
45
+ AttributedString getPlaceholderAttributedString(const LayoutContext &layoutContext) const;
46
46
 
47
47
  /*
48
48
  * Associates a shared TextLayoutManager with the node.
@@ -62,13 +62,13 @@ class WindowsTextInputShadowNode final : public ConcreteViewShadowNode<
62
62
  /**
63
63
  * Get the most up-to-date attributed string for measurement and State.
64
64
  */
65
- AttributedString getMostRecentAttributedString() const;
65
+ AttributedString getMostRecentAttributedString(const LayoutContext &layoutContext) const;
66
66
 
67
67
  /*
68
68
  * Creates a `State` object (with `AttributedText` and
69
69
  * `TextLayoutManager`) if needed.
70
70
  */
71
- void updateStateIfNeeded();
71
+ void updateStateIfNeeded(const LayoutContext &layoutContext);
72
72
 
73
73
  SharedTextLayoutManager m_textLayoutManager;
74
74
 
@@ -31,17 +31,4 @@ WindowsTextInputState::WindowsTextInputState(
31
31
  defaultThemePaddingTop(defaultThemePaddingTop),
32
32
  defaultThemePaddingBottom(defaultThemePaddingBottom) {}
33
33
 
34
- WindowsTextInputState::WindowsTextInputState(const WindowsTextInputState &previousState, const folly::dynamic &data)
35
- : mostRecentEventCount(data.getDefault("mostRecentEventCount", previousState.mostRecentEventCount).getInt()),
36
- cachedAttributedStringId(data.getDefault("opaqueCacheId", previousState.cachedAttributedStringId).getInt()),
37
- attributedString(previousState.attributedString),
38
- reactTreeAttributedString(previousState.reactTreeAttributedString),
39
- paragraphAttributes(previousState.paragraphAttributes),
40
- defaultThemePaddingStart(
41
- data.getDefault("themePaddingStart", previousState.defaultThemePaddingStart).getDouble()),
42
- defaultThemePaddingEnd(data.getDefault("themePaddingEnd", previousState.defaultThemePaddingEnd).getDouble()),
43
- defaultThemePaddingTop(data.getDefault("themePaddingTop", previousState.defaultThemePaddingTop).getDouble()),
44
- defaultThemePaddingBottom(
45
- data.getDefault("themePaddingBottom", previousState.defaultThemePaddingBottom).getDouble()){};
46
-
47
34
  } // namespace facebook::react
@@ -66,9 +66,6 @@ class WindowsTextInputState final {
66
66
  double defaultThemePaddingBottom);
67
67
 
68
68
  WindowsTextInputState() = default;
69
- WindowsTextInputState(const WindowsTextInputState &previousState, const folly::dynamic &data);
70
- folly::dynamic getDynamic() const;
71
- MapBuffer getMapBuffer() const;
72
69
  };
73
70
 
74
71
  } // namespace facebook::react
@@ -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