Skip to content

Commit

Permalink
[Fabric] Introducing autocapitalize prop in TextInput - Take 2 (micro…
Browse files Browse the repository at this point in the history
…soft#13343)

* New implementation of autocapitalize!

* Change files

* Fixed bug for sentences scenario

* Just keep characters mode for now

* Revert "Just keep characters mode for now"

This reverts commit 60ca1ce.

* Re-apply changes minus packages.json.lock

* The original js file was deleted, re-applying changes

* Fixed snapshot and lint errors

* Fix override mismatch, added comments

* Remove stale test check

* Minor changes

* Update obsolete snapshot
  • Loading branch information
danielayala94 authored and rnbot committed Nov 2, 2024
1 parent 44bc602 commit 4294d05
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 163 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Introduced autocapitalize prop in TextInput",
"packageName": "react-native-windows",
"email": "14967941+danielayala94@users.noreply.github.com",
"dependentChangeType": "patch"
}
63 changes: 53 additions & 10 deletions packages/e2e-test-app-fabric/test/TextInputComponentTest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,39 +96,82 @@ describe('TextInput Tests', () => {
await component.waitForDisplayed({timeout: 5000});
const dump = await dumpVisualTree('capitalize-none');
expect(dump).toMatchSnapshot();

await app.waitUntil(
async () => {
await component.setValue('Hello World');
return (await component.getText()) === 'Hello World';
await component.setValue('hello world');
return (await component.getText()) === 'hello world';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
},
);
expect(await component.getText()).toBe('Hello World');
expect(await component.getText()).toBe('hello world');
});
test('TextInputs can autocapitalize: Autocapitalize Sentences', async () => {
// Comment out once the sentences mode has been implemented.
/*test('TextInputs can autocapitalize: Autocapitalize Sentences', async () => {
const component = await app.findElementByTestID('capitalize-sentences');
await component.waitForDisplayed({timeout: 5000});
const dump = await dumpVisualTree('capitalize-sentences');
expect(dump).toMatchSnapshot();
// Behavior not supported yet.
});
test('TextInputs can autocapitalize: Autocapitalize Words', async () => {
// Test behavior when text is set from JS.
// These TextInputs are currently empty. Setting defaultValue prop for them in TextInputSharedExamples.js
// leads to an "override error". This file is expected to be a exact copy of its RN Core parent.
expect(await component.getText()).toBe('initial text is not capitalized');
await app.waitUntil(
async () => {
await component.setValue('hey here is a sentence. one more sentence? yeah one more sentence! and a last one.');
return (await component.getText()) === 'Hey here is a sentence. One more sentence? Yeah one more sentence! And a last one.';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
});
});*/
// Comment out once the words mode has been implemented.
/*test('TextInputs can autocapitalize: Autocapitalize Words', async () => {
const component = await app.findElementByTestID('capitalize-words');
await component.waitForDisplayed({timeout: 5000});
const dump = await dumpVisualTree('capitalize-words');
expect(dump).toMatchSnapshot();
// Behavior not supported yet.
});
// Test behavior when text is set from JS.
// These TextInputs are currently empty. Setting defaultValue prop for them in TextInputSharedExamples.js
// leads to an "override error". This file is expected to be a exact copy of its RN Core parent.
expect(await component.getText()).toBe('initial text is not capitalized');
await app.waitUntil(
async () => {
await component.setValue('hi i am autocapitalizing all words.');
return (await component.getText()) === 'Hi I Am Autocapitalizing All Words.';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
});
});*/
test('TextInputs can autocapitalize: Autocapitalize Characters', async () => {
const component = await app.findElementByTestID('capitalize-characters');
await component.waitForDisplayed({timeout: 5000});
const dump = await dumpVisualTree('capitalize-characters');
expect(dump).toMatchSnapshot();
// Behavior not supported yet.

await app.waitUntil(
async () => {
await component.setValue('hi i am setting up this whole UPPERCASE sentence.');
return (await component.getText()) === 'HI I AM SETTING UP THIS WHOLE UPPERCASE SENTENCE.';
},
{
interval: 1500,
timeout: 5000,
timeoutMsg: `Unable to enter correct text.`,
});
});
test('TextInputs can have attributed text', async () => {
const component = await app.findElementByTestID('text-input');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,82 +425,6 @@ exports[`TextInput Tests TextInputs can autocapitalize: Autocapitalize Character
}
`;

exports[`TextInput Tests TextInputs can autocapitalize: Autocapitalize Sentences 1`] = `
{
"Automation Tree": {
"AutomationId": "capitalize-sentences",
"ControlType": 50004,
"IsKeyboardFocusable": true,
"LocalizedControlType": "edit",
"ValuePattern.IsReadOnly": false,
},
"Component Tree": {
"Type": "Microsoft.ReactNative.Composition.WindowsTextInputComponentView",
"_Props": {
"TestId": "capitalize-sentences",
},
},
"Visual Tree": {
"Comment": "capitalize-sentences",
"Offset": "0, 0, 0",
"Size": "791, 28",
"Visual Type": "SpriteVisual",
"__Children": [
{
"Offset": "0, 0, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "1, 0, 0",
"Size": "-2, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "-1, 0, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "-1, 1, 0",
"Size": "1, -2",
"Visual Type": "SpriteVisual",
},
{
"Offset": "-1, -1, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "1, -1, 0",
"Size": "-2, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "0, -1, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "0, 1, 0",
"Size": "1, -2",
"Visual Type": "SpriteVisual",
},
{
"Brush": {
"Brush Type": "ColorBrush",
"Color": "rgba(0, 0, 0, 228)",
},
"Offset": "0, 0, 0",
"Opacity": 0,
"Size": "0, 0",
"Visual Type": "SpriteVisual",
},
],
},
}
`;

exports[`TextInput Tests TextInputs can autocapitalize: Autocapitalize Turned Off 1`] = `
{
"Automation Tree": {
Expand Down Expand Up @@ -577,82 +501,6 @@ exports[`TextInput Tests TextInputs can autocapitalize: Autocapitalize Turned Of
}
`;

exports[`TextInput Tests TextInputs can autocapitalize: Autocapitalize Words 1`] = `
{
"Automation Tree": {
"AutomationId": "capitalize-words",
"ControlType": 50004,
"IsKeyboardFocusable": true,
"LocalizedControlType": "edit",
"ValuePattern.IsReadOnly": false,
},
"Component Tree": {
"Type": "Microsoft.ReactNative.Composition.WindowsTextInputComponentView",
"_Props": {
"TestId": "capitalize-words",
},
},
"Visual Tree": {
"Comment": "capitalize-words",
"Offset": "0, 0, 0",
"Size": "791, 29",
"Visual Type": "SpriteVisual",
"__Children": [
{
"Offset": "0, 0, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "1, 0, 0",
"Size": "-2, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "-1, 0, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "-1, 1, 0",
"Size": "1, -2",
"Visual Type": "SpriteVisual",
},
{
"Offset": "-1, -1, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "1, -1, 0",
"Size": "-2, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "0, -1, 0",
"Size": "1, 1",
"Visual Type": "SpriteVisual",
},
{
"Offset": "0, 1, 0",
"Size": "1, -2",
"Visual Type": "SpriteVisual",
},
{
"Brush": {
"Brush Type": "ColorBrush",
"Color": "rgba(0, 0, 0, 228)",
},
"Offset": "0, 0, 0",
"Opacity": 0,
"Size": "0, 0",
"Visual Type": "SpriteVisual",
},
],
},
}
`;

exports[`TextInput Tests TextInputs can autocomplete, address country 1`] = `
{
"Automation Tree": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,7 @@ void WindowsTextInputComponentView::OnCharacterReceived(
emitter->onKeyPress(onKeyPressArgs);

WPARAM wParam = static_cast<WPARAM>(args.KeyCode());

LPARAM lParam = 0;
lParam = args.KeyStatus().RepeatCount; // bits 0-15
lParam |= args.KeyStatus().ScanCode << 16; // bits 16-23
Expand Down Expand Up @@ -1022,6 +1023,10 @@ void WindowsTextInputComponentView::updateProps(
m_submitKeyEvents.clear();
}

if (oldTextInputProps.autoCapitalize != newTextInputProps.autoCapitalize) {
autoCapitalizeOnUpdateProps(oldTextInputProps.autoCapitalize, newTextInputProps.autoCapitalize);
}

UpdatePropertyBits();
}

Expand Down Expand Up @@ -1476,4 +1481,29 @@ winrt::Microsoft::ReactNative::ComponentView WindowsTextInputComponentView::Crea
return winrt::make<WindowsTextInputComponentView>(compContext, tag, reactContext);
}

} // namespace winrt::Microsoft::ReactNative::Composition::implementation
// This function assumes that previous and new capitalization types are different.
void WindowsTextInputComponentView::autoCapitalizeOnUpdateProps(
const std::string &previousCapitalizationType,
const std::string &newCapitalizationType) noexcept {
/*
Possible values are:
Characters - All characters.
Words - First letter of each word.
Sentences - First letter of each sentence.
None - Do not autocapitalize anything.
For now, only characters and none are supported.
*/

if (previousCapitalizationType == "characters") {
winrt::check_hresult(m_textServices->TxSendMessage(
EM_SETEDITSTYLE, 0 /* disable */, SES_UPPERCASE /* flag affected */, nullptr /* LRESULT */));
}

if (newCapitalizationType == "characters") {
winrt::check_hresult(m_textServices->TxSendMessage(
EM_SETEDITSTYLE, SES_UPPERCASE /* enable */, SES_UPPERCASE /* flag affected */, nullptr /* LRESULT */));
}
}

} // namespace winrt::Microsoft::ReactNative::Composition::implementation
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ struct WindowsTextInputComponentView
void InternalFinalize() noexcept;
void UpdatePropertyBits() noexcept;

void autoCapitalizeOnUpdateProps(
const std::string &previousCapitalizationType,
const std::string &newcapitalizationType) noexcept;

winrt::Windows::UI::Composition::CompositionSurfaceBrush m_brush{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::ICaretVisual m_caretVisual{nullptr};
winrt::Microsoft::ReactNative::Composition::Experimental::IDrawingSurfaceBrush m_drawingSurface{nullptr};
Expand Down

0 comments on commit 4294d05

Please sign in to comment.