1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and affiliates.
    
  3.  *
    
  4.  * This source code is licensed under the MIT license found in the
    
  5.  * LICENSE file in the root directory of this source tree.
    
  6.  *
    
  7.  * @flow
    
  8.  */
    
  9. 
    
  10. import type {Rect} from '../geometry';
    
  11. import type {ScrollState} from '../utils/scrollState';
    
  12. import type {Surface} from '../Surface';
    
  13. import type {ViewState} from '../../types';
    
  14. 
    
  15. import {VerticalScrollBarView} from './VerticalScrollBarView';
    
  16. import {withVerticalScrollbarLayout} from './withVerticalScrollbarLayout';
    
  17. import {View} from '../View';
    
  18. import {VerticalScrollView} from '../VerticalScrollView';
    
  19. 
    
  20. export class VerticalScrollOverflowView extends View {
    
  21.   _contentView: View;
    
  22.   _isProcessingOnChange: boolean = false;
    
  23.   _isScrolling: boolean = false;
    
  24.   _scrollOffset: number = 0;
    
  25.   _scrollBarView: VerticalScrollBarView;
    
  26.   _verticalScrollView: VerticalScrollView;
    
  27. 
    
  28.   constructor(
    
  29.     surface: Surface,
    
  30.     frame: Rect,
    
  31.     contentView: View,
    
  32.     viewState: ViewState,
    
  33.   ) {
    
  34.     super(surface, frame, withVerticalScrollbarLayout);
    
  35. 
    
  36.     this._contentView = contentView;
    
  37.     this._verticalScrollView = new VerticalScrollView(
    
  38.       surface,
    
  39.       frame,
    
  40.       contentView,
    
  41.       viewState,
    
  42.       'VerticalScrollOverflowView',
    
  43.     );
    
  44.     this._verticalScrollView.onChange(this._onVerticalScrollViewChange);
    
  45. 
    
  46.     this._scrollBarView = new VerticalScrollBarView(surface, frame, this);
    
  47. 
    
  48.     this.addSubview(this._verticalScrollView);
    
  49.     this.addSubview(this._scrollBarView);
    
  50.   }
    
  51. 
    
  52.   layoutSubviews() {
    
  53.     super.layoutSubviews();
    
  54. 
    
  55.     const contentSize = this._contentView.desiredSize();
    
  56. 
    
  57.     // This should be done after calling super.layoutSubviews() – calling it
    
  58.     // before somehow causes _contentView to need display on every mousemove
    
  59.     // event when the scroll bar is shown.
    
  60.     this._scrollBarView.setContentHeight(contentSize.height);
    
  61.   }
    
  62. 
    
  63.   setScrollOffset(newScrollOffset: number, maxScrollOffset: number) {
    
  64.     const deltaY = newScrollOffset - this._scrollOffset;
    
  65. 
    
  66.     if (!this._isProcessingOnChange) {
    
  67.       this._verticalScrollView.scrollBy(-deltaY);
    
  68.     }
    
  69. 
    
  70.     this._scrollOffset = newScrollOffset;
    
  71. 
    
  72.     this.setNeedsDisplay();
    
  73.   }
    
  74. 
    
  75.   _onVerticalScrollViewChange: (
    
  76.     scrollState: ScrollState,
    
  77.     containerLength: number,
    
  78.   ) => void = (scrollState: ScrollState, containerLength: number) => {
    
  79.     const maxOffset = scrollState.length - containerLength;
    
  80.     if (maxOffset === 0) {
    
  81.       return;
    
  82.     }
    
  83. 
    
  84.     const percentage = Math.abs(scrollState.offset) / maxOffset;
    
  85.     const maxScrollThumbY = this._scrollBarView.getMaxScrollThumbY();
    
  86. 
    
  87.     this._isProcessingOnChange = true;
    
  88.     this._scrollBarView.setScrollThumbY(percentage * maxScrollThumbY);
    
  89.     this._isProcessingOnChange = false;
    
  90.   };
    
  91. }