Skip to content

Commit 486ca2b

Browse files
authored
TextInput and Switcher should respect backgroundColor, borderColor, color props for all interaction states (#3652)
* Ensure TextControl* resource brushes are synchronized with RN backgroundColor, color, and borderColor * extract string constants to StandardControlResourceKeyNames.h * update resource brushs for Switch/ToggleSwitch
1 parent 901fcd9 commit 486ca2b

File tree

8 files changed

+391
-33
lines changed

8 files changed

+391
-33
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"type": "none",
3+
"comment": "fix TextInput and Switch component colors",
4+
"packageName": "react-native-windows",
5+
"email": "robmeyer@microsoft.com",
6+
"commit": "ab50b2508092d9faa2b796821dfbbf0f0847ed7b",
7+
"date": "2019-11-13T23:49:28.167Z"
8+
}

vnext/ReactUWP/ReactUWP.vcxproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,10 @@
166166
<ClInclude Include="Modules\Animated\CalculatedAnimationDriver.h" />
167167
<ClInclude Include="Modules\Animated\SpringAnimationDriver.h" />
168168
<ClInclude Include="Modules\Animated\TrackingAnimatedNode.h" />
169+
<ClInclude Include="Utils\ResourceBrushUtils.h" />
169170
<ClInclude Include="Threading\BatchingUIMessageQueueThread.h" />
170171
<ClInclude Include="Utils\CppWinrtLessExceptions.h" />
172+
<ClInclude Include="Utils\StandardControlResourceKeyNames.h" />
171173
<ClInclude Include="Utils\UwpPreparedScriptStore.h" Condition="'$(OSS_RN)' != 'true'" />
172174
<ClInclude Include="Utils\UwpScriptStore.h" Condition="'$(OSS_RN)' != 'true'" />
173175
<ClInclude Include="Executors\WebSocketJSExecutorUwp.h" />
@@ -267,6 +269,7 @@
267269
<ClCompile Include="Modules\Animated\CalculatedAnimationDriver.cpp" />
268270
<ClCompile Include="Modules\Animated\SpringAnimationDriver.cpp" />
269271
<ClCompile Include="Modules\Animated\TrackingAnimatedNode.cpp" />
272+
<ClCompile Include="Utils\ResourceBrushUtils.cpp" />
270273
<ClCompile Include="Threading\BatchingUIMessageQueueThread.cpp" />
271274
<ClCompile Include="Utils\UwpPreparedScriptStore.cpp" Condition="'$(OSS_RN)' != 'true'" />
272275
<ClCompile Include="Utils\UwpScriptStore.cpp" Condition="'$(OSS_RN)' != 'true'" />
@@ -419,7 +422,8 @@
419422
<DisableReferences>true</DisableReferences>
420423
<HeaderFileName>$(IdlHeaderDirectory)\%(Filename).h</HeaderFileName>
421424
<MetadataFileName>$(UnmergedWinmdDirectory)\%(Filename).winmd</MetadataFileName>
422-
<AdditionalOptions></AdditionalOptions>
425+
<AdditionalOptions>
426+
</AdditionalOptions>
423427
</Midl>
424428
<Midl Include="Views/cppwinrt/BorderEffect.idl" />
425429
<Midl Include="Views/cppwinrt/AccessibilityAction.idl" />

vnext/ReactUWP/ReactUWP.vcxproj.filters

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,10 @@
305305
<ClCompile Include="Views\RefreshControlManager.cpp">
306306
<Filter>Views</Filter>
307307
</ClCompile>
308+
<ClCompile Include="Views\SIPEventHandler.cpp" />
309+
<ClCompile Include="Utils\ResourceBrushUtils.cpp">
310+
<Filter>Utils</Filter>
311+
</ClCompile>
308312
</ItemGroup>
309313
<ItemGroup>
310314
<ClInclude Include="Modules\DeviceInfoModule.h">
@@ -623,6 +627,11 @@
623627
<ClInclude Include="Views\RefreshControlManager.h">
624628
<Filter>Views</Filter>
625629
</ClInclude>
630+
<ClInclude Include="Views\SIPEventHandler.h" />
631+
<ClInclude Include="Utils\ResourceBrushUtils.h">
632+
<Filter>Utils</Filter>
633+
</ClInclude>
634+
<ClInclude Include="Utils\StandardControlResourceKeyNames.h" />
626635
</ItemGroup>
627636
<ItemGroup>
628637
<None Include="EndPoints\dll\react-native-uwp.arm.def">

vnext/ReactUWP/Utils/PropertyUtils.h

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#pragma once
55

6+
#include <Utils/ResourceBrushUtils.h>
67
#include <Utils/ValueUtils.h>
78

89
#include <folly/dynamic.h>
@@ -107,10 +108,14 @@ void SetBorderBrush(const T &element, const winrt::Windows::UI::Xaml::Media::Bru
107108
template <class T>
108109
bool TryUpdateBackgroundBrush(const T &element, const std::string &propertyName, const folly::dynamic &propertyValue) {
109110
if (propertyName == "backgroundColor") {
110-
if (IsValidColorValue(propertyValue))
111-
element.Background(BrushFrom(propertyValue));
112-
else if (propertyValue.isNull())
111+
if (IsValidColorValue(propertyValue)) {
112+
const auto brush = BrushFrom(propertyValue);
113+
element.Background(brush);
114+
UpdateControlBackgroundResourceBrushes(element, brush);
115+
} else if (propertyValue.isNull()) {
113116
element.ClearValue(T::BackgroundProperty());
117+
UpdateControlBackgroundResourceBrushes(element, nullptr);
118+
}
114119

115120
return true;
116121
}
@@ -136,10 +141,14 @@ void UpdateCornerRadiusOnElement(ShadowNodeBase *node, const T &element) {
136141
template <class T>
137142
bool TryUpdateForeground(const T &element, const std::string &propertyName, const folly::dynamic &propertyValue) {
138143
if (propertyName == "color") {
139-
if (IsValidColorValue(propertyValue))
140-
element.Foreground(BrushFrom(propertyValue));
141-
else if (propertyValue.isNull())
144+
if (IsValidColorValue(propertyValue)) {
145+
const auto brush = BrushFrom(propertyValue);
146+
element.Foreground(brush);
147+
UpdateControlForegroundResourceBrushes(element, brush);
148+
} else if (propertyValue.isNull()) {
142149
element.ClearValue(T::ForegroundProperty());
150+
UpdateControlForegroundResourceBrushes(element, nullptr);
151+
}
143152

144153
return true;
145154
}
@@ -156,10 +165,14 @@ bool TryUpdateBorderProperties(
156165
bool isBorderProperty = true;
157166

158167
if (propertyName == "borderColor") {
159-
if (IsValidColorValue(propertyValue))
160-
element.BorderBrush(BrushFrom(propertyValue));
161-
else if (propertyValue.isNull())
168+
if (IsValidColorValue(propertyValue)) {
169+
const auto brush = BrushFrom(propertyValue);
170+
element.BorderBrush(brush);
171+
UpdateControlBorderResourceBrushes(element, brush);
172+
} else if (propertyValue.isNull()) {
162173
element.ClearValue(T::BorderBrushProperty());
174+
UpdateControlBorderResourceBrushes(element, nullptr);
175+
}
163176
} else if (propertyName == "borderLeftWidth") {
164177
if (propertyValue.isNumber())
165178
SetBorderThickness(node, element, ShadowEdges::Left, propertyValue.asDouble());
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#include "pch.h"
5+
6+
#include "ResourceBrushUtils.h"
7+
#include "StandardControlResourceKeyNames.h"
8+
9+
#include <winrt/Windows.UI.Xaml.h>
10+
11+
namespace winrt {
12+
using namespace Windows::UI::Xaml;
13+
using namespace Windows::UI::Xaml::Controls;
14+
} // namespace winrt
15+
16+
namespace react {
17+
namespace uwp {
18+
19+
void UpdateResourceBrush(
20+
const winrt::FrameworkElement &element,
21+
const std::wstring &resourceName,
22+
const winrt::Brush brush) {
23+
const auto resources = element.Resources();
24+
if (resources != nullptr) {
25+
if (brush != nullptr) {
26+
resources.Insert(winrt::box_value(resourceName), brush);
27+
} else {
28+
resources.Remove(winrt::box_value(resourceName));
29+
}
30+
}
31+
}
32+
33+
void UpdateTextControlBackgroundResourceBrushes(const winrt::FrameworkElement &element, const winrt::Brush brush) {
34+
UpdateResourceBrush(element, c_textControlBackground, brush);
35+
UpdateResourceBrush(element, c_textControlBackgroundPointerOver, brush);
36+
UpdateResourceBrush(element, c_textControlBackgroundFocused, brush);
37+
UpdateResourceBrush(element, c_textControlBackgroundDisabled, brush);
38+
39+
UpdateResourceBrush(element, c_textControlButtonForegroundPressed, brush);
40+
}
41+
42+
void UpdateTextControlForegroundResourceBrushes(const winrt::FrameworkElement element, const winrt::Brush brush) {
43+
UpdateResourceBrush(element, c_textControlForeground, brush);
44+
UpdateResourceBrush(element, c_textControlForegroundPointerOver, brush);
45+
UpdateResourceBrush(element, c_textControlForegroundFocused, brush);
46+
UpdateResourceBrush(element, c_textControlForegroundDisabled, brush);
47+
48+
UpdateResourceBrush(element, c_textControlButtonForeground, brush);
49+
UpdateResourceBrush(element, c_textControlButtonForegroundPointerOver, brush);
50+
UpdateResourceBrush(element, c_textControlButtonBackgroundPressed, brush);
51+
}
52+
53+
void UpdateTextControlBorderResourceBrushes(const winrt::FrameworkElement &element, const winrt::Brush brush) {
54+
UpdateResourceBrush(element, c_textControlBorderBrush, brush);
55+
UpdateResourceBrush(element, c_textControlBorderBrushPointerOver, brush);
56+
UpdateResourceBrush(element, c_textControlBorderBrushFocused, brush);
57+
UpdateResourceBrush(element, c_textControlBorderBrushDisabled, brush);
58+
}
59+
60+
void UpdateToggleSwitchBorderResourceBrushes(const winrt::ToggleSwitch &toggleSwitch, const winrt::Brush brush) {
61+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOff, brush);
62+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOffPointerOver, brush);
63+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOffPressed, brush);
64+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOffDisabled, brush);
65+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOn, brush);
66+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOnPointerOver, brush);
67+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOnPressed, brush);
68+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchStrokeOnDisabled, brush);
69+
}
70+
71+
void UpdateToggleSwitchThumbResourceBrushes(const winrt::ToggleSwitch &toggleSwitch, const winrt::Brush thumbBrush) {
72+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOff, thumbBrush);
73+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOffPointerOver, thumbBrush);
74+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOffPressed, thumbBrush);
75+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOffDisabled, thumbBrush);
76+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOn, thumbBrush);
77+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOnPointerOver, thumbBrush);
78+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOnPressed, thumbBrush);
79+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchKnobFillOnDisabled, thumbBrush);
80+
}
81+
82+
void UpdateToggleSwitchTrackResourceBrushes(
83+
const winrt::ToggleSwitch &toggleSwitch,
84+
const winrt::Brush onTrackBrush,
85+
const winrt::Brush offTrackBrush) {
86+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOn, onTrackBrush);
87+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOnPointerOver, onTrackBrush);
88+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOnPressed, onTrackBrush);
89+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOnDisabled, onTrackBrush);
90+
91+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOff, offTrackBrush);
92+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOffPointerOver, offTrackBrush);
93+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOffPressed, offTrackBrush);
94+
UpdateResourceBrush(toggleSwitch, c_toggleSwitchFillOffDisabled, offTrackBrush);
95+
}
96+
97+
bool IsObjectATextControl(const winrt::DependencyObject &object) {
98+
return object.try_as<winrt::TextBox>() != nullptr || object.try_as<winrt::PasswordBox>() != nullptr ||
99+
object.try_as<winrt::RichEditBox>() != nullptr || object.try_as<winrt::AutoSuggestBox>() != nullptr;
100+
}
101+
102+
void UpdateControlBackgroundResourceBrushes(
103+
const winrt::Windows::UI::Xaml::FrameworkElement &element,
104+
const winrt::Media::Brush brush) {
105+
if (IsObjectATextControl(element)) {
106+
UpdateTextControlBackgroundResourceBrushes(element, brush);
107+
}
108+
}
109+
110+
void UpdateControlForegroundResourceBrushes(
111+
const winrt::Windows::UI::Xaml::DependencyObject object,
112+
const winrt::Media::Brush brush) {
113+
if (IsObjectATextControl(object)) {
114+
const auto element = object.try_as<winrt::FrameworkElement>();
115+
UpdateTextControlForegroundResourceBrushes(element, brush);
116+
}
117+
}
118+
119+
void UpdateControlBorderResourceBrushes(
120+
const winrt::Windows::UI::Xaml::FrameworkElement &element,
121+
const winrt::Media::Brush brush) {
122+
if (IsObjectATextControl(element)) {
123+
UpdateTextControlBorderResourceBrushes(element, brush);
124+
} else if (const auto toggleSwitch = element.try_as<winrt::ToggleSwitch>()) {
125+
UpdateToggleSwitchBorderResourceBrushes(toggleSwitch, brush);
126+
}
127+
}
128+
129+
} // namespace uwp
130+
} // namespace react
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
#pragma once
5+
6+
#include <winrt/Windows.UI.Xaml.Media.h>
7+
#include <winrt/Windows.UI.Xaml.h>
8+
#include <winrt/Windows.UI.h>
9+
10+
namespace winrt {
11+
using namespace Windows::UI::Xaml;
12+
using namespace Windows::UI::Xaml::Media;
13+
} // namespace winrt
14+
15+
namespace react {
16+
namespace uwp {
17+
18+
// Some XAML controls use additional resource-brushes that need to be
19+
// kept in sync with the Background, Foreground, and BorderBrush
20+
// DependencyProperties. RN clients (windows-included) that
21+
// want different backgroundColor, color, or borderColor
22+
// depending on interactive states (e.g. PointerOver, Focused,
23+
// and Disabled), expect to handle these state changes in js by
24+
// re-rendering with different props in response to state
25+
// change events (onFocus, onBlur, onMouseEnter, onMouseLeave)
26+
// or when changing enabled/disabled props.
27+
void UpdateControlBackgroundResourceBrushes(
28+
const winrt::Windows::UI::Xaml::FrameworkElement &element,
29+
const winrt::Media::Brush brush);
30+
31+
void UpdateControlForegroundResourceBrushes(
32+
const winrt::Windows::UI::Xaml::DependencyObject object,
33+
const winrt::Media::Brush brush);
34+
35+
void UpdateControlBorderResourceBrushes(
36+
const winrt::Windows::UI::Xaml::FrameworkElement &element,
37+
const winrt::Media::Brush brush);
38+
39+
void UpdateToggleSwitchThumbResourceBrushes(
40+
const winrt::Windows::UI::Xaml::Controls::ToggleSwitch &toggleSwitch,
41+
const winrt::Windows::UI::Xaml::Media::Brush thumbBrush);
42+
43+
void UpdateToggleSwitchTrackResourceBrushes(
44+
const winrt::Windows::UI::Xaml::Controls::ToggleSwitch &toggleSwitch,
45+
const winrt::Windows::UI::Xaml::Media::Brush onTrackBrush,
46+
const winrt::Windows::UI::Xaml::Media::Brush offTrackBrush);
47+
48+
} // namespace uwp
49+
} // namespace react

0 commit comments

Comments
 (0)