-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix cursor position when adding emoji #12632
Conversation
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
I'm adding this message here to provide a bit of context. I did not test for the platforms: Mobile Web - Safari and iOS because my currently available work computer is not a Mac. I can get access to a friend's phone to test the Mobile Web - Safari probably still this week. I'll also try to get my hands on a Mac to be able to use Xcode to run the iOS version of the App and test the changes. This said, if someone would be kind enough to run the tests for the iOS version for me I'd be very grateful. Regarding the Desktop version, I tried spinning up the electron build on my local computer (I'm running Ubuntu 22.04) but I did not have much success. If someone could help me get the desktop environment setup it would be awesome. It's my first time contributing for this App and I only started getting into the code last week so I'm still getting my grip with setting up the proper dev environment. |
I have read the CLA Document and I hereby sign the CLA |
@ctkochan22 and @rushatgabhane I think this didn't get properly linked to the issue so I added you as reviewers, removing myself. Let me know if you want extra eyes on this though! |
Looks good. @rushatgabhane Let me know when you can test this 🙇 |
Android BugI'm making this comment to address the Android example: bug12325_review_android.webmAs you can see in the video, the desired behavior is not achieved in this case. This is because of a preexisting bug. Here are videos from the App without my commit showing the same behavior happening: bug12325_review_android_previous_bug4.webmbug12325_review_android_previous_bug3.webmbug12325_review_android_previous_bug2.webmbug12325_review_android_previous_bug1.webmbug12325_review_android_previous_bug.webmInitially when I tested in the Android app I was surprised to see this bug because of the small change I made to the code and me not being aware of the preexisting bug. Only when I undid my commit and tested the behavior again is it that I found out it was preexisting. DiscussionWhat I want to discuss now in this comment is a broader decision that's regarding Controlled Selection vs Uncontrolled Selection. When I was working on this bug and I was finished implementing my solution I wanted to check if the bug was still present on the default branch. Out of habit I checkout out the The problemTurns out that if you go to react-native repository and you search in issues for onSelectionChange you'll see that there's a lot of problems with this handler. The most relevant issues in my opinion are:
There's a lot of problems regarding the onSelectionChange in react-native, causing different behaviors in the browser, ios, android and desktop environments. As well as onSelect with React itself between different browsers, as I discovered as I was tackling this bug #12298 and that lead me to having to open yet another issue in React's repo itself facebook/react#25643 In fact, as I was looking into the bug seeing if I could fix it (because even though it was preexisting, I don't feel good presenting a solution that does not behave as intended) I found out that the onSelectionChange handler is very erratic. With the same input, sometimes if fires the event 3 times, sometimes 5 times. Sometimes it puts the cursor 3 chars away, other times 7, other times leaves it in the place I set it, other times it takes it to the end of the string. Setting state every time onSelectionChange fires is causing multiple re-renders and that's why in the footage you see the cursor "flashing around" (you can only tell it's flashing because that's an emulator running a live dev server, in the built app the re-renders happen to fast to notice the "flashing" but the cursor still ends up in completely erratic locations) I also suspect that a lot of bugs that are happening lately are due to this erratic behavior of onSelectionChange, for example:
OpinionI'm sure there was a really good reason to transition from the default Uncontrolled Selection strategy to the Controlled Selection strategy but there's a real problem with onSelectionChange events that needs to be addressed. I've worked previously with react-native in other projects and although most of the times the default Uncontrolled Selection strategy is the one pursued there's been a handful of cases where it was decided to use Controlled Selection. In the cases of using Controlled Selection it was decided to avoid, every time it was possible, using the onSelectionChange due to its erratic nature and I believe this is a philosophy that really positively impacted the development. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- please run
npx eslint .
and fix the lint errors - Expensify requires that you can test on all platforms - https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms
- suggestion: change issue title to something more meaningful like
Fix cursor position when adding emoji
@AndreasBBS Thanks for your detailed investigation!!
Let's address this in a seperate issue because it's unrelated to the current PR/issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AndreasBBS Fantastic work!
@ctkochan22 LGTM! 🎉
Web
Screen.Recording.2022-11-16.at.12.23.57.AM.mov
mWeb
Screen.Recording.2022-11-16.at.12.27.53.AM.mov
iOS
Screen.Recording.2022-11-16.at.12.32.10.AM.mov
Android
Screen.Recording.2022-11-16.at.12.30.05.AM.mov
Desktop
Screen.Recording.2022-11-16.at.12.30.53.AM.mov
PR Reviewer Checklist
- I have verified the author checklist is complete (all boxes are checked off).
- I verified the correct issue is linked in the
### Fixed Issues
section above - I verified testing steps are clear and they cover the changes made in this PR
- I verified the steps for local testing are in the
Tests
section - I verified the steps for Staging and/or Production testing are in the
QA steps
section - I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
- I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
- I verified the steps for local testing are in the
- I checked that screenshots or videos are included for tests on all platforms
- I included screenshots or videos for tests on all platforms
- I verified tests pass on all platforms & I tested again on:
- iOS / native
- Android / native
- iOS / Safari
- Android / Chrome
- MacOS / Chrome
- MacOS / Desktop
- If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
- I verified proper code patterns were followed (see Reviewing the code)
- I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e.
toggleReport
and notonIconClick
). - I verified that comments were added to code that is not self explanatory
- I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
- I verified any copy / text shown in the product was added in all
src/languages/*
files - I verified any copy / text that was added to the app is correct English and approved by marketing by adding the
Waiting for Copy
label for a copy review on the original GH to get the correct copy. - I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
- I verified the JSDocs style guidelines (in
STYLE.md
) were followed
- I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e.
- If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
- I verified that this PR follows the guidelines as stated in the Review Guidelines
- I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like
Avatar
, I verified the components usingAvatar
have been tested & I retested again) - I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
- I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
- If a new component is created I verified that:
- A similar component doesn't exist in the codebase
- All props are defined accurately and each prop has a
/** comment above it */
- The file is named correctly
- The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
- The only data being stored in the state is data necessary for rendering and nothing else
- For Class Components, any internal methods passed to components event handlers are bound to
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor) - Any internal methods bound to
this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
) - All JSX used for rendering exists in the render method
- The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
- If a new CSS style is added I verified that:
- A similar style doesn't already exist
- The style can't be created with an existing StyleUtils function (i.e.
StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)
- If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like
Avatar
is modified, I verified thatAvatar
is working as expected in all cases) - If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
- I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work!
Oh man your commits are not verified -- https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#begin-coding-your-solution-in-a-pull-request |
@AndreasBBS feel free to ask for help :) |
@rushatgabhane Thanks a million for testing on all platforms. I don't have a mac and I've been trying to make ends meet with what I can do in Ubuntu. I added my own videos for macos safari, chrome and electron (I managed to run catalina in virtualbox). But I'm having trouble installing XCode on the VM. I think I should be able to have the tests on iOS by the end of the week. I meanwhile fixed the linting errors and changed the title. Let me know if there's something else on my side that's missing. EDIT: I'm currently signing the commits. |
bea9e61
7e83d17
to
bea9e61
Compare
- In ReportActionItemMessageEdit.js change updateDraft's setState - In ReportActionCompose.js change updateComment's setState - In both changes, verify if the input has been manipulated. If yes, mantain cursor position from previous state
bea9e61
to
0a9087c
Compare
Looks good! Thank you for fixing your commits! |
@ctkochan22 looks like this was merged without the checklist test passing. Please add a note explaining why this was done and remove the |
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
🚀 Deployed to staging by @ctkochan22 in version: 1.2.29-0 🚀
|
🚀 Deployed to production by @AndrewGable in version: 1.2.29-7 🚀
|
value: newComment, | ||
}; | ||
if (comment !== newComment) { | ||
const remainder = prevState.value.slice(prevState.selection.end).length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was hidden bug in this logic. #17275 (comment) for more details about the root cause.
Just flagging that this PR caused a bug where the cursor position would freeze after pasting emojis. The root cause is the reliance on App/src/pages/home/report/ReportActionCompose.js Lines 386 to 400 in 8188200
The issue is that due to the async nature of |
Details
Changed the way the cursor is placed after an emoji is written through the "two dot mechanism" :emoji: or a string with an :emoji: is pasted. For example:
Let's say we're pasting the string
:wave: friend
in the stringHello nice to meet you
between the wordHello
andnice
:Hello |nice to meet you
(representing the cursor with the char|
):Hello 👋 friend nice to meet you|
Hello 👋 friend |nice to meet you
Let's say we're writing the emoji
:wave:
in the stringHello nice to meet you
between the wordHello
andnice
:Hello |nice to meet you
:Hello 👋nice to meet you|
hello 👋|nice to meet you
Fixed Issues
$ #12325
PROPOSAL: https://github.com/Expensify/App/issues/12325#issuecomment-1299518471
Tests
Case 1:
Hello nice to meet you
:wave:
in the stringHello nice to meet you
between the wordHello
andnice
Case 2:
Hello nice to meet you
:wave: friend
in the stringHello nice to meet you
between the wordHello
andnice
QA Steps
Case 1:
Hello nice to meet you
:wave:
in the stringHello nice to meet you
between the wordHello
andnice
Case 2:
Hello nice to meet you
:wave: friend
in the stringHello nice to meet you
between the wordHello
andnice
PR Author Checklist
### Fixed Issues
section aboveTests
sectionQA steps
sectiontoggleReport
and notonIconClick
)src/languages/*
filesWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
are working as expected)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)PR Reviewer Checklist
The reviewer will copy/paste it into a new comment and complete it after the author checklist is completed
### Fixed Issues
section aboveTests
sectionQA steps
sectiontoggleReport
and notonIconClick
).src/languages/*
filesWaiting for Copy
label for a copy review on the original GH to get the correct copy.STYLE.md
) were followedAvatar
, I verified the components usingAvatar
have been tested & I retested again)/** comment above it */
this
properly so there are no scoping issues (i.e. foronClick={this.submit}
the methodthis.submit
should be bound tothis
in the constructor)this
are necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);
ifthis.submit
is never passed to a component event handler likeonClick
)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG
)Avatar
is modified, I verified thatAvatar
is working as expected in all cases)Screenshots
Web
bug12325_review_web.webm
macos_chrome.mov
macos_safari.mov
Mobile Web - Chrome
bug12325_review_android_chrome.1.webm
Mobile Web - Safari
Desktop
electron.mov
iOS
Android
bug12325_review_android.webm