Skip to content

Commit

Permalink
fix(): use getBoundingClientRect consistently
Browse files Browse the repository at this point in the history
  • Loading branch information
petyosi committed Aug 17, 2021
1 parent 65d732e commit 94c470e
Show file tree
Hide file tree
Showing 7 changed files with 21 additions and 22 deletions.
10 changes: 2 additions & 8 deletions src/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@ const GridItems: FC = React.memo(function GridItems() {
const listRef = useSize((el) => {
const firstItem = el.firstChild as HTMLElement
if (firstItem) {
itemDimensions({
width: firstItem.offsetWidth,
height: firstItem.offsetHeight,
})
itemDimensions(firstItem.getBoundingClientRect())
}
})

Expand All @@ -125,10 +122,7 @@ const Viewport: FC = ({ children }) => {
const viewportDimensions = usePublisher('viewportDimensions')

const viewportRef = useSize((el) => {
viewportDimensions({
width: el.offsetWidth,
height: el.offsetHeight,
})
viewportDimensions(el.getBoundingClientRect())
})

return (
Expand Down
8 changes: 4 additions & 4 deletions src/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
getValue,
map,
pipe,
prop,
publish,
statefulStream,
stream,
Expand All @@ -28,6 +27,7 @@ import { Components, ComputeItemKey, GroupContent, GroupItemContent, ItemContent
import { listSystem } from './listSystem'
import { positionStickyCssValue } from './utils/positionStickyCssValue'
import useWindowViewportRectRef from './hooks/useWindowViewportRect'
import { correctItemSize } from './utils/correctItemSize'

export function identity<T>(value: T) {
return value
Expand Down Expand Up @@ -268,15 +268,15 @@ const Header: FC = React.memo(function VirtuosoHeader() {
const Header = useEmitterValue('HeaderComponent')
const headerHeight = usePublisher('headerHeight')
const headerFooterTag = useEmitterValue('headerFooterTag')
const ref = useSize((el) => headerHeight(el.offsetHeight))
const ref = useSize((el) => headerHeight(correctItemSize(el, 'height')))
return Header ? createElement(headerFooterTag, { ref }, createElement(Header)) : null
})

const Footer: FC = React.memo(function VirtuosoFooter() {
const Footer = useEmitterValue('FooterComponent')
const footerHeight = usePublisher('footerHeight')
const headerFooterTag = useEmitterValue('headerFooterTag')
const ref = useSize((el) => footerHeight(el.offsetHeight))
const ref = useSize((el) => footerHeight(correctItemSize(el, 'height')))
return Footer ? createElement(headerFooterTag, { ref }, createElement(Footer)) : null
})

Expand Down Expand Up @@ -351,7 +351,7 @@ export function buildWindowScroller({ usePublisher, useEmitter, useEmitterValue

const Viewport: FC = ({ children }) => {
const viewportHeight = usePublisher('viewportHeight')
const viewportRef = useSize(compose(viewportHeight, prop('offsetHeight')))
const viewportRef = useSize(compose(viewportHeight, (el) => correctItemSize(el, 'height')))

return (
<div style={viewportStyle} ref={viewportRef}>
Expand Down
2 changes: 1 addition & 1 deletion src/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export interface VirtuosoProps<D> extends Omit<ListProps, 'groupCounts' | 'group
/**
* Allows customizing the height/width calculation of `Item` elements.
*
* The default implementation reads `el.offsetHeight` and `el.offsetWidth`.
* The default implementation reads `el.getBoundingClientRect().height` and `el.getBoundingClientRect().width`.
*/
itemSize?: (el: HTMLElement, field: 'offsetHeight' | 'offsetWidth') => number

Expand Down
7 changes: 4 additions & 3 deletions src/hooks/useScrollTop.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useRef, useCallback, useEffect } from 'react'
import * as u from '@virtuoso.dev/urx'
import { correctItemSize } from '../utils/correctItemSize'

export type ScrollerRef = Window | HTMLElement | null

Expand All @@ -21,7 +22,7 @@ export default function useScrollTop(
scrollTopCallback(Math.max(scrollTop, 0))

if (scrollTopTarget.current !== null) {
if (scrollTop === scrollTopTarget.current || scrollTop <= 0 || scrollTop === el.scrollHeight - el.offsetHeight) {
if (scrollTop === scrollTopTarget.current || scrollTop <= 0 || scrollTop === el.scrollHeight - correctItemSize(el, 'height')) {
scrollTopTarget.current = null
smoothScrollTargetReached(true)
if (timeoutRef.current) {
Expand Down Expand Up @@ -61,12 +62,12 @@ export default function useScrollTop(

if (scrollerElement === window) {
// this is not a mistake
scrollHeight = Math.max(document.documentElement.offsetHeight, document.documentElement.scrollHeight)
scrollHeight = Math.max(correctItemSize(document.documentElement, 'height'), document.documentElement.scrollHeight)
offsetHeight = window.innerHeight
scrollTop = document.documentElement.scrollTop
} else {
scrollHeight = (scrollerElement as HTMLElement).scrollHeight
offsetHeight = (scrollerElement as HTMLElement).offsetHeight
offsetHeight = correctItemSize(scrollerElement as HTMLElement, 'height')
scrollTop = (scrollerElement as HTMLElement).scrollTop
}

Expand Down
3 changes: 2 additions & 1 deletion src/sizeSystem.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as u from '@virtuoso.dev/urx'
import { arrayToRanges, AANode, empty, findMaxKeyValue, insert, newTree, Range, rangesWithin, remove, walk } from './AATree'
import * as arrayBinarySearch from './utils/binaryArraySearch'
import { correctItemSize } from './utils/correctItemSize'

export interface SizeRange {
startIndex: number
Expand Down Expand Up @@ -245,7 +246,7 @@ export const sizeSystem = u.system(
const groupIndices = u.statefulStream([] as number[])
const fixedItemSize = u.statefulStream<OptionalNumber>(undefined)
const defaultItemSize = u.statefulStream<OptionalNumber>(undefined)
const itemSize = u.statefulStream<SizeFunction>((el, field) => el.getBoundingClientRect()[SIZE_MAP[field]])
const itemSize = u.statefulStream<SizeFunction>((el, field) => correctItemSize(el, SIZE_MAP[field]))
const data = u.statefulStream<Data>(undefined)
const initial = initialSizeState()

Expand Down
3 changes: 3 additions & 0 deletions src/utils/correctItemSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function correctItemSize(el: HTMLElement, dimension: 'height' | 'width') {
return el.getBoundingClientRect()[dimension]
}
10 changes: 5 additions & 5 deletions test/List.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('List', () => {

act(() => {
scroller.triggerScroll(0)
viewport.triggerResize({ offsetHeight: 700 })
viewport.triggerResize({ getBoundingClientRect: () => ({ height: 700 }) })
})

expect(listParent.children).toHaveLength(1)
Expand All @@ -57,7 +57,7 @@ describe('List', () => {

act(() => {
scroller.triggerScroll(0)
viewport.triggerResize({ offsetHeight: 700 })
viewport.triggerResize({ getBoundingClientRect: () => ({ height: 700 }) })
listParent.triggerChangedChildSizes([{ startIndex: 0, endIndex: 0, size: 30 }])
})
})
Expand Down Expand Up @@ -99,7 +99,7 @@ describe('List', () => {

act(() => {
scroller.triggerScroll(0)
viewport.triggerResize({ offsetHeight: 100 })
viewport.triggerResize({ getBoundingClientRect: () => ({ height: 700 }) })
listParent.triggerChangedChildSizes([{ startIndex: 0, endIndex: 0, size: 10 }])
})
})
Expand Down Expand Up @@ -131,7 +131,7 @@ describe('List', () => {

act(() => {
scroller.triggerScroll(0)
viewport.triggerResize({ offsetHeight: 100 })
viewport.triggerResize({ getBoundingClientRect: () => ({ height: 100 }) })
listParent.triggerChangedChildSizes([{ startIndex: 0, endIndex: 0, size: 10 }])
container.querySelector('button').dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
Expand Down Expand Up @@ -166,7 +166,7 @@ describe('List', () => {

act(() => {
scroller.triggerScroll(0)
viewport.triggerResize({ offsetHeight: 100 })
viewport.triggerResize({ getBoundingClientRect: () => ({ height: 100 }) })
listParent.triggerChangedChildSizes([{ startIndex: 0, endIndex: 0, size: 10 }])
container.querySelector('button').dispatchEvent(new MouseEvent('click', { bubbles: true }))
})
Expand Down

0 comments on commit 94c470e

Please sign in to comment.