react-window
Version:
<img src="https://react-window.vercel.app/og.svg" alt="react-window logo" width="400" height="210" />
1 lines • 64.2 kB
Source Map (JSON)
{"version":3,"file":"react-window.cjs","sources":["../lib/utils/isRtl.ts","../lib/core/useIsRtl.ts","../lib/hooks/useIsomorphicLayoutEffect.ts","../lib/utils/parseNumericStyleValue.ts","../lib/hooks/useResizeObserver.ts","../lib/hooks/useStableCallback.ts","../lib/utils/getRTLOffsetType.ts","../lib/utils/adjustScrollOffsetForRtl.ts","../lib/utils/assert.ts","../lib/utils/shallowCompare.ts","../lib/core/getEstimatedSize.ts","../lib/core/getOffsetForIndex.ts","../lib/core/getStartStopIndices.ts","../lib/core/createCachedBounds.ts","../lib/core/useCachedBounds.ts","../lib/core/useItemSize.ts","../lib/core/useVirtualizer.ts","../lib/hooks/useMemoizedObject.ts","../lib/utils/arePropsEqual.ts","../lib/components/grid/Grid.tsx","../lib/components/grid/useGridCallbackRef.ts","../lib/components/grid/useGridRef.ts","../lib/components/list/isDynamicRowHeight.ts","../lib/components/list/List.tsx","../lib/components/list/useDynamicRowHeight.ts","../lib/components/list/useListCallbackRef.ts","../lib/components/list/useListRef.ts","../lib/utils/getScrollbarSize.ts"],"sourcesContent":["export function isRtl(element: HTMLElement) {\n let currentElement: HTMLElement | null = element;\n while (currentElement) {\n if (currentElement.dir) {\n return currentElement.dir === \"rtl\";\n }\n\n currentElement = currentElement.parentElement;\n }\n\n return false;\n}\n","import { useLayoutEffect, useState, type HTMLAttributes } from \"react\";\nimport { isRtl } from \"../utils/isRtl\";\n\nexport function useIsRtl(\n element: HTMLElement | null,\n dir: HTMLAttributes<HTMLElement>[\"dir\"]\n) {\n const [value, setValue] = useState(dir === \"rtl\");\n\n useLayoutEffect(() => {\n if (element) {\n if (!dir) {\n setValue(isRtl(element));\n }\n }\n }, [dir, element]);\n\n return value;\n}\n","import { useEffect, useLayoutEffect } from \"react\";\n\nexport const useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n","import type { CSSProperties } from \"react\";\n\nexport function parseNumericStyleValue(\n value: CSSProperties[\"height\"]\n): number | undefined {\n if (value !== undefined) {\n switch (typeof value) {\n case \"number\": {\n return value;\n }\n case \"string\": {\n if (value.endsWith(\"px\")) {\n return parseFloat(value);\n }\n break;\n }\n }\n }\n}\n","import { useMemo, useState, type CSSProperties } from \"react\";\nimport { parseNumericStyleValue } from \"../utils/parseNumericStyleValue\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\n\nexport function useResizeObserver({\n box,\n defaultHeight,\n defaultWidth,\n disabled: disabledProp,\n element,\n mode,\n style\n}: {\n box?: ResizeObserverBoxOptions;\n defaultHeight?: number;\n defaultWidth?: number;\n disabled?: boolean;\n element: HTMLElement | null;\n mode?: \"only-height\" | \"only-width\";\n style: CSSProperties | undefined;\n}) {\n const { styleHeight, styleWidth } = useMemo(\n () => ({\n styleHeight: parseNumericStyleValue(style?.height),\n styleWidth: parseNumericStyleValue(style?.width)\n }),\n [style?.height, style?.width]\n );\n\n const [state, setState] = useState<{\n height: number | undefined;\n width: number | undefined;\n }>({\n height: defaultHeight,\n width: defaultWidth\n });\n\n const disabled =\n disabledProp ||\n (mode === \"only-height\" && styleHeight !== undefined) ||\n (mode === \"only-width\" && styleWidth !== undefined) ||\n (styleHeight !== undefined && styleWidth !== undefined);\n\n useIsomorphicLayoutEffect(() => {\n if (element === null || disabled) {\n return;\n }\n\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { contentRect, target } = entry;\n if (element === target) {\n setState((prevState) => {\n if (\n prevState.height === contentRect.height &&\n prevState.width === contentRect.width\n ) {\n return prevState;\n }\n\n return {\n height: contentRect.height,\n width: contentRect.width\n };\n });\n }\n }\n });\n resizeObserver.observe(element, { box });\n\n return () => {\n resizeObserver?.unobserve(element);\n };\n }, [box, disabled, element, styleHeight, styleWidth]);\n\n return useMemo(\n () => ({\n height: styleHeight ?? state.height,\n width: styleWidth ?? state.width\n }),\n [state, styleHeight, styleWidth]\n );\n}\n","import { useCallback, useRef } from \"react\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect\";\n\n// Forked from useEventCallback (usehooks-ts)\nexport function useStableCallback<Args, Return>(\n fn: (args: Args) => Return\n): (args: Args) => Return {\n const ref = useRef<typeof fn>(() => {\n throw new Error(\"Cannot call during render.\");\n });\n\n useIsomorphicLayoutEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n return useCallback((args: Args) => ref.current?.(args), [ref]) as (\n args: Args\n ) => Return;\n}\n","export type RTLOffsetType =\n | \"negative\"\n | \"positive-descending\"\n | \"positive-ascending\";\n\nlet cachedRTLResult: RTLOffsetType | null = null;\n\n// TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.\n// Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).\n// Safari's elastic bounce makes detecting this even more complicated wrt potential false positives.\n// The safest way to check this is to intentionally set a negative offset,\n// and then verify that the subsequent \"scroll\" event matches the negative offset.\n// If it does not match, then we can assume a non-standard RTL scroll implementation.\nexport function getRTLOffsetType(recalculate: boolean = false): RTLOffsetType {\n if (cachedRTLResult === null || recalculate) {\n const outerDiv = document.createElement(\"div\");\n const outerStyle = outerDiv.style;\n outerStyle.width = \"50px\";\n outerStyle.height = \"50px\";\n outerStyle.overflow = \"scroll\";\n outerStyle.direction = \"rtl\";\n\n const innerDiv = document.createElement(\"div\");\n const innerStyle = innerDiv.style;\n innerStyle.width = \"100px\";\n innerStyle.height = \"100px\";\n\n outerDiv.appendChild(innerDiv);\n\n document.body.appendChild(outerDiv);\n\n if (outerDiv.scrollLeft > 0) {\n cachedRTLResult = \"positive-descending\";\n } else {\n outerDiv.scrollLeft = 1;\n if (outerDiv.scrollLeft === 0) {\n cachedRTLResult = \"negative\";\n } else {\n cachedRTLResult = \"positive-ascending\";\n }\n }\n\n document.body.removeChild(outerDiv);\n\n return cachedRTLResult;\n }\n\n return cachedRTLResult;\n}\n","import type { Direction } from \"../core/types\";\nimport { getRTLOffsetType } from \"./getRTLOffsetType\";\n\nexport function adjustScrollOffsetForRtl({\n containerElement,\n direction,\n isRtl,\n scrollOffset\n}: {\n containerElement: HTMLElement | null;\n direction: Direction;\n isRtl: boolean;\n scrollOffset: number;\n}) {\n // TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.\n // This is not the case for all browsers though (e.g. Chrome reports values as positive, measured relative to the left).\n // So we need to determine which browser behavior we're dealing with, and mimic it.\n if (direction === \"horizontal\") {\n if (isRtl) {\n switch (getRTLOffsetType()) {\n case \"negative\": {\n return -scrollOffset;\n }\n case \"positive-descending\": {\n if (containerElement) {\n const { clientWidth, scrollLeft, scrollWidth } = containerElement;\n return scrollWidth - clientWidth - scrollLeft;\n }\n break;\n }\n }\n }\n }\n return scrollOffset;\n}\n","export function assert(\n expectedCondition: unknown,\n message: string = \"Assertion error\"\n): asserts expectedCondition {\n if (!expectedCondition) {\n console.error(message);\n\n throw Error(message);\n }\n}\n","import { assert } from \"./assert\";\n\nexport function shallowCompare<Type extends object>(\n a: Type | undefined,\n b: Type | undefined\n) {\n if (a === b) {\n return true;\n }\n\n if (!!a !== !!b) {\n return false;\n }\n\n assert(a !== undefined);\n assert(b !== undefined);\n\n if (Object.keys(a).length !== Object.keys(b).length) {\n return false;\n }\n\n for (const key in a) {\n if (!Object.is(b[key], a[key])) {\n return false;\n }\n }\n\n return true;\n}\n","import type { CachedBounds, SizeFunction } from \"./types\";\nimport { assert } from \"../utils/assert\";\n\nexport function getEstimatedSize<Props extends object>({\n cachedBounds,\n itemCount,\n itemSize\n}: {\n cachedBounds: CachedBounds;\n itemCount: number;\n itemSize: number | SizeFunction<Props>;\n}) {\n if (itemCount === 0) {\n return 0;\n } else if (typeof itemSize === \"number\") {\n return itemCount * itemSize;\n } else {\n const bounds = cachedBounds.get(\n cachedBounds.size === 0 ? 0 : cachedBounds.size - 1\n );\n assert(bounds !== undefined, \"Unexpected bounds cache miss\");\n\n const averageItemSize =\n (bounds.scrollOffset + bounds.size) / cachedBounds.size;\n\n return itemCount * averageItemSize;\n }\n}\n","import type { Align } from \"../types\";\nimport { getEstimatedSize } from \"./getEstimatedSize\";\nimport type { CachedBounds, SizeFunction } from \"./types\";\n\nexport function getOffsetForIndex<Props extends object>({\n align,\n cachedBounds,\n index,\n itemCount,\n itemSize,\n containerScrollOffset,\n containerSize\n}: {\n align: Align;\n cachedBounds: CachedBounds;\n index: number;\n itemCount: number;\n itemSize: number | SizeFunction<Props>;\n containerScrollOffset: number;\n containerSize: number;\n}) {\n if (index < 0 || index >= itemCount) {\n throw RangeError(`Invalid index specified: ${index}`, {\n cause: `Index ${index} is not within the range of 0 - ${itemCount - 1}`\n });\n }\n\n const estimatedTotalSize = getEstimatedSize({\n cachedBounds,\n itemCount,\n itemSize\n });\n\n const bounds = cachedBounds.get(index);\n const maxOffset = Math.max(\n 0,\n Math.min(estimatedTotalSize - containerSize, bounds.scrollOffset)\n );\n const minOffset = Math.max(\n 0,\n bounds.scrollOffset - containerSize + bounds.size\n );\n\n if (align === \"smart\") {\n if (\n containerScrollOffset >= minOffset &&\n containerScrollOffset <= maxOffset\n ) {\n align = \"auto\";\n } else {\n align = \"center\";\n }\n }\n\n switch (align) {\n case \"start\": {\n return maxOffset;\n }\n case \"end\": {\n return minOffset;\n }\n case \"center\": {\n if (bounds.scrollOffset <= containerSize / 2) {\n // Too near the beginning to center-align\n return 0;\n } else if (\n bounds.scrollOffset + bounds.size / 2 >=\n estimatedTotalSize - containerSize / 2\n ) {\n // Too near the end to center-align\n return estimatedTotalSize - containerSize;\n } else {\n return bounds.scrollOffset + bounds.size / 2 - containerSize / 2;\n }\n }\n case \"auto\":\n default: {\n if (\n containerScrollOffset >= minOffset &&\n containerScrollOffset <= maxOffset\n ) {\n return containerScrollOffset;\n } else if (containerScrollOffset < minOffset) {\n return minOffset;\n } else {\n return maxOffset;\n }\n }\n }\n}\n","import type { CachedBounds } from \"./types\";\n\nexport function getStartStopIndices({\n cachedBounds,\n containerScrollOffset,\n containerSize,\n itemCount,\n overscanCount\n}: {\n cachedBounds: CachedBounds;\n containerScrollOffset: number;\n containerSize: number;\n itemCount: number;\n overscanCount: number;\n}): {\n startIndexVisible: number;\n stopIndexVisible: number;\n startIndexOverscan: number;\n stopIndexOverscan: number;\n} {\n const maxIndex = itemCount - 1;\n\n let startIndexVisible = 0;\n let stopIndexVisible = -1;\n let startIndexOverscan = 0;\n let stopIndexOverscan = -1;\n let currentIndex = 0;\n\n while (currentIndex < maxIndex) {\n const bounds = cachedBounds.get(currentIndex);\n\n if (bounds.scrollOffset + bounds.size > containerScrollOffset) {\n break;\n }\n\n currentIndex++;\n }\n\n startIndexVisible = currentIndex;\n startIndexOverscan = Math.max(0, startIndexVisible - overscanCount);\n\n while (currentIndex < maxIndex) {\n const bounds = cachedBounds.get(currentIndex);\n\n if (\n bounds.scrollOffset + bounds.size >=\n containerScrollOffset + containerSize\n ) {\n break;\n }\n\n currentIndex++;\n }\n\n stopIndexVisible = Math.min(maxIndex, currentIndex);\n stopIndexOverscan = Math.min(itemCount - 1, stopIndexVisible + overscanCount);\n\n if (startIndexVisible < 0) {\n startIndexVisible = 0;\n stopIndexVisible = -1;\n startIndexOverscan = 0;\n stopIndexOverscan = -1;\n }\n\n return {\n startIndexVisible,\n stopIndexVisible,\n startIndexOverscan,\n stopIndexOverscan\n };\n}\n","import { assert } from \"../utils/assert\";\nimport type { Bounds, CachedBounds, SizeFunction } from \"./types\";\n\nexport function createCachedBounds<Props extends object>({\n itemCount,\n itemProps,\n itemSize\n}: {\n itemCount: number;\n itemProps: Props;\n itemSize: number | SizeFunction<Props>;\n}): CachedBounds {\n const cache = new Map<number, Bounds>();\n\n return {\n get(index: number) {\n assert(index < itemCount, `Invalid index ${index}`);\n\n while (cache.size - 1 < index) {\n const currentIndex = cache.size;\n\n let size: number;\n switch (typeof itemSize) {\n case \"function\": {\n size = itemSize(currentIndex, itemProps);\n break;\n }\n case \"number\": {\n size = itemSize;\n break;\n }\n }\n\n if (currentIndex === 0) {\n cache.set(currentIndex, {\n size,\n scrollOffset: 0\n });\n } else {\n const previousRowBounds = cache.get(currentIndex - 1);\n assert(\n previousRowBounds !== undefined,\n `Unexpected bounds cache miss for index ${index}`\n );\n\n cache.set(currentIndex, {\n scrollOffset:\n previousRowBounds.scrollOffset + previousRowBounds.size,\n size\n });\n }\n }\n\n const bounds = cache.get(index);\n assert(\n bounds !== undefined,\n `Unexpected bounds cache miss for index ${index}`\n );\n\n return bounds;\n },\n set(index: number, bounds: Bounds) {\n cache.set(index, bounds);\n },\n get size() {\n return cache.size;\n }\n };\n}\n","import { useMemo } from \"react\";\nimport { createCachedBounds } from \"./createCachedBounds\";\nimport type { CachedBounds, SizeFunction } from \"./types\";\n\nexport function useCachedBounds<Props extends object>({\n itemCount,\n itemProps,\n itemSize\n}: {\n itemCount: number;\n itemProps: Props;\n itemSize: number | SizeFunction<Props>;\n}): CachedBounds {\n return useMemo(\n () =>\n createCachedBounds({\n itemCount,\n itemProps,\n itemSize\n }),\n [itemCount, itemProps, itemSize]\n );\n}\n","import { assert } from \"../utils/assert\";\nimport type { SizeFunction } from \"./types\";\n\nexport function useItemSize<Props extends object>({\n containerSize,\n itemSize: itemSizeProp\n}: {\n containerSize: number;\n itemSize: number | string | SizeFunction<Props>;\n}) {\n let itemSize: number | SizeFunction<Props>;\n switch (typeof itemSizeProp) {\n case \"string\": {\n assert(\n itemSizeProp.endsWith(\"%\"),\n `Invalid item size: \"${itemSizeProp}\"; string values must be percentages (e.g. \"100%\")`\n );\n assert(\n containerSize !== undefined,\n \"Container size must be defined if a percentage item size is specified\"\n );\n\n itemSize = (containerSize * parseInt(itemSizeProp)) / 100;\n break;\n }\n default: {\n itemSize = itemSizeProp;\n break;\n }\n }\n\n return itemSize;\n}\n","import {\n useCallback,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties\n} from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../hooks/useIsomorphicLayoutEffect\";\nimport { useResizeObserver } from \"../hooks/useResizeObserver\";\nimport { useStableCallback } from \"../hooks/useStableCallback\";\nimport type { Align } from \"../types\";\nimport { adjustScrollOffsetForRtl } from \"../utils/adjustScrollOffsetForRtl\";\nimport { shallowCompare } from \"../utils/shallowCompare\";\nimport { getEstimatedSize as getEstimatedSizeUtil } from \"./getEstimatedSize\";\nimport { getOffsetForIndex } from \"./getOffsetForIndex\";\nimport { getStartStopIndices as getStartStopIndicesUtil } from \"./getStartStopIndices\";\nimport type { Direction, SizeFunction } from \"./types\";\nimport { useCachedBounds } from \"./useCachedBounds\";\nimport { useItemSize } from \"./useItemSize\";\n\nexport function useVirtualizer<Props extends object>({\n containerElement,\n containerStyle,\n defaultContainerSize = 0,\n direction,\n isRtl = false,\n itemCount,\n itemProps,\n itemSize: itemSizeProp,\n onResize,\n overscanCount\n}: {\n containerElement: HTMLElement | null;\n containerStyle?: CSSProperties;\n defaultContainerSize?: number;\n direction: Direction;\n isRtl?: boolean;\n itemCount: number;\n itemProps: Props;\n itemSize: number | string | SizeFunction<Props>;\n onResize:\n | ((\n size: { height: number; width: number },\n prevSize: { height: number; width: number }\n ) => void)\n | undefined;\n overscanCount: number;\n}) {\n const { height = defaultContainerSize, width = defaultContainerSize } =\n useResizeObserver({\n defaultHeight:\n direction === \"vertical\" ? defaultContainerSize : undefined,\n defaultWidth:\n direction === \"horizontal\" ? defaultContainerSize : undefined,\n element: containerElement,\n mode: direction === \"vertical\" ? \"only-height\" : \"only-width\",\n style: containerStyle\n });\n\n const prevSizeRef = useRef<{ height: number; width: number }>({\n height: 0,\n width: 0\n });\n\n const containerSize = direction === \"vertical\" ? height : width;\n\n const itemSize = useItemSize({ containerSize, itemSize: itemSizeProp });\n\n useLayoutEffect(() => {\n if (typeof onResize === \"function\") {\n const prevSize = prevSizeRef.current;\n\n if (prevSize.height !== height || prevSize.width !== width) {\n onResize({ height, width }, { ...prevSize });\n\n prevSize.height = height;\n prevSize.width = width;\n }\n }\n }, [height, onResize, width]);\n\n const cachedBounds = useCachedBounds({\n itemCount,\n itemProps,\n itemSize\n });\n\n const getCellBounds = useCallback(\n (index: number) => cachedBounds.get(index),\n [cachedBounds]\n );\n\n const [indices, setIndices] = useState<{\n startIndexVisible: number;\n stopIndexVisible: number;\n startIndexOverscan: number;\n stopIndexOverscan: number;\n }>(() =>\n getStartStopIndicesUtil({\n cachedBounds,\n // TODO Potentially support a defaultScrollOffset prop?\n containerScrollOffset: 0,\n containerSize,\n itemCount,\n overscanCount\n })\n );\n\n // Guard against temporarily invalid indices that may occur when item count decreases\n // Cached bounds object will be re-created and a second render will restore things\n const {\n startIndexVisible,\n startIndexOverscan,\n stopIndexVisible,\n stopIndexOverscan\n } = {\n startIndexVisible: Math.min(itemCount - 1, indices.startIndexVisible),\n startIndexOverscan: Math.min(itemCount - 1, indices.startIndexOverscan),\n stopIndexVisible: Math.min(itemCount - 1, indices.stopIndexVisible),\n stopIndexOverscan: Math.min(itemCount - 1, indices.stopIndexOverscan)\n };\n\n const getEstimatedSize = useCallback(\n () =>\n getEstimatedSizeUtil({\n cachedBounds,\n itemCount,\n itemSize\n }),\n [cachedBounds, itemCount, itemSize]\n );\n\n const getStartStopIndices = useCallback(\n (scrollOffset: number) => {\n const containerScrollOffset = adjustScrollOffsetForRtl({\n containerElement,\n direction,\n isRtl,\n scrollOffset\n });\n\n return getStartStopIndicesUtil({\n cachedBounds,\n containerScrollOffset,\n containerSize,\n itemCount,\n overscanCount\n });\n },\n [\n cachedBounds,\n containerElement,\n containerSize,\n direction,\n isRtl,\n itemCount,\n overscanCount\n ]\n );\n\n useIsomorphicLayoutEffect(() => {\n const scrollOffset =\n (direction === \"vertical\"\n ? containerElement?.scrollTop\n : containerElement?.scrollLeft) ?? 0;\n\n setIndices(getStartStopIndices(scrollOffset));\n }, [containerElement, direction, getStartStopIndices]);\n\n useIsomorphicLayoutEffect(() => {\n if (!containerElement) {\n return;\n }\n\n const onScroll = () => {\n setIndices((prev) => {\n const { scrollLeft, scrollTop } = containerElement;\n\n const scrollOffset = adjustScrollOffsetForRtl({\n containerElement,\n direction,\n isRtl,\n scrollOffset: direction === \"vertical\" ? scrollTop : scrollLeft\n });\n\n const next = getStartStopIndicesUtil({\n cachedBounds,\n containerScrollOffset: scrollOffset,\n containerSize,\n itemCount,\n overscanCount\n });\n\n if (shallowCompare(next, prev)) {\n return prev;\n }\n\n return next;\n });\n };\n\n containerElement.addEventListener(\"scroll\", onScroll);\n\n return () => {\n containerElement.removeEventListener(\"scroll\", onScroll);\n };\n }, [\n cachedBounds,\n containerElement,\n containerSize,\n direction,\n itemCount,\n overscanCount\n ]);\n\n const scrollToIndex = useStableCallback(\n ({\n align = \"auto\",\n containerScrollOffset,\n index\n }: {\n align?: Align;\n containerScrollOffset: number;\n index: number;\n }) => {\n let scrollOffset = getOffsetForIndex({\n align,\n cachedBounds,\n containerScrollOffset,\n containerSize,\n index,\n itemCount,\n itemSize\n });\n\n if (containerElement) {\n scrollOffset = adjustScrollOffsetForRtl({\n containerElement,\n direction,\n isRtl,\n scrollOffset\n });\n\n if (typeof containerElement.scrollTo !== \"function\") {\n // Special case for environments like jsdom that don't implement scrollTo\n const next = getStartStopIndices(scrollOffset);\n if (!shallowCompare(indices, next)) {\n setIndices(next);\n }\n }\n\n return scrollOffset;\n }\n }\n );\n\n return {\n getCellBounds,\n getEstimatedSize,\n scrollToIndex,\n startIndexOverscan,\n startIndexVisible,\n stopIndexOverscan,\n stopIndexVisible\n };\n}\n","import { useMemo } from \"react\";\n\nexport function useMemoizedObject<Type extends object>(\n unstableObject: Type\n): Type {\n return useMemo(() => {\n return unstableObject;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, Object.values(unstableObject));\n}\n","import type { CSSProperties } from \"react\";\nimport { shallowCompare } from \"./shallowCompare\";\n\n// Custom comparison function for React.memo()\n// It knows to compare individual style props and ignore the wrapper object.\n// See https://react.dev/reference/react/memo#memo\nexport function arePropsEqual(\n prevProps: { ariaAttributes: object; style: CSSProperties },\n nextProps: { ariaAttributes: object; style: CSSProperties }\n): boolean {\n const {\n ariaAttributes: prevAriaAttributes,\n style: prevStyle,\n ...prevRest\n } = prevProps;\n const {\n ariaAttributes: nextAriaAttributes,\n style: nextStyle,\n ...nextRest\n } = nextProps;\n\n return (\n shallowCompare(prevAriaAttributes, nextAriaAttributes) &&\n shallowCompare(prevStyle, nextStyle) &&\n shallowCompare(prevRest, nextRest)\n );\n}\n","\"use client\";\n\nimport {\n createElement,\n memo,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n type ReactElement,\n type ReactNode\n} from \"react\";\nimport { useIsRtl } from \"../../core/useIsRtl\";\nimport { useVirtualizer } from \"../../core/useVirtualizer\";\nimport { useMemoizedObject } from \"../../hooks/useMemoizedObject\";\nimport type { Align, TagNames } from \"../../types\";\nimport { arePropsEqual } from \"../../utils/arePropsEqual\";\nimport type { GridProps } from \"./types\";\n\n/**\n * Renders data with many rows and columns.\n */\nexport function Grid<\n CellProps extends object,\n TagName extends TagNames = \"div\"\n>({\n cellComponent: CellComponentProp,\n cellProps: cellPropsUnstable,\n children,\n className,\n columnCount,\n columnWidth,\n defaultHeight = 0,\n defaultWidth = 0,\n dir,\n gridRef,\n onCellsRendered,\n onResize,\n overscanCount = 3,\n rowCount,\n rowHeight,\n style,\n tagName = \"div\" as TagName,\n ...rest\n}: GridProps<CellProps, TagName>): ReactElement {\n const cellProps = useMemoizedObject(cellPropsUnstable);\n const CellComponent = useMemo(\n () => memo(CellComponentProp, arePropsEqual),\n [CellComponentProp]\n );\n\n const [element, setElement] = useState<HTMLDivElement | null>(null);\n\n const isRtl = useIsRtl(element, dir);\n\n const {\n getCellBounds: getColumnBounds,\n getEstimatedSize: getEstimatedWidth,\n startIndexOverscan: columnStartIndexOverscan,\n startIndexVisible: columnStartIndexVisible,\n scrollToIndex: scrollToColumnIndex,\n stopIndexOverscan: columnStopIndexOverscan,\n stopIndexVisible: columnStopIndexVisible\n } = useVirtualizer({\n containerElement: element,\n containerStyle: style,\n defaultContainerSize: defaultWidth,\n direction: \"horizontal\",\n isRtl,\n itemCount: columnCount,\n itemProps: cellProps,\n itemSize: columnWidth,\n onResize,\n overscanCount\n });\n\n const {\n getCellBounds: getRowBounds,\n getEstimatedSize: getEstimatedHeight,\n startIndexOverscan: rowStartIndexOverscan,\n startIndexVisible: rowStartIndexVisible,\n scrollToIndex: scrollToRowIndex,\n stopIndexOverscan: rowStopIndexOverscan,\n stopIndexVisible: rowStopIndexVisible\n } = useVirtualizer({\n containerElement: element,\n containerStyle: style,\n defaultContainerSize: defaultHeight,\n direction: \"vertical\",\n itemCount: rowCount,\n itemProps: cellProps,\n itemSize: rowHeight,\n onResize,\n overscanCount\n });\n\n useImperativeHandle(\n gridRef,\n () => ({\n get element() {\n return element;\n },\n\n scrollToCell({\n behavior = \"auto\",\n columnAlign = \"auto\",\n columnIndex,\n rowAlign = \"auto\",\n rowIndex\n }: {\n behavior?: ScrollBehavior;\n columnAlign?: Align;\n columnIndex: number;\n rowAlign?: Align;\n rowIndex: number;\n }) {\n const left = scrollToColumnIndex({\n align: columnAlign,\n containerScrollOffset: element?.scrollLeft ?? 0,\n index: columnIndex\n });\n const top = scrollToRowIndex({\n align: rowAlign,\n containerScrollOffset: element?.scrollTop ?? 0,\n index: rowIndex\n });\n\n if (typeof element?.scrollTo === \"function\") {\n element.scrollTo({\n behavior,\n left,\n top\n });\n }\n },\n\n scrollToColumn({\n align = \"auto\",\n behavior = \"auto\",\n index\n }: {\n align?: Align;\n behavior?: ScrollBehavior;\n index: number;\n }) {\n const left = scrollToColumnIndex({\n align,\n containerScrollOffset: element?.scrollLeft ?? 0,\n index\n });\n\n if (typeof element?.scrollTo === \"function\") {\n element.scrollTo({\n behavior,\n left\n });\n }\n },\n\n scrollToRow({\n align = \"auto\",\n behavior = \"auto\",\n index\n }: {\n align?: Align;\n behavior?: ScrollBehavior;\n index: number;\n }) {\n const top = scrollToRowIndex({\n align,\n containerScrollOffset: element?.scrollTop ?? 0,\n index\n });\n\n if (typeof element?.scrollTo === \"function\") {\n element.scrollTo({\n behavior,\n top\n });\n }\n }\n }),\n [element, scrollToColumnIndex, scrollToRowIndex]\n );\n\n useEffect(() => {\n if (\n columnStartIndexOverscan >= 0 &&\n columnStopIndexOverscan >= 0 &&\n rowStartIndexOverscan >= 0 &&\n rowStopIndexOverscan >= 0 &&\n onCellsRendered\n ) {\n onCellsRendered(\n {\n columnStartIndex: columnStartIndexVisible,\n columnStopIndex: columnStopIndexVisible,\n rowStartIndex: rowStartIndexVisible,\n rowStopIndex: rowStopIndexVisible\n },\n {\n columnStartIndex: columnStartIndexOverscan,\n columnStopIndex: columnStopIndexOverscan,\n rowStartIndex: rowStartIndexOverscan,\n rowStopIndex: rowStopIndexOverscan\n }\n );\n }\n }, [\n onCellsRendered,\n columnStartIndexOverscan,\n columnStartIndexVisible,\n columnStopIndexOverscan,\n columnStopIndexVisible,\n rowStartIndexOverscan,\n rowStartIndexVisible,\n rowStopIndexOverscan,\n rowStopIndexVisible\n ]);\n\n const cells = useMemo(() => {\n const children: ReactNode[] = [];\n if (columnCount > 0 && rowCount > 0) {\n for (\n let rowIndex = rowStartIndexOverscan;\n rowIndex <= rowStopIndexOverscan;\n rowIndex++\n ) {\n const rowBounds = getRowBounds(rowIndex);\n\n const columns: ReactNode[] = [];\n\n for (\n let columnIndex = columnStartIndexOverscan;\n columnIndex <= columnStopIndexOverscan;\n columnIndex++\n ) {\n const columnBounds = getColumnBounds(columnIndex);\n\n columns.push(\n <CellComponent\n {...(cellProps as CellProps)}\n ariaAttributes={{\n \"aria-colindex\": columnIndex + 1,\n role: \"gridcell\"\n }}\n columnIndex={columnIndex}\n key={columnIndex}\n rowIndex={rowIndex}\n style={{\n position: \"absolute\",\n left: isRtl ? undefined : 0,\n right: isRtl ? 0 : undefined,\n transform: `translate(${isRtl ? -columnBounds.scrollOffset : columnBounds.scrollOffset}px, ${rowBounds.scrollOffset}px)`,\n height: rowBounds.size,\n width: columnBounds.size\n }}\n />\n );\n }\n\n children.push(\n <div key={rowIndex} role=\"row\" aria-rowindex={rowIndex + 1}>\n {columns}\n </div>\n );\n }\n }\n return children;\n }, [\n CellComponent,\n cellProps,\n columnCount,\n columnStartIndexOverscan,\n columnStopIndexOverscan,\n getColumnBounds,\n getRowBounds,\n isRtl,\n rowCount,\n rowStartIndexOverscan,\n rowStopIndexOverscan\n ]);\n\n const sizingElement = (\n <div\n aria-hidden\n style={{\n height: getEstimatedHeight(),\n width: getEstimatedWidth(),\n zIndex: -1\n }}\n ></div>\n );\n\n return createElement(\n tagName,\n {\n \"aria-colcount\": columnCount,\n \"aria-rowcount\": rowCount,\n role: \"grid\",\n ...rest,\n className,\n dir,\n ref: setElement,\n style: {\n position: \"relative\",\n maxHeight: \"100%\",\n maxWidth: \"100%\",\n flexGrow: 1,\n overflow: \"auto\",\n ...style\n }\n },\n cells,\n children,\n sizingElement\n );\n}\n","import { useState } from \"react\";\nimport type { GridImperativeAPI } from \"./types\";\n\n/**\n * Convenience hook to return a properly typed ref callback for the Grid component.\n *\n * Use this hook when you need to share the ref with another component or hook.\n */\nexport const useGridCallbackRef =\n useState as typeof useState<GridImperativeAPI | null>;\n","import { useRef } from \"react\";\nimport type { GridImperativeAPI } from \"./types\";\n\n/**\n * Convenience hook to return a properly typed ref for the Grid component.\n */\nexport const useGridRef = useRef as typeof useRef<GridImperativeAPI>;\n","import type { DynamicRowHeight } from \"./types\";\n\nexport function isDynamicRowHeight(value: unknown): value is DynamicRowHeight {\n return (\n value != null &&\n typeof value === \"object\" &&\n \"getAverageRowHeight\" in value &&\n typeof value.getAverageRowHeight === \"function\"\n );\n}\n","\"use client\";\n\nimport {\n createElement,\n memo,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n type ReactElement,\n type ReactNode\n} from \"react\";\nimport { useVirtualizer } from \"../../core/useVirtualizer\";\nimport { useIsomorphicLayoutEffect } from \"../../hooks/useIsomorphicLayoutEffect\";\nimport { useMemoizedObject } from \"../../hooks/useMemoizedObject\";\nimport type { Align, TagNames } from \"../../types\";\nimport { arePropsEqual } from \"../../utils/arePropsEqual\";\nimport { isDynamicRowHeight as isDynamicRowHeightUtil } from \"./isDynamicRowHeight\";\nimport type { ListProps } from \"./types\";\n\nexport const DATA_ATTRIBUTE_LIST_INDEX = \"data-react-window-index\";\n\n/**\n * Renders data with many rows.\n */\nexport function List<\n RowProps extends object,\n TagName extends TagNames = \"div\"\n>({\n children,\n className,\n defaultHeight = 0,\n listRef,\n onResize,\n onRowsRendered,\n overscanCount = 3,\n rowComponent: RowComponentProp,\n rowCount,\n rowHeight: rowHeightProp,\n rowProps: rowPropsUnstable,\n tagName = \"div\" as TagName,\n style,\n ...rest\n}: ListProps<RowProps, TagName>): ReactElement {\n const rowProps = useMemoizedObject(rowPropsUnstable);\n const RowComponent = useMemo(\n () => memo(RowComponentProp, arePropsEqual),\n [RowComponentProp]\n );\n\n const [element, setElement] = useState<HTMLDivElement | null>(null);\n\n const isDynamicRowHeight = isDynamicRowHeightUtil(rowHeightProp);\n\n const rowHeight = useMemo(() => {\n if (isDynamicRowHeight) {\n return (index: number) => {\n return (\n rowHeightProp.getRowHeight(index) ??\n rowHeightProp.getAverageRowHeight()\n );\n };\n }\n\n return rowHeightProp;\n }, [isDynamicRowHeight, rowHeightProp]);\n\n const {\n getCellBounds,\n getEstimatedSize,\n scrollToIndex,\n startIndexOverscan,\n startIndexVisible,\n stopIndexOverscan,\n stopIndexVisible\n } = useVirtualizer({\n containerElement: element,\n containerStyle: style,\n defaultContainerSize: defaultHeight,\n direction: \"vertical\",\n itemCount: rowCount,\n itemProps: rowProps,\n itemSize: rowHeight,\n onResize,\n overscanCount\n });\n\n useImperativeHandle(\n listRef,\n () => ({\n get element() {\n return element;\n },\n\n scrollToRow({\n align = \"auto\",\n behavior = \"auto\",\n index\n }: {\n align?: Align;\n behavior?: ScrollBehavior;\n index: number;\n }) {\n const top = scrollToIndex({\n align,\n containerScrollOffset: element?.scrollTop ?? 0,\n index\n });\n\n if (typeof element?.scrollTo === \"function\") {\n element.scrollTo({\n behavior,\n top\n });\n }\n }\n }),\n [element, scrollToIndex]\n );\n\n useIsomorphicLayoutEffect(() => {\n if (!element) {\n return;\n }\n\n const rows = Array.from(element.children).filter((item, index) => {\n if (item.hasAttribute(\"aria-hidden\")) {\n // Ignore sizing element\n return false;\n }\n\n const attribute = `${startIndexOverscan + index}`;\n item.setAttribute(DATA_ATTRIBUTE_LIST_INDEX, attribute);\n\n return true;\n });\n\n if (isDynamicRowHeight) {\n return rowHeightProp.observeRowElements(rows);\n }\n }, [\n element,\n isDynamicRowHeight,\n rowHeightProp,\n startIndexOverscan,\n stopIndexOverscan\n ]);\n\n useEffect(() => {\n if (startIndexOverscan >= 0 && stopIndexOverscan >= 0 && onRowsRendered) {\n onRowsRendered(\n {\n startIndex: startIndexVisible,\n stopIndex: stopIndexVisible\n },\n {\n startIndex: startIndexOverscan,\n stopIndex: stopIndexOverscan\n }\n );\n }\n }, [\n onRowsRendered,\n startIndexOverscan,\n startIndexVisible,\n stopIndexOverscan,\n stopIndexVisible\n ]);\n\n const rows = useMemo(() => {\n const children: ReactNode[] = [];\n if (rowCount > 0) {\n for (\n let index = startIndexOverscan;\n index <= stopIndexOverscan;\n index++\n ) {\n const bounds = getCellBounds(index);\n\n children.push(\n <RowComponent\n {...(rowProps as RowProps)}\n ariaAttributes={{\n \"aria-posinset\": index + 1,\n \"aria-setsize\": rowCount,\n role: \"listitem\"\n }}\n key={index}\n index={index}\n style={{\n position: \"absolute\",\n left: 0,\n transform: `translateY(${bounds.scrollOffset}px)`,\n // In case of dynamic row heights, don't specify a height style\n // otherwise a default/estimated height would mask the actual height\n height: isDynamicRowHeight ? undefined : bounds.size,\n width: \"100%\"\n }}\n />\n );\n }\n }\n return children;\n }, [\n RowComponent,\n getCellBounds,\n isDynamicRowHeight,\n rowCount,\n rowProps,\n startIndexOverscan,\n stopIndexOverscan\n ]);\n\n const sizingElement = (\n <div\n aria-hidden\n style={{\n height: getEstimatedSize(),\n width: \"100%\",\n zIndex: -1\n }}\n ></div>\n );\n\n return createElement(\n tagName,\n {\n role: \"list\",\n ...rest,\n className,\n ref: setElement,\n style: {\n position: \"relative\",\n maxHeight: \"100%\",\n flexGrow: 1,\n overflowY: \"auto\",\n ...style\n }\n },\n rows,\n children,\n sizingElement\n );\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useStableCallback } from \"../../hooks/useStableCallback\";\nimport { assert } from \"../../utils/assert\";\nimport { DATA_ATTRIBUTE_LIST_INDEX } from \"./List\";\nimport type { DynamicRowHeight } from \"./types\";\n\nexport function useDynamicRowHeight({\n defaultRowHeight,\n key\n}: {\n defaultRowHeight: number;\n key?: string | number;\n}) {\n const [state, setState] = useState<{\n key: string | number | undefined;\n map: Map<number, number>;\n }>({\n key,\n map: new Map()\n });\n\n if (state.key !== key) {\n setState({\n key,\n map: new Map()\n });\n }\n\n const { map } = state;\n\n const getAverageRowHeight = useCallback(() => {\n let totalHeight = 0;\n\n map.forEach((height) => {\n totalHeight += height;\n });\n\n if (totalHeight === 0) {\n return defaultRowHeight;\n }\n\n return totalHeight / map.size;\n }, [defaultRowHeight, map]);\n\n const getRowHeight = useCallback(\n (index: number) => {\n const measuredHeight = map.get(index);\n if (measuredHeight !== undefined) {\n return measuredHeight;\n }\n\n // Temporarily store default height in the cache map to avoid scroll jumps if rowProps change\n // Else rowProps changes can impact the average height, and cause rows to shift up or down within the list\n // see github.com/bvaughn/react-window/issues/863\n map.set(index, defaultRowHeight);\n\n return defaultRowHeight;\n },\n [defaultRowHeight, map]\n );\n\n const setRowHeight = useCallback((index: number, size: number) => {\n setState((prevState) => {\n if (prevState.map.get(index) === size) {\n return prevState;\n }\n\n const clonedMap = new Map(prevState.map);\n clonedMap.set(index, size);\n\n return {\n ...prevState,\n map: clonedMap\n };\n });\n }, []);\n\n const resizeObserverCallback = useStableCallback(\n (entries: ResizeObserverEntry[]) => {\n if (entries.length === 0) {\n return;\n }\n\n entries.forEach((entry) => {\n const { borderBoxSize, target } = entry;\n\n const attribute = target.getAttribute(DATA_ATTRIBUTE_LIST_INDEX);\n assert(\n attribute !== null,\n `Invalid ${DATA_ATTRIBUTE_LIST_INDEX} attribute value`\n );\n\n const index = parseInt(attribute);\n\n const { blockSize: height } = borderBoxSize[0];\n if (!height) {\n // Ignore heights that have not yet been measured (e.g. <img> elements that have not yet loaded)\n return;\n }\n\n setRowHeight(index, height);\n });\n }\n );\n\n const [resizeObserver] = useState(\n () => new ResizeObserver(resizeObserverCallback)\n );\n\n useEffect(() => {\n return () => {\n resizeObserver.disconnect();\n };\n }, [resizeObserver]);\n\n const observeRowElements = useCallback(\n (elements: Element[] | NodeListOf<Element>) => {\n elements.forEach((element) => resizeObserver.observe(element));\n return () => {\n elements.forEach((element) => resizeObserver.unobserve(element));\n };\n },\n [resizeObserver]\n );\n\n return useMemo<DynamicRowHeight>(\n () => ({\n getAverageRowHeight,\n getRowHeight,\n setRowHeight,\n observeRowElements\n }),\n [getAverageRowHeight, getRowHeight, setRowHeight, observeRowElements]\n );\n}\n","import { useState } from \"react\";\nimport type { ListImperativeAPI } from \"./types\";\n\n/**\n * Convenience hook to return a properly typed ref callback for the List component.\n *\n * Use this hook when you need to share the ref with another component or hook.\n */\nexport const useListCallbackRef =\n useState as typeof useState<ListImperativeAPI | null>;\n","import { useRef } from \"react\";\nimport type { ListImperativeAPI } from \"./types\";\n\n/**\n * Convenience hook to return a properly typed ref for the List component.\n */\nexport const useListRef = useRef as typeof useRef<ListImperativeAPI>;\n","let size: number = -1;\n\nexport function getScrollbarSize(recalculate: boolean = false): number {\n if (size === -1 || recalculate) {\n const div = document.createElement(\"div\");\n const style = div.style;\n style.width = \"50px\";\n style.height = \"50px\";\n style.overflow = \"scroll\";\n\n document.body.appendChild(div);\n\n size = div.offsetWidth - div.clientWidth;\n\n document.body.removeChild(div);\n }\n\n return size;\n}\n\nexport function setScrollbarSizeForTests(value: number) {\n size = value;\n}\n"],"names":["isRtl","element","currentElement","useIsRtl","dir","value","setValue","useState","useLayoutEffect","useIsomorphicLayoutEffect","useEffect","parseNumericStyleValue","useResizeObserver","box","defaultHeight","defaultWidth","disabledProp","mode","style","styleHeight","styleWidth","useMemo","state","setState","disabled","resizeObserver","entries","entry","contentRect","target","prevState","useStableCallback","fn","ref","useRef","useCallback","args","cachedRTLResult","getRTLOffsetType","recalculate","outerDiv","outerStyle","innerDiv","innerStyle","adjustScrollOffsetForRtl","containerElement","direction","scrollOffset","clientWidth","scrollLeft","scrollWidth","assert","expectedCondition","message","shallowCompare","a","b","key","getEstimatedSize","cachedBounds","itemCount","itemSize","bounds","averageItemSize","getOffsetForIndex","align","index","containerScrollOffset","containerSize","estimatedTotalSize","maxOffset","minOffset","getStartStopIndices","overscanCount","maxIndex","startIndexVisible","stopIndexVisible","startIndexOverscan","stopIndexOverscan","currentIndex","createCachedBounds","itemProps","cache","size","previousRowBounds","useCachedBounds","useItemSize","itemSizeProp","useVirtualizer","containerStyle","defaultContainerSize","onResize","height","width","prevSizeRef","prevSize","getCellBounds","indices","setIndices","getStartStopIndicesUtil","getEstimatedSizeUtil","onScroll","prev","scrollTop","next","scrollToIndex","useMemoizedObject","unstableObject","arePropsEqual","prevProps","nextProps","prevAriaAttributes","prevStyle","prevRest","nextAriaAttributes","nextStyle","nextRest","Grid","CellComponentProp","cellPropsUnstable","children","className","columnCount","columnWidth","gridRef","onCellsRendered","rowCount","rowHeight","tagName","rest","cellProps","CellComponent","memo","setElement","getColumnBounds","getEstimatedWidth","columnStartIndexOverscan","columnStartIndexVisible","scrollToColumnIndex","columnStopIndexOverscan","columnStopIndexVisible","getRowBounds","getEstimatedHeight","rowStartIndexOverscan","rowStartIndexVisible","scrollToRowIndex","rowStopIndexOverscan","rowStopIndexVisible","useImperativeHandle","behavior","columnAlign","columnIndex","rowAlign","rowIndex","left","top","cells","rowBounds","columns","columnBounds","createElement","jsx","sizingElement","useGridCallbackRef","useGridRef","isDynamicRowHeight","DATA_ATTRIBUTE_LIST_INDEX","List","listRef","onRowsRendered","RowComponentProp","rowHeightProp","rowPropsUnstable","rowProps","RowComponent","isDynamicRowHeightUtil","rows","item","attribute","useDynamicRowHeight","defaultRowHeight","map","getAverageRowHeight","totalHeight","getRowHeight","measuredHeight","setRowHeight","clonedMap","resizeObserverCallback","borderBoxSize","observeRowElements","elements","useListCallbackRef","useListRef","getScrollbarSize","div"],"mappings":"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