diff --git a/src/List.tsx b/src/List.tsx index 426609466..475fe170e 100644 --- a/src/List.tsx +++ b/src/List.tsx @@ -172,8 +172,9 @@ export const Items = React.memo(function VirtuosoItems({ showTopList = false }: const itemContent = useEmitterValue('itemContent') const groupContent = useEmitterValue('groupContent') const trackItemSizes = useEmitterValue('trackItemSizes') + const itemSize = useEmitterValue('itemSize') - const ref = useChangedChildSizes(sizeRanges, trackItemSizes) + const ref = useChangedChildSizes(sizeRanges, itemSize, trackItemSizes) const EmptyPlaceholder = useEmitterValue('EmptyPlaceholder') const ScrollSeekPlaceholder = useEmitterValue('ScrollSeekPlaceholder') || DefaultScrollSeekPlaceholder const ListComponent = useEmitterValue('ListComponent')! @@ -418,6 +419,7 @@ export const { Component: List, usePublisher, useEmitterValue, useEmitter } = sy computeItemKey: 'computeItemKey', defaultItemHeight: 'defaultItemHeight', fixedItemHeight: 'fixedItemHeight', + itemSize: 'itemSize', scrollSeekConfiguration: 'scrollSeekConfiguration', headerFooterTag: 'headerFooterTag', data: 'data', diff --git a/src/components.tsx b/src/components.tsx index 285619c27..d07939871 100644 --- a/src/components.tsx +++ b/src/components.tsx @@ -87,6 +87,13 @@ export interface VirtuosoProps extends Omit number + /** * Can be used to improve performance if the rendered items are of known size. * Setting it causes the component to skip item measurements. diff --git a/src/hooks/useChangedChildSizes.ts b/src/hooks/useChangedChildSizes.ts index ed4ac3655..cd984cd2a 100644 --- a/src/hooks/useChangedChildSizes.ts +++ b/src/hooks/useChangedChildSizes.ts @@ -1,16 +1,16 @@ -import { SizeRange } from '../sizeSystem' +import { SizeFunction, SizeRange } from '../sizeSystem' import useSize from './useSize' -export default function useChangedChildSizes(callback: (ranges: SizeRange[]) => void, enabled: boolean) { +export default function useChangedChildSizes(callback: (ranges: SizeRange[]) => void, itemSize: SizeFunction, enabled: boolean) { return useSize((el: HTMLElement) => { - const ranges = getChangedChildSizes(el.children, 'offsetHeight') + const ranges = getChangedChildSizes(el.children, itemSize, 'offsetHeight') if (ranges !== null) { callback(ranges) } }, enabled) } -function getChangedChildSizes(children: HTMLCollection, field: 'offsetHeight' | 'offsetWidth') { +function getChangedChildSizes(children: HTMLCollection, itemSize: SizeFunction, field: 'offsetHeight' | 'offsetWidth') { const length = children.length if (length === 0) { @@ -28,7 +28,7 @@ function getChangedChildSizes(children: HTMLCollection, field: 'offsetHeight' | const index = parseInt(child.dataset.index!) const knownSize = parseInt(child.dataset.knownSize!) - const size = child[field] + const size = itemSize(child, field) if (size === 0) { throw new Error('Zero-sized element, this should not happen') diff --git a/src/listSystem.ts b/src/listSystem.ts index 244bd3a29..23c116d98 100644 --- a/src/listSystem.ts +++ b/src/listSystem.ts @@ -46,7 +46,7 @@ const featureGroup1System = u.system( export const listSystem = u.system( ([ - { totalCount, sizeRanges, fixedItemSize, defaultItemSize, trackItemSizes, data, firstItemIndex, groupIndices }, + { totalCount, sizeRanges, fixedItemSize, defaultItemSize, trackItemSizes, itemSize, data, firstItemIndex, groupIndices }, { initialTopMostItemIndex, scrolledToInitialItem }, domIO, followOutput, @@ -79,6 +79,7 @@ export const listSystem = u.system( listState, scrollToIndex, trackItemSizes, + itemSize, groupIndices, // exported from stateFlagsSystem diff --git a/src/sizeSystem.ts b/src/sizeSystem.ts index 4142d401d..3e7a7066e 100644 --- a/src/sizeSystem.ts +++ b/src/sizeSystem.ts @@ -227,6 +227,10 @@ export function hasGroups(sizes: SizeState) { } type OptionalNumber = number | undefined + +/** Calculates the height of `el`, which will be the `Item` element in the DOM. */ +export type SizeFunction = (el: HTMLElement, field: 'offsetHeight' | 'offsetWidth') => number + export const sizeSystem = u.system( () => { const sizeRanges = u.stream() @@ -236,6 +240,7 @@ export const sizeSystem = u.system( const groupIndices = u.statefulStream([] as number[]) const fixedItemSize = u.statefulStream(undefined) const defaultItemSize = u.statefulStream(undefined) + const itemSize = u.statefulStream((el, field) => el[field]) const data = u.statefulStream(undefined) const initial = initialSizeState() @@ -384,6 +389,7 @@ export const sizeSystem = u.system( sizes, listRefresh, trackItemSizes, + itemSize, } }, [],