Skip to content
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": "Emit TextInput onChangeText before onSelectionChange",
"packageName": "react-native-windows",
"email": "erozell@outlook.com",
"dependentChangeType": "patch"
}
36 changes: 36 additions & 0 deletions packages/e2e-test-app/test/LegacyTextInputTest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ describe('LegacyTextInputTest', () => {

expect(await textInput.getText()).toBe('abc\rdef');
});

test('TextInput onChange before onSelectionChange', async () => {
const textInput = await textInputField();
await textInput.setValue('a');
await assertLogContainsInOrder(
'onChange text: a',
'onSelectionChange range: 1,1',
);
});
});

async function textInputField() {
Expand Down Expand Up @@ -101,3 +110,30 @@ async function assertLogContains(text: string) {
},
);
}

async function assertLogContainsInOrder(...expectedLines: string[]) {
const textLogComponent = await $('~textinput-log');

await browser.waitUntil(
async () => {
const loggedText = await textLogComponent.getText();
const actualLines = loggedText.split('\n');
let previousIndex = Number.MAX_VALUE;
for (const line of expectedLines) {
const index = actualLines.findIndex(l => l === line);
if (index === -1 || index > previousIndex) {
return false;
}

previousIndex = index;
}

return true;
},
{
timeoutMsg: `"${await textLogComponent.getText()}" did not contain lines "${expectedLines.join(
', ',
)}"`,
},
);
}
34 changes: 10 additions & 24 deletions vnext/Microsoft.ReactNative/Views/TextInputViewManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@ class TextInputShadowNode : public ShadowNodeBase {

private:
xaml::Controls::TextBox::TextChanging_revoker m_textBoxTextChangingRevoker{};
xaml::Controls::TextBox::TextChanged_revoker m_textBoxTextChangedRevoker{};
xaml::Controls::TextBox::SelectionChanged_revoker m_textBoxSelectionChangedRevoker{};
xaml::Controls::TextBox::ContextMenuOpening_revoker m_textBoxContextMenuOpeningRevoker{};

Expand Down Expand Up @@ -202,35 +201,22 @@ void TextInputShadowNode::registerEvents() {
//
// TextChanging is used to drop the Javascript response of 'A' and expect
// 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 &&) {
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 &&) {
if (m_initialUpdateComplete)
m_nativeEventCount++;
});
}
}

if (m_isTextBox) {
m_passwordBoxPasswordChangedRevoker = {};
m_passwordBoxPasswordChangingRevoker = {};
auto textBox = control.as<xaml::Controls::TextBox>();
m_textBoxTextChangedRevoker = textBox.TextChanged(
m_textBoxTextChangingRevoker = textBox.TextChanging(
winrt::auto_revoke, [=](auto &&, auto &&) { dispatchTextInputChangeEvent(textBox.Text()); });
} else {
m_textBoxTextChangedRevoker = {};
m_textBoxTextChangingRevoker = {};
auto passwordBox = control.as<xaml::Controls::PasswordBox>();
m_passwordBoxPasswordChangedRevoker = passwordBox.PasswordChanged(
winrt::auto_revoke, [=](auto &&, auto &&) { dispatchTextInputChangeEvent(passwordBox.Password()); });
if (control.try_as<xaml::Controls::IPasswordBox4>()) {
m_passwordBoxPasswordChangingRevoker = passwordBox.PasswordChanging(
winrt::auto_revoke, [=](auto &&, auto &&) { dispatchTextInputChangeEvent(passwordBox.Password()); });
} else {
m_passwordBoxPasswordChangedRevoker = passwordBox.PasswordChanged(
winrt::auto_revoke, [=](auto &&, auto &&) { dispatchTextInputChangeEvent(passwordBox.Password()); });
}
}

if (m_isTextBox) {
Expand Down