( props: ScrollViewProps, ref: RefObject<HTMLElement | null> )
| 68 | } |
| 69 | |
| 70 | export function useScrollView( |
| 71 | props: ScrollViewProps, |
| 72 | ref: RefObject<HTMLElement | null> |
| 73 | ): ScrollViewAria { |
| 74 | let { |
| 75 | contentSize, |
| 76 | onVisibleRectChange, |
| 77 | onSizeChange, |
| 78 | innerStyle, |
| 79 | onScrollStart, |
| 80 | onScrollEnd, |
| 81 | scrollDirection = 'both', |
| 82 | onScroll: onScrollProp, |
| 83 | allowsWindowScrolling, |
| 84 | ...otherProps |
| 85 | } = props; |
| 86 | |
| 87 | let state = useRef({ |
| 88 | // Internal scroll position of the scroll view. |
| 89 | scrollPosition: new Point(), |
| 90 | // Size of the scroll view. |
| 91 | size: new Size(), |
| 92 | // Offset of the scroll view relative to the window viewport. |
| 93 | viewportOffset: new Point(), |
| 94 | // Size of the window viewport. |
| 95 | viewportSize: new Size(), |
| 96 | scrollEndTime: 0, |
| 97 | scrollTimeout: null as ReturnType<typeof setTimeout> | null, |
| 98 | isScrolling: false, |
| 99 | lastVisibleRect: new Rect() |
| 100 | }).current; |
| 101 | let {direction} = useLocale(); |
| 102 | |
| 103 | let updateVisibleRect = useCallback(() => { |
| 104 | // Intersect the window viewport with the scroll view itself to find the actual visible rectangle. |
| 105 | // This allows virtualized components to have unbounded height but still virtualize when scrolled with the page. |
| 106 | // While there may be other scrollable elements between the <body> and the scroll view, we do not take |
| 107 | // their sizes into account for performance reasons. Their scroll positions are accounted for in viewportOffset |
| 108 | // though (due to getBoundingClientRect). This may result in more rows than absolutely necessary being rendered, |
| 109 | // but no more than the entire height of the viewport which is good enough for virtualization use cases. |
| 110 | let visibleRect = allowsWindowScrolling |
| 111 | ? new Rect( |
| 112 | state.viewportOffset.x + state.scrollPosition.x, |
| 113 | state.viewportOffset.y + state.scrollPosition.y, |
| 114 | Math.max( |
| 115 | 0, |
| 116 | Math.min(state.size.width - state.viewportOffset.x, state.viewportSize.width) |
| 117 | ), |
| 118 | Math.max( |
| 119 | 0, |
| 120 | Math.min(state.size.height - state.viewportOffset.y, state.viewportSize.height) |
| 121 | ) |
| 122 | ) |
| 123 | : new Rect( |
| 124 | state.scrollPosition.x, |
| 125 | state.scrollPosition.y, |
| 126 | state.size.width, |
| 127 | state.size.height |
no test coverage detected