-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Proposal: Backport TextInput PRs #7056 #7285 #7658 to 0.63
Summary
Backports TextInput Cursor and Controlled TextInput fixes from 0.64/0.65 to 0.63
Motivation
A lot of TextInput cursor/controlled TextInput behaviour has been fixed recently for 0.65 and 0.64 which is great! Unfortunately not everyone is able to update to 0.64/0.65 at the current point and TextInput is a, I would say, critical component to work correctly.
In our use-case, we aren't able to update to 0.64 due to some issues with native modules and a white screen on production build where I haven't had the time to figure out what is causing it and we're just about to release. See see #7537 for further details.
The changes mentioned in the title though are critical for our App to work correctly from a user-viewpoint.
Basic example
I have created a patch-package fix for myself including the above mentioned PRs:
Would it be possible to integrate that into a 0.63 release or would you rather advice to keep it as a patch with patch-package?
diff --git a/node_modules/react-native-windows/Libraries/Components/TextInput/TextInput.windows.js b/node_modules/react-native-windows/Libraries/Components/TextInput/TextInput.windows.js
index 33114f0..d344cf1 100644
--- a/node_modules/react-native-windows/Libraries/Components/TextInput/TextInput.windows.js
+++ b/node_modules/react-native-windows/Libraries/Components/TextInput/TextInput.windows.js
@@ -1140,6 +1140,7 @@ function InternalTextInput(props: Props): React.Node {
ref={_setNativeRef}
{...props}
dataDetectorTypes={props.dataDetectorTypes}
+ mostRecentEventCount={mostRecentEventCount}
onBlur={_onBlur}
onChange={_onChange}
onContentSizeChange={props.onContentSizeChange}
diff --git a/node_modules/react-native-windows/Microsoft.ReactNative/Views/TextInputViewManager.cpp b/node_modules/react-native-windows/Microsoft.ReactNative/Views/TextInputViewManager.cpp
index 892ca95..1e5d1cd 100644
--- a/node_modules/react-native-windows/Microsoft.ReactNative/Views/TextInputViewManager.cpp
+++ b/node_modules/react-native-windows/Microsoft.ReactNative/Views/TextInputViewManager.cpp
@@ -114,6 +114,7 @@ class TextInputShadowNode : public ShadowNodeBase {
void setPasswordBoxPlaceholderForeground(xaml::Controls::PasswordBox passwordBox, folly::dynamic color);
winrt::Shape FindCaret(xaml::DependencyObject element);
+ bool m_initialUpdateComplete = false;
bool m_shouldClearTextOnFocus = false;
bool m_shouldSelectTextOnFocus = false;
bool m_contextMenuHidden = false;
@@ -153,6 +154,10 @@ void TextInputShadowNode::createView() {
}
void TextInputShadowNode::dispatchTextInputChangeEvent(winrt::hstring newText) {
+ if (!m_initialUpdateComplete) {
+ return;
+ }
+
auto wkinstance = GetViewManager()->GetReactInstance();
if (auto instance = wkinstance.lock()) {
@@ -182,14 +187,20 @@ void TextInputShadowNode::registerEvents() {
// another TextChanged event with correct event count.
if (m_isTextBox) {
m_passwordBoxPasswordChangingRevoker = {};
- m_textBoxTextChangingRevoker = control.as<xaml::Controls::TextBox>().TextChanging(
- winrt::auto_revoke, [=](auto &&, auto &&) { m_nativeEventCount++; });
+ m_textBoxTextChangingRevoker =
+ control.as<xaml::Controls::TextBox>().TextChanging(winrt::auto_revoke, [=](auto &&, auto &&) {
+ if (m_initialUpdateComplete)
+ m_nativeEventCount++;
+ });
} else {
m_textBoxTextChangingRevoker = {};
if (control.try_as<xaml::Controls::IPasswordBox4>()) {
- m_passwordBoxPasswordChangingRevoker = control.as<xaml::Controls::IPasswordBox4>().PasswordChanging(
- winrt::auto_revoke, [=](auto &&, auto &&) { m_nativeEventCount++; });
+ m_passwordBoxPasswordChangingRevoker =
+ control.as<xaml::Controls::IPasswordBox4>().PasswordChanging(winrt::auto_revoke, [=](auto &&, auto &&) {
+ if (m_initialUpdateComplete)
+ m_nativeEventCount++;
+ });
}
}
@@ -556,10 +567,17 @@ void TextInputShadowNode::updateProperties(const folly::dynamic &&props) {
} else if (propertyName == "text") {
if (m_mostRecentEventCount == m_nativeEventCount) {
if (propertyValue.isString()) {
+ auto oldCursor = textBox.SelectionStart();
+ auto oldSelectionLength = textBox.SelectionLength();
auto oldValue = textBox.Text();
auto newValue = asHstring(propertyValue);
if (oldValue != newValue) {
textBox.Text(newValue);
+ if (oldValue.size() == newValue.size()) {
+ textBox.SelectionStart(oldCursor);
+ } else {
+ textBox.SelectionStart(newValue.size());
+ }
}
} else if (propertyValue.isNull())
textBox.ClearValue(xaml::Controls::TextBox::TextProperty());
@@ -596,6 +614,7 @@ void TextInputShadowNode::updateProperties(const folly::dynamic &&props) {
Super::updateProperties(std::move(props));
m_updating = false;
+ m_initialUpdateComplete = true;
}
TextInputViewManager::TextInputViewManager(const std::shared_ptr<IReactInstance> &reactInstance)