Fix browser glitch caused by two overlapping scroll animations in web UI (#31960)
This commit is contained in:
		@@ -4,8 +4,6 @@ import { Children, cloneElement, useCallback } from 'react';
 | 
			
		||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
			
		||||
 | 
			
		||||
import { supportsPassiveEvents } from 'detect-passive-events';
 | 
			
		||||
 | 
			
		||||
import { scrollRight } from '../../../scroll';
 | 
			
		||||
import BundleContainer from '../containers/bundle_container';
 | 
			
		||||
import {
 | 
			
		||||
@@ -71,10 +69,6 @@ export default class ColumnsArea extends ImmutablePureComponent {
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  componentDidMount() {
 | 
			
		||||
    if (!this.props.singleColumn) {
 | 
			
		||||
      this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.mediaQuery) {
 | 
			
		||||
      if (this.mediaQuery.addEventListener) {
 | 
			
		||||
        this.mediaQuery.addEventListener('change', this.handleLayoutChange);
 | 
			
		||||
@@ -87,23 +81,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
 | 
			
		||||
    this.isRtlLayout = document.getElementsByTagName('body')[0].classList.contains('rtl');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  UNSAFE_componentWillUpdate(nextProps) {
 | 
			
		||||
    if (this.props.singleColumn !== nextProps.singleColumn && nextProps.singleColumn) {
 | 
			
		||||
      this.node.removeEventListener('wheel', this.handleWheel);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  componentDidUpdate(prevProps) {
 | 
			
		||||
    if (this.props.singleColumn !== prevProps.singleColumn && !this.props.singleColumn) {
 | 
			
		||||
      this.node.addEventListener('wheel', this.handleWheel, supportsPassiveEvents ? { passive: true } : false);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  componentWillUnmount () {
 | 
			
		||||
    if (!this.props.singleColumn) {
 | 
			
		||||
      this.node.removeEventListener('wheel', this.handleWheel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (this.mediaQuery) {
 | 
			
		||||
      if (this.mediaQuery.removeEventListener) {
 | 
			
		||||
        this.mediaQuery.removeEventListener('change', this.handleLayoutChange);
 | 
			
		||||
@@ -116,7 +94,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
 | 
			
		||||
  handleChildrenContentChange() {
 | 
			
		||||
    if (!this.props.singleColumn) {
 | 
			
		||||
      const modifier = this.isRtlLayout ? -1 : 1;
 | 
			
		||||
      this._interruptScrollAnimation = scrollRight(this.node, (this.node.scrollWidth - window.innerWidth) * modifier);
 | 
			
		||||
      scrollRight(this.node, (this.node.scrollWidth - window.innerWidth) * modifier);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -124,14 +102,6 @@ export default class ColumnsArea extends ImmutablePureComponent {
 | 
			
		||||
    this.setState({ renderComposePanel: !e.matches });
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  handleWheel = () => {
 | 
			
		||||
    if (typeof this._interruptScrollAnimation !== 'function') {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this._interruptScrollAnimation();
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  setRef = (node) => {
 | 
			
		||||
    this.node = node;
 | 
			
		||||
  };
 | 
			
		||||
 
 | 
			
		||||
@@ -38,13 +38,20 @@ const scroll = (
 | 
			
		||||
const isScrollBehaviorSupported =
 | 
			
		||||
  'scrollBehavior' in document.documentElement.style;
 | 
			
		||||
 | 
			
		||||
export const scrollRight = (node: Element, position: number) => {
 | 
			
		||||
  if (isScrollBehaviorSupported)
 | 
			
		||||
    node.scrollTo({ left: position, behavior: 'smooth' });
 | 
			
		||||
  else scroll(node, 'scrollLeft', position);
 | 
			
		||||
};
 | 
			
		||||
export const scrollRight = (node: Element, position: number) =>
 | 
			
		||||
  requestIdleCallback(() => {
 | 
			
		||||
    if (isScrollBehaviorSupported) {
 | 
			
		||||
      node.scrollTo({ left: position, behavior: 'smooth' });
 | 
			
		||||
    } else {
 | 
			
		||||
      scroll(node, 'scrollLeft', position);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
export const scrollTop = (node: Element) => {
 | 
			
		||||
  if (isScrollBehaviorSupported) node.scrollTo({ top: 0, behavior: 'smooth' });
 | 
			
		||||
  else scroll(node, 'scrollTop', 0);
 | 
			
		||||
};
 | 
			
		||||
export const scrollTop = (node: Element) =>
 | 
			
		||||
  requestIdleCallback(() => {
 | 
			
		||||
    if (isScrollBehaviorSupported) {
 | 
			
		||||
      node.scrollTo({ top: 0, behavior: 'smooth' });
 | 
			
		||||
    } else {
 | 
			
		||||
      scroll(node, 'scrollTop', 0);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,14 @@ import { render as rtlRender } from '@testing-library/react';
 | 
			
		||||
 | 
			
		||||
import { IdentityContext } from './identity_context';
 | 
			
		||||
 | 
			
		||||
beforeEach(() => {
 | 
			
		||||
  global.requestIdleCallback = jest
 | 
			
		||||
    .fn()
 | 
			
		||||
    .mockImplementation((fn: () => void) => {
 | 
			
		||||
      fn();
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function render(
 | 
			
		||||
  ui: React.ReactElement,
 | 
			
		||||
  {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user