'use client'; import { useIsomorphicLayoutEffect, useMergedRefs } from '@fluentui/react-utilities'; import * as React from 'react'; import { useResizeObserverRef_unstable } from './useResizeObserverRef'; import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; /** * React hook that measures virtualized space dynamically to ensure optimized virtualization length. * @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release. */ export const useDynamicVirtualizerMeasure = (virtualizerProps)=>{ const { defaultItemSize, direction = 'vertical', numItems, getItemSize, bufferItems, bufferSize, virtualizerContext } = virtualizerProps; const [state, setState] = React.useState({ virtualizerLength: 0, virtualizerBufferItems: 0, virtualizerBufferSize: 0 }); const containerSizeRef = React.useRef(0); const scrollPosition = React.useRef(0); const { virtualizerLength, virtualizerBufferItems, virtualizerBufferSize } = state; const { targetDocument } = useFluent(); const container = React.useRef(null); const handleScrollResize = React.useCallback(// eslint-disable-next-line @typescript-eslint/no-deprecated (scrollRef)=>{ if (!(scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current)) { // Error? ignore? return; } if (scrollRef.current !== (targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body)) { // We have a local scroll container containerSizeRef.current = direction === 'vertical' ? scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current.getBoundingClientRect().height : scrollRef === null || scrollRef === void 0 ? void 0 : scrollRef.current.getBoundingClientRect().width; } else if (targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView) { var _targetDocument_defaultView, _targetDocument_defaultView1; // If our scroll ref is the document body, we should check window height containerSizeRef.current = direction === 'vertical' ? targetDocument === null || targetDocument === void 0 ? void 0 : (_targetDocument_defaultView = targetDocument.defaultView) === null || _targetDocument_defaultView === void 0 ? void 0 : _targetDocument_defaultView.innerHeight : targetDocument === null || targetDocument === void 0 ? void 0 : (_targetDocument_defaultView1 = targetDocument.defaultView) === null || _targetDocument_defaultView1 === void 0 ? void 0 : _targetDocument_defaultView1.innerWidth; } let indexSizer = 0; let i = 0; let length = 0; const startIndex = virtualizerContext.contextIndex; const sizeToBeat = containerSizeRef.current + virtualizerBufferSize * 2; while(indexSizer <= sizeToBeat && i + startIndex < numItems){ const iItemSize = getItemSize(startIndex + i); if (virtualizerContext.childProgressiveSizes.current.length < numItems) { /* We are in unknown territory, either an initial render or an update in virtualizer item length has occurred. We need to let the new items render first then we can accurately assess.*/ return virtualizerLength - virtualizerBufferSize * 2; } const currentScrollPos = scrollPosition.current; const currentItemPos = virtualizerContext.childProgressiveSizes.current[startIndex + i] - iItemSize; if (currentScrollPos > currentItemPos + iItemSize) { // The item isn't in view, ignore for now. i++; continue; } else if (currentScrollPos > currentItemPos) { // The item is partially out of view, ignore the out of bounds portion const variance = currentItemPos + iItemSize - currentScrollPos; indexSizer += variance; } else { // Item is in view indexSizer += iItemSize; } // Increment i++; length++; } /* * Number of items to append at each end, i.e. 'preload' each side before entering view. * Minimum: 2 - we give slightly more buffer for dynamic version. */ const newBufferItems = bufferItems !== null && bufferItems !== void 0 ? bufferItems : Math.max(Math.ceil(length / 3), 1); /* * This is how far we deviate into the bufferItems to detect a redraw. */ const newBufferSize = bufferSize !== null && bufferSize !== void 0 ? bufferSize : Math.max(defaultItemSize / 2, 1); const totalLength = length + newBufferItems * 2; setState({ virtualizerLength: totalLength, virtualizerBufferSize: newBufferSize, virtualizerBufferItems: newBufferItems }); }, [ bufferItems, bufferSize, defaultItemSize, direction, getItemSize, numItems, targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.body, targetDocument === null || targetDocument === void 0 ? void 0 : targetDocument.defaultView, virtualizerBufferSize, virtualizerContext.childProgressiveSizes, virtualizerContext.contextIndex, virtualizerLength ]); const resizeCallback = React.useCallback((_entries, // TODO: exclude types from this lint rule: https://github.com/microsoft/fluentui/issues/31286 _observer, // eslint-disable-next-line @typescript-eslint/no-deprecated scrollRef)=>{ if (scrollRef) { handleScrollResize(scrollRef); } }, [ handleScrollResize ]); const scrollRef = useMergedRefs(container, useResizeObserverRef_unstable(resizeCallback)); useIsomorphicLayoutEffect(()=>{ if (virtualizerContext.contextIndex + virtualizerLength < numItems) { // Avoid re-rendering/re-calculating when the end index has already been reached handleScrollResize(container); } }, [ handleScrollResize, numItems, virtualizerContext.contextIndex, virtualizerLength ]); const updateScrollPosition = React.useCallback((_scrollPosition)=>{ scrollPosition.current = _scrollPosition; // Check if our vLength's need recalculating handleScrollResize(scrollRef); }, [ handleScrollResize, scrollRef ]); return { virtualizerLength, bufferItems: virtualizerBufferItems, bufferSize: virtualizerBufferSize, scrollRef, containerSizeRef, updateScrollPosition }; };