Skip to content
Closed
Show file tree
Hide file tree
Changes from 10 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 @@
{
"comment": "Fix TextInput clearTextOnSubmit-style behavior regression in Fabric architecture",
"type": "prerelease",
"packageName": "react-native-windows",
"email": "protikbiswas100@microsoft.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,7 @@ const examples: Array<RNTesterModuleExample> = [
},
// [Windows
{
title: 'Clear text on submit',
title: 'Clear text on submitting',
render: function (): React.Node {
return (
<View>
Expand Down Expand Up @@ -799,6 +799,38 @@ const examples: Array<RNTesterModuleExample> = [
);
},
},
{
title: 'Manual clear text on submit (setValue in onSubmitEditing)',
render: function () {
function ManualClearExample() {
const [value, setValue] = React.useState('');
const submitValue = () => {
// Simulate the regression scenario: manual setValue('') during onSubmitEditing
if (value !== '') {
setValue('');
}
};
return (
<View>
<Text>
Manual clear using setValue('') in onSubmitEditing callback:
</Text>
<ExampleTextInput
style={styles.singleLine}
value={value}
onChangeText={setValue}
onSubmitEditing={submitValue}
submitKeyEvents={[{code: 'Enter'}]}
testID="textinput-manual-clear-on-submit"
placeholder="Type text and press Enter to clear"
/>
<Text>Current value: "{value}"</Text>
</View>
);
}
return <ManualClearExample />;
},
},
{
title: 'Stop propagation sample',
render: function (): React.Node {
Expand Down
41 changes: 41 additions & 0 deletions packages/e2e-test-app-fabric/test/TextInputComponentTest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,47 @@ describe('TextInput Tests', () => {
const dump = await dumpVisualTree('textinput-clear-on-submit-4');
expect(dump).toMatchSnapshot();
});
test('TextInputs can manually clear text on submit using setValue in onSubmitEditing', async () => {
const component = await app.findElementByTestID(
'textinput-manual-clear-on-submit',
);
await component.waitForDisplayed({timeout: 5000});

// Enter text in the input
await app.waitUntil(
async () => {
await component.setValue('Hello World');
return (await component.getText()) === 'Hello World';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
},
);

// Verify text was entered
expect(await component.getText()).toBe('Hello World');

// Press Enter to trigger onSubmitEditing which should clear the text
await app.waitUntil(
async () => {
await component.setValue('\uE007'); // Enter key
return (await component.getText()) === '';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Text should be cleared after pressing Enter (manual setValue('') in onSubmitEditing)`,
},
);

// Verify text was cleared
expect(await component.getText()).toBe('');

const dump = await dumpVisualTree('textinput-manual-clear-on-submit');
expect(dump).toMatchSnapshot();
});
test('TextInputs can keep text on focus', async () => {
const componentFocusFalse = await app.findElementByTestID(
'clear-text-on-focus-false',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,13 @@ void WindowsTextInputComponentView::HandleCommand(
std::optional<winrt::hstring> text;

winrt::Microsoft::ReactNative::ReadArgs(args.CommandArgs(), eventCount, text, begin, end);
if (eventCount >= m_nativeEventCount) {
// Accept text updates that match current event count, or clear text operations
// that are one event behind (to handle immediate setValue('') during onSubmitEditing)
bool isEmptyTextUpdate = text.has_value() && text.value().empty();
bool isValidEventCount = eventCount >= m_nativeEventCount;
bool isRecentClearText = isEmptyTextUpdate && (eventCount >= m_nativeEventCount - 1);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still breaking the synchronization logic. What if they do two setValue calls from JS. Or 3. Then the event count would be 2 or 3 values off.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the logic here again, I see your point.
Solution:
Ntaive filres onSubmitEditing with eventCount = m_nativeEventCount (current count N)
JS received the event with eventCount = N
JS immediately calls setValue('') with eventCount = N
Native accepts N >= N (which is true)
The Native increments count for future events


if (isValidEventCount || isRecentClearText) {
m_comingFromJS = true;
{
if (text.has_value()) {
Expand Down
Loading