Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fabric] implement tooltip property #13941

Merged
merged 11 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "[Fabric] implement view tooltip property",
"packageName": "react-native-windows",
"email": "30809111+acoates-ms@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6085,12 +6085,24 @@ exports[`View Tests Views can have tooltips 1`] = `
"_Props": {},
},
{
"Type": "Microsoft.ReactNative.Composition.ParagraphComponentView",
"Type": "Microsoft.ReactNative.Composition.ViewComponentView",
"_Props": {},
"__Children": [
{
"Type": "Microsoft.ReactNative.Composition.ParagraphComponentView",
"_Props": {},
},
],
},
{
"Type": "Microsoft.ReactNative.Composition.ParagraphComponentView",
"Type": "Microsoft.ReactNative.Composition.ViewComponentView",
"_Props": {},
"__Children": [
{
"Type": "Microsoft.ReactNative.Composition.ParagraphComponentView",
"_Props": {},
},
],
},
],
},
Expand Down Expand Up @@ -6126,6 +6138,25 @@ exports[`View Tests Views can have tooltips 1`] = `
"Offset": "0, 0, 0",
"Size": "916, 15",
"Visual Type": "SpriteVisual",
"__Children": [
{
"Offset": "0, 0, 0",
"Size": "916, 15",
"Visual Type": "SpriteVisual",
"__Children": [
{
"Offset": "0, 0, 0",
"Size": "916, 15",
"Visual Type": "SpriteVisual",
},
{
"Offset": "0, 0, 0",
"Size": "0, 0",
"Visual Type": "SpriteVisual",
},
],
},
],
},
{
"Offset": "0, 0, 0",
Expand All @@ -6136,13 +6167,32 @@ exports[`View Tests Views can have tooltips 1`] = `
},
{
"Offset": "0, 29, 0",
"Size": "916, 16",
"Size": "916, 14",
"Visual Type": "SpriteVisual",
"__Children": [
{
"Offset": "0, 0, 0",
"Size": "916, 16",
"Size": "916, 14",
"Visual Type": "SpriteVisual",
"__Children": [
{
"Offset": "0, 0, 0",
"Size": "916, 16",
"Visual Type": "SpriteVisual",
"__Children": [
{
"Offset": "0, 0, 0",
"Size": "916, 16",
"Visual Type": "SpriteVisual",
},
{
"Offset": "0, 0, 0",
"Size": "0, 0",
"Visual Type": "SpriteVisual",
},
],
},
],
},
{
"Offset": "0, 0, 0",
Expand Down
1 change: 1 addition & 0 deletions vnext/Desktop.DLL/React.Windows.Desktop.DLL.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
comsuppw.lib;
Shlwapi.lib;
Version.lib;
Dwmapi.lib;
WindowsApp_downlevel.lib;
%(AdditionalDependencies)
</AdditionalDependencies>
Expand Down
12 changes: 12 additions & 0 deletions vnext/Microsoft.ReactNative/Fabric/ComponentView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <Fabric/Composition/RootComponentView.h>
#include "AbiEventEmitter.h"
#include "AbiShadowNode.h"
#include "ReactCoreInjection.h"

namespace winrt::Microsoft::ReactNative::Composition::implementation {
struct RootComponentView;
Expand Down Expand Up @@ -262,6 +263,17 @@ void ComponentView::HandleCommand(const winrt::Microsoft::ReactNative::HandleCom
}
}

HWND ComponentView::GetHwndForParenting() noexcept {
if (m_parent) {
return winrt::get_self<winrt::Microsoft::ReactNative::implementation::ComponentView>(m_parent)
->GetHwndForParenting();
}

// Fallback if we do not know any more specific HWND
return reinterpret_cast<HWND>(winrt::Microsoft::ReactNative::implementation::ReactCoreInjection::GetTopLevelWindowId(
m_reactContext.Properties().Handle()));
}

winrt::Microsoft::ReactNative::Composition::implementation::RootComponentView *ComponentView::rootComponentView()
const noexcept {
if (m_rootView)
Expand Down
3 changes: 3 additions & 0 deletions vnext/Microsoft.ReactNative/Fabric/ComponentView.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ struct ComponentView : public ComponentViewT<ComponentView> {
// Notify up the tree to bring the rect into view by scrolling as needed
virtual void StartBringIntoView(BringIntoViewOptions &&args) noexcept;

// Eventually PopupContentLink and similar APIs will remove the need for this.
virtual HWND GetHwndForParenting() noexcept;

virtual const winrt::Microsoft::ReactNative::IComponentProps userProps(
facebook::react::Props::Shared const &props) noexcept;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "CompositionHelpers.h"
#include "RootComponentView.h"
#include "Theme.h"
#include "TooltipService.h"
#include "UiaHelpers.h"
#include "d2d1helper.h"

Expand All @@ -43,6 +44,13 @@ ComponentView::ComponentView(
m_outerVisual.InsertAt(m_focusVisual.InnerVisual(), 0);
}

ComponentView::~ComponentView() {
if (m_tooltipTracked) {
TooltipService::GetCurrent(m_reactContext.Properties())->StopTracking(*this);
m_tooltipTracked = false;
}
}

facebook::react::Tag ComponentView::Tag() const noexcept {
return m_tag;
}
Expand Down Expand Up @@ -130,6 +138,16 @@ void ComponentView::updateProps(
updateShadowProps(oldViewProps, newViewProps);
}

if (oldViewProps.tooltip != newViewProps.tooltip) {
if (!m_tooltipTracked && newViewProps.tooltip) {
TooltipService::GetCurrent(m_reactContext.Properties())->StartTracking(*this);
m_tooltipTracked = true;
} else if (m_tooltipTracked && !newViewProps.tooltip) {
TooltipService::GetCurrent(m_reactContext.Properties())->StopTracking(*this);
m_tooltipTracked = false;
}
}

base_type::updateProps(props, oldProps);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct ComponentView : public ComponentViewT<
facebook::react::Tag tag,
winrt::Microsoft::ReactNative::ReactContext const &reactContext,
ComponentViewFeatures flags);
virtual ~ComponentView();

virtual winrt::Microsoft::ReactNative::Composition::Experimental::IVisual Visual() const noexcept {
return nullptr;
Expand Down Expand Up @@ -151,6 +152,7 @@ struct ComponentView : public ComponentViewT<
const facebook::react::ViewProps &viewProps) noexcept;

bool m_FinalizeTransform{false};
bool m_tooltipTracked{false};
ComponentViewFeatures m_flags;
void showFocusVisual(bool show) noexcept;
winrt::Microsoft::ReactNative::Composition::Experimental::IFocusVisual m_focusVisual{nullptr};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ winrt::IInspectable ReactNativeIsland::GetUiaProvider() noexcept {
if (m_uiaProvider == nullptr) {
m_uiaProvider =
winrt::make<winrt::Microsoft::ReactNative::implementation::CompositionRootAutomationProvider>(*this);
if (m_hwnd) {
if (m_hwnd && !m_island) {
auto pRootProvider =
static_cast<winrt::Microsoft::ReactNative::implementation::CompositionRootAutomationProvider *>(
m_uiaProvider.as<IRawElementProviderSimple>().get());
Expand All @@ -348,6 +348,10 @@ void ReactNativeIsland::SetWindow(uint64_t hwnd) noexcept {
m_hwnd = reinterpret_cast<HWND>(hwnd);
}

HWND ReactNativeIsland::GetHwndForParenting() noexcept {
return m_hwnd;
}

int64_t ReactNativeIsland::SendMessage(uint32_t msg, uint64_t wParam, int64_t lParam) noexcept {
if (m_rootTag == -1)
return 0;
Expand All @@ -367,7 +371,7 @@ int64_t ReactNativeIsland::SendMessage(uint32_t msg, uint64_t wParam, int64_t lP
bool ReactNativeIsland::CapturePointer(
const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
facebook::react::Tag tag) noexcept {
if (m_hwnd) {
if (m_hwnd && !m_island) {
SetCapture(m_hwnd);
}
return m_CompositionEventHandler->CapturePointer(pointer, tag);
Expand All @@ -377,7 +381,7 @@ void ReactNativeIsland::ReleasePointerCapture(
const winrt::Microsoft::ReactNative::Composition::Input::Pointer &pointer,
facebook::react::Tag tag) noexcept {
if (m_CompositionEventHandler->ReleasePointerCapture(pointer, tag)) {
if (m_hwnd) {
if (m_hwnd && !m_island) {
if (m_hwnd == GetCapture()) {
ReleaseCapture();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct ReactNativeIsland
void AddRenderedVisual(const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept;
void RemoveRenderedVisual(const winrt::Microsoft::ReactNative::Composition::Experimental::IVisual &visual) noexcept;
bool TrySetFocus() noexcept;
HWND GetHwndForParenting() noexcept;

winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader Resources() noexcept;
void Resources(const winrt::Microsoft::ReactNative::Composition::ICustomResourceLoader &resources) noexcept;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,4 +231,15 @@ winrt::Microsoft::ReactNative::implementation::ClipState RootComponentView::getC
return winrt::Microsoft::ReactNative::implementation::ClipState::NoClip;
}

HWND RootComponentView::GetHwndForParenting() noexcept {
if (auto rootView = m_wkRootView.get()) {
auto hwnd = winrt::get_self<winrt::Microsoft::ReactNative::implementation::ReactNativeIsland>(rootView)
->GetHwndForParenting();
if (hwnd)
return hwnd;
}

return base_type::GetHwndForParenting();
}

} // namespace winrt::Microsoft::ReactNative::Composition::implementation
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ struct RootComponentView : RootComponentViewT<RootComponentView, ViewComponentVi
winrt::Microsoft::ReactNative::ComponentView FindFirstFocusableElement() noexcept;
winrt::Microsoft::ReactNative::ComponentView FindLastFocusableElement() noexcept;

HWND GetHwndForParenting() noexcept override;

private:
// should this be a ReactTaggedView? - It shouldn't actually matter since if the view is going away it should always
// be clearing its focus But being a reactTaggedView might make it easier to identify cases where that isn't
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
namespace winrt::Microsoft::ReactNative::Composition {

void RenderText(
ID2D1DeviceContext &deviceContext,
ID2D1RenderTarget &deviceContext,
::IDWriteTextLayout &textLayout,
const facebook::react::AttributedString &attributedString,
const facebook::react::TextAttributes &textAttributes,
Expand All @@ -26,7 +26,6 @@ void RenderText(
float offsetX = offset.x / pointScaleFactor;
float offsetY = offset.y / pointScaleFactor;

assert(deviceContext.GetUnitMode() == D2D1_UNIT_MODE_DIPS);
const auto dpi = pointScaleFactor * 96.0f;
float oldDpiX, oldDpiY;
deviceContext.GetDpi(&oldDpiX, &oldDpiY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
namespace winrt::Microsoft::ReactNative::Composition {

void RenderText(
ID2D1DeviceContext &deviceContext,
ID2D1RenderTarget &deviceContext,
::IDWriteTextLayout &textLayout,
const facebook::react::AttributedString &attributedString,
const facebook::react::TextAttributes &textAttributes,
Expand Down
16 changes: 12 additions & 4 deletions vnext/Microsoft.ReactNative/Fabric/Composition/Theme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
{"ScrollBarThumbFillDisabled", "ControlStrongFillColorDisabled"},
{"ScrollBarTrackFill",
"AcrylicInAppFillColorDefault"}, // TODO make AcrylicInAppFillColorDefault a real acrylic brush
};
{"ToolTipBackground", "SystemChromeMediumLowColor"},
{"ToolTipForeground", "SystemControlForegroundBaseHighColor"},
{"ToolTipBorderBrush", "SystemControlTransientBorderColor"}};

static std::unordered_map<std::string, winrt::Windows::UI::Color, std::hash<std::string_view>, std::equal_to<>>
s_lightColors = {
Expand Down Expand Up @@ -326,7 +328,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
{"ControlStrongFillColorDefault", {0x72, 0x00, 0x00, 0x00}},
{"ControlStrongFillColorDisabled", {0x51, 0x00, 0x00, 0x00}},
{"AcrylicInAppFillColorDefault", {0x9E, 0xFF, 0xFF, 0xFF}},
};
{"SystemChromeMediumLowColor", {0xFF, 0xF2, 0xF2, 0xF2}},
{"SystemControlForegroundBaseHighColor", {0xFF, 0x00, 0x00, 0x00}},
{"SystemControlTransientBorderColor", {0x24, 0x00, 0x00, 0x00}}};

static std::unordered_map<std::string, winrt::Windows::UI::Color, std::hash<std::string_view>, std::equal_to<>>
s_darkColors = {
Expand Down Expand Up @@ -356,7 +360,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
{"ControlStrongFillColorDefault", {0x8B, 0xFF, 0xFF, 0xFF}},
{"ControlStrongFillColorDisabled", {0x3F, 0xFF, 0xFF, 0xFF}},
{"AcrylicInAppFillColorDefault", {0x9E, 0x00, 0x00, 0x00}},
};
{"SystemChromeMediumLowColor", {0xFF, 0x2B, 0x2B, 0x2B}},
{"SystemControlForegroundBaseHighColor", {0xFF, 0xFF, 0xFF, 0xFF}},
{"SystemControlTransientBorderColor", {0x5C, 0x00, 0x00, 0x00}}};

static std::unordered_map<
std::string,
Expand Down Expand Up @@ -391,7 +397,9 @@ bool Theme::TryGetPlatformColor(const std::string &platformColor, winrt::Windows
{"SubtleFillColorSecondary", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
{"ControlStrongFillColorDefault", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
{"ControlStrongFillColorDisabled", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
};
{"SystemChromeMediumLowColor", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonFace, {}}},
{"SystemControlForegroundBaseHighColor", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonText, {}}},
{"SystemControlTransientBorderColor", {winrt::Windows::UI::ViewManagement::UIElementType::ButtonText, {}}}};

auto alias = s_xamlAliasedColors.find(platformColor);
if (alias != s_xamlAliasedColors.end()) {
Expand Down
Loading
Loading