forked from microsoft/react-native-windows
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXamlIslandUtils.cpp
72 lines (63 loc) · 3.38 KB
/
XamlIslandUtils.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include "Utils/XamlIslandUtils.h"
#include <UI.Xaml.Input.h>
namespace Microsoft::ReactNative {
struct CustomAppBarButton : xaml::Controls::AppBarButtonT<CustomAppBarButton> {
void OnPointerExited(xaml::Input::PointerRoutedEventArgs const &e) {
// This method crashes in the superclass, so we purposely don't call super. But the superclass
// implementation likely cancels a timer that will show the submenu shortly after pointer enter.
// Since we don't have access to that timer, instead we reset the Flyout property, which resets
// the timer. This also fixes a crash where you can get a zombie submenu showing if the app
// loses focus while this timer is scheduled to show the submenu.
if (auto flyout = this->Flyout()) {
this->Flyout(nullptr);
this->Flyout(flyout);
}
// The superclass implementation resets the button to the normal state, so we do this ourselves.
this->SetValue(xaml::Controls::Primitives::ButtonBase::IsPointerOverProperty(), winrt::box_value(false));
xaml::VisualStateManager::GoToState(*this, L"Normal", false);
}
void OnPointerPressed(xaml::Input::PointerRoutedEventArgs const &e) {
// Clicking AppBarButton by default will dismiss the menu, but since we only use this class for
// submenus we override it to be a no-op so it behaves like MenuFlyoutSubItem.
}
};
void FixProofingMenuCrashForXamlIsland(xaml::Controls::Primitives::FlyoutBase const &flyout) {
flyout.Opening([](winrt::IInspectable const &sender, auto &&) {
const auto &flyout = sender.as<winrt::Microsoft::UI::Xaml::Controls::TextCommandBarFlyout>();
if (const auto &textBox = flyout.Target().try_as<xaml::Controls::TextBox>()) {
const auto &commands = flyout.SecondaryCommands();
for (uint32_t i = 0; i < commands.Size(); ++i) {
if (const auto &appBarButton = commands.GetAt(i).try_as<xaml::Controls::AppBarButton>()) {
if (!appBarButton.Flyout()) {
// This works around a loss of focus from the target element when clicking on
// on the menu items.
// https://github.com/microsoft/microsoft-ui-xaml/issues/5818
appBarButton.Click([weakCommandBarFlyout = winrt::make_weak(flyout)](auto &&...) {
if (auto flyout = weakCommandBarFlyout.get()) {
xaml::Input::FocusManager::TryFocusAsync(flyout.Target(), xaml::FocusState::Programmatic);
}
});
} else if (appBarButton.Flyout() == textBox.ProofingMenuFlyout()) {
if (!appBarButton.try_as<CustomAppBarButton>()) {
// Replace the AppBarButton for the proofing menu with one that doesn't crash
const auto customAppBarButton = winrt::make<CustomAppBarButton>();
customAppBarButton.Label(appBarButton.Label());
customAppBarButton.Icon(appBarButton.Icon());
customAppBarButton.Flyout(appBarButton.Flyout());
commands.RemoveAt(i);
commands.InsertAt(i, customAppBarButton);
} else if (!textBox.IsSpellCheckEnabled()) {
// Remove proofing menu option if spell-check is disabled
commands.RemoveAt(i);
}
// There is only one proofing menu option
break;
}
}
}
}
});
}
} // namespace Microsoft::ReactNative