Skip to content
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

Defer day focusing until next animation frame #1707

Merged
merged 1 commit into from
Jun 25, 2019
Merged

Conversation

lencioni
Copy link
Contributor

At Airbnb we noticed a bug affecting only mobile devices or desktop with
mobile device emulation enabled. In months that span 5 weeks that are
followed by months that span 6 weeks (e.g. May 2019), the scroll
position of the calendar days was scrolled down some, causing the
numbers to awkwardly overlap with the days of the week and look broken.
This only happened when first opening the date picker, and once you go
to a different month it would fix itself.

After some sleuthing, I determined that this was caused by these
.focus() calls happening at a weird time, causing a parent container (I
think maybe the DayPicker transition container with overflow hidden) to
have a > 0 scrollTop.

It seems that we can prevent this from happening by deferring the focus
until the next animation frame. I think this could also help us avoid
some layout thrashing, which could give us a little performance boost
here.

I was entirely unable to reproduce this in react-dates storybook, but
testing this fix out in the Airbnb codebase seems to fix the issue.

Before fix:
image

After fix:
image

@coveralls
Copy link

coveralls commented Jun 25, 2019

Coverage Status

Coverage increased (+0.5%) to 85.095% when pulling 1babba9 on jdl-defer-focus into c6debdc on master.

Copy link
Member

@ljharb ljharb left a comment

Choose a reason for hiding this comment

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

It'd be good to find a way to add some kind of regression test, even if it's checking for the exact implementation, to avoid it being accidentally removed in the future.

@@ -58,7 +58,11 @@ class CalendarDay extends React.PureComponent {
const { isFocused, tabIndex } = this.props;
if (tabIndex === 0) {
if (isFocused || tabIndex !== prevProps.tabIndex) {
this.buttonRef.focus();
requestAnimationFrame(() => {
Copy link
Member

Choose a reason for hiding this comment

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

do we already reference rAF elsewhere in the repo, or is this dependency a potential breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This looks like the first usage

Copy link
Member

Choose a reason for hiding this comment

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

any chance we could use https://npmjs.com/raf instead of the global?

Copy link
Contributor

@nkinser nkinser left a comment

Choose a reason for hiding this comment

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

Thank you so much for fixing this!!!! I really appreciate it!
Do you think this could also fix this bug?

@@ -58,7 +58,11 @@ class CalendarDay extends React.PureComponent {
const { isFocused, tabIndex } = this.props;
if (tabIndex === 0) {
if (isFocused || tabIndex !== prevProps.tabIndex) {
this.buttonRef.focus();
requestAnimationFrame(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

should we cancelAnimationFrame when the component unmounts?

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 don't think we need to, since I included a check that this.buttonRef is still truthy, so if it unmounts in between, it will essentially be a noop anyway.

@lencioni
Copy link
Contributor Author

@nkinser I think it could, but hard to say.

At Airbnb we noticed a bug affecting only mobile devices or desktop with
mobile device emulation enabled. In months that span 5 weeks that are
followed by months that span 6 weeks (e.g. May 2019), the scroll
position of the calendar days was scrolled down some, causing the
numbers to awkwardly overlap with the days of the week and look broken.
This only happened when first opening the date picker, and once you go
to a different month it would fix itself.

After some sleuthing, I determined that this was caused by these
.focus() calls happening at a weird time, causing a parent container (I
think maybe the DayPicker transition container with overflow hidden) to
have a > 0 scrollTop.

It seems that we can prevent this from happening by deferring the focus
until the next animation frame. I think this could also help us avoid
some layout thrashing, which could give us a little performance boost
here.

I was entirely unable to reproduce this in react-dates storybook, but
testing this fix out in the Airbnb codebase seems to fix the issue.
@lencioni
Copy link
Contributor Author

@ljharb I added some tests

@lencioni lencioni merged commit d549f41 into master Jun 25, 2019
@lencioni lencioni deleted the jdl-defer-focus branch June 25, 2019 23:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants