diff --git a/change/@fluentui-react-virtualizer-eeedf712-20cc-43fd-afc3-c4bc3ce8f9d7.json b/change/@fluentui-react-virtualizer-eeedf712-20cc-43fd-afc3-c4bc3ce8f9d7.json new file mode 100644 index 0000000000000..eb7a69c4e2818 --- /dev/null +++ b/change/@fluentui-react-virtualizer-eeedf712-20cc-43fd-afc3-c4bc3ce8f9d7.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Fix: Ensure 'start buffer' is margin padded into the non-virtualized space on horizontal layouts", + "packageName": "@fluentui/react-virtualizer", + "email": "mifraser@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizer.ts b/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizer.ts index 9f6c4d24b0743..c624eca75bd47 100644 --- a/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizer.ts +++ b/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizer.ts @@ -113,7 +113,6 @@ export function useVirtualizer_unstable(props: VirtualizerProps): VirtualizerSta // Local updates updateChildRows(index); updateCurrentItemSizes(index); - // State setters setActualIndex(index); }; @@ -277,7 +276,7 @@ export function useVirtualizer_unstable(props: VirtualizerProps): VirtualizerSta }, [getItemSize, itemSize, numItems]); const calculateBefore = useCallback(() => { - const currentIndex = Math.min(actualIndex, numItems); + const currentIndex = Math.min(actualIndex, numItems - 1); if (!getItemSize) { // The missing items from before virtualization starts height @@ -293,19 +292,19 @@ export function useVirtualizer_unstable(props: VirtualizerProps): VirtualizerSta }, [actualIndex, getItemSize, itemSize, numItems]); const calculateAfter = useCallback(() => { - if (numItems === 0) { + if (numItems === 0 || actualIndex + virtualizerLength >= numItems) { return 0; } - const lastItemIndex = Math.min(actualIndex + virtualizerLength, numItems - 1); + const lastItemIndex = Math.min(actualIndex + virtualizerLength, numItems); if (!getItemSize) { // The missing items from after virtualization ends height - const remainingItems = numItems - lastItemIndex - 1; + const remainingItems = numItems - lastItemIndex; return remainingItems * itemSize; } // Time for custom size calcs - return childProgressiveSizes.current[numItems - 1] - childProgressiveSizes.current[lastItemIndex]; + return childProgressiveSizes.current[numItems - 1] - childProgressiveSizes.current[lastItemIndex - 1]; }, [actualIndex, getItemSize, itemSize, numItems, virtualizerLength]); const updateChildRows = useCallback( diff --git a/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizerStyles.styles.ts b/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizerStyles.styles.ts index 0f11ce8778d7b..b3fcfd4b20f3f 100644 --- a/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizerStyles.styles.ts +++ b/packages/react-components/react-virtualizer/src/components/Virtualizer/useVirtualizerStyles.styles.ts @@ -76,9 +76,9 @@ export const useVirtualizerStyles_unstable = (state: VirtualizerState): Virtuali // Column-Reverse ...(reversed && !horizontal && { marginTop: `-${bufferPx}` }), // Row - ...(!reversed && horizontal && { marginLeft: `-${bufferPx}` }), + ...(!reversed && horizontal && { marginRight: `-${bufferPx}` }), // Row-Reverse - ...(reversed && horizontal && { marginRight: `-${bufferPx}` }), + ...(reversed && horizontal && { marginLeft: `-${bufferPx}` }), }; const afterBuffer = { diff --git a/packages/react-components/react-virtualizer/src/components/VirtualizerScrollView/useVirtualizerScrollViewStyles.styles.ts b/packages/react-components/react-virtualizer/src/components/VirtualizerScrollView/useVirtualizerScrollViewStyles.styles.ts index cd0221a8cff35..15e818c0f0cb5 100644 --- a/packages/react-components/react-virtualizer/src/components/VirtualizerScrollView/useVirtualizerScrollViewStyles.styles.ts +++ b/packages/react-components/react-virtualizer/src/components/VirtualizerScrollView/useVirtualizerScrollViewStyles.styles.ts @@ -16,11 +16,9 @@ const useStyles = makeStyles({ display: 'flex', width: '100%', height: '100%', - overflowAnchor: 'none', }, vertical: { flexDirection: 'column', - overflowAnchor: 'none', overflowY: 'auto', }, horizontal: { diff --git a/packages/react-components/react-virtualizer/src/components/VirtualizerScrollViewDynamic/useVirtualizerScrollViewDynamicStyles.styles.ts b/packages/react-components/react-virtualizer/src/components/VirtualizerScrollViewDynamic/useVirtualizerScrollViewDynamicStyles.styles.ts index 40c3c2a9b18de..a1a58fb7e6994 100644 --- a/packages/react-components/react-virtualizer/src/components/VirtualizerScrollViewDynamic/useVirtualizerScrollViewDynamicStyles.styles.ts +++ b/packages/react-components/react-virtualizer/src/components/VirtualizerScrollViewDynamic/useVirtualizerScrollViewDynamicStyles.styles.ts @@ -18,7 +18,6 @@ const useStyles = makeStyles({ display: 'flex', width: '100%', height: '100%', - overflowAnchor: 'none', }, vertical: { flexDirection: 'column', diff --git a/packages/react-components/react-virtualizer/src/hooks/useDynamicVirtualizerMeasure.ts b/packages/react-components/react-virtualizer/src/hooks/useDynamicVirtualizerMeasure.ts index e026991d5801c..91302fe36d734 100644 --- a/packages/react-components/react-virtualizer/src/hooks/useDynamicVirtualizerMeasure.ts +++ b/packages/react-components/react-virtualizer/src/hooks/useDynamicVirtualizerMeasure.ts @@ -58,14 +58,14 @@ export const useDynamicVirtualizerMeasure = ( /* * Number of items to append at each end, i.e. 'preload' each side before entering view. */ - const bufferItems = Math.max(Math.floor(length / 4), 2); + const bufferItems = Math.max(Math.floor(length / 4), 4); /* * This is how far we deviate into the bufferItems to detect a redraw. */ const bufferSize = Math.max(Math.floor((length / 8) * defaultItemSize), 1); - const totalLength = length + bufferItems * 2 + 3; + const totalLength = length + bufferItems * 2 + 1; setState({ virtualizerLength: totalLength, virtualizerBufferSize: bufferSize, diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/Default.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/Default.stories.tsx index 28b75b3f13a2f..a1e8b98ff9145 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/Default.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/Default.stories.tsx @@ -6,7 +6,6 @@ const useStyles = makeStyles({ container: { display: 'flex', flexDirection: 'column', - overflowAnchor: 'none', overflowY: 'auto', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/DefaultUnbounded.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/DefaultUnbounded.stories.tsx index 799190d010d26..a22d4758951ae 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/DefaultUnbounded.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/DefaultUnbounded.stories.tsx @@ -14,7 +14,6 @@ const useStyles = makeStyles({ */ display: 'flex', flexDirection: 'column', - overflowAnchor: 'none', maxHeight: '300VH', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/Dynamic.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/Dynamic.stories.tsx index f89975410c0e7..6705c92cf2a9b 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/Dynamic.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/Dynamic.stories.tsx @@ -13,7 +13,6 @@ const useStyles = makeStyles({ container: { display: 'flex', flexDirection: 'column', - overflowAnchor: 'none', overflowY: 'auto', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/Horizontal.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/Horizontal.stories.tsx index 9b0539346f338..16edbe43f39f4 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/Horizontal.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/Horizontal.stories.tsx @@ -6,7 +6,6 @@ const useStyles = makeStyles({ container: { display: 'flex', flexDirection: 'row', - overflowAnchor: 'none', overflowY: 'auto', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/MultiUnbounded.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/MultiUnbounded.stories.tsx index 53bab4dffe408..e6bf79745fd88 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/MultiUnbounded.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/MultiUnbounded.stories.tsx @@ -12,7 +12,6 @@ const useStyles = makeStyles({ */ display: 'flex', flexDirection: 'column', - overflowAnchor: 'none', maxHeight: '300VH', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/RTL.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/RTL.stories.tsx index 9f6d296753b31..dcb16f951cb12 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/RTL.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/RTL.stories.tsx @@ -6,7 +6,6 @@ const useStyles = makeStyles({ container: { display: 'flex', flexDirection: 'row', - overflowAnchor: 'none', overflowY: 'auto', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/Reversed.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/Reversed.stories.tsx index a774d23f4321c..109f2da1f82c9 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/Reversed.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/Reversed.stories.tsx @@ -6,7 +6,6 @@ const useStyles = makeStyles({ container: { display: 'flex', flexDirection: 'column-reverse', - overflowAnchor: 'none', overflowY: 'auto', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/Virtualizer/ReversedHorizontal.stories.tsx b/packages/react-components/react-virtualizer/stories/Virtualizer/ReversedHorizontal.stories.tsx index 8d0ca6180070d..bdb10df418cf6 100644 --- a/packages/react-components/react-virtualizer/stories/Virtualizer/ReversedHorizontal.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/Virtualizer/ReversedHorizontal.stories.tsx @@ -6,7 +6,6 @@ const useStyles = makeStyles({ container: { display: 'flex', flexDirection: 'row-reverse', - overflowAnchor: 'none', overflowY: 'auto', width: '100%', height: '100%', diff --git a/packages/react-components/react-virtualizer/stories/VirtualizerScrollView/SnapToAlignment.stories.tsx b/packages/react-components/react-virtualizer/stories/VirtualizerScrollView/SnapToAlignment.stories.tsx new file mode 100644 index 0000000000000..3c28373410a70 --- /dev/null +++ b/packages/react-components/react-virtualizer/stories/VirtualizerScrollView/SnapToAlignment.stories.tsx @@ -0,0 +1,57 @@ +import { Button, makeStyles, shorthands, useArrowNavigationGroup } from '@fluentui/react-components'; +import * as React from 'react'; +import { VirtualizerScrollView } from '@fluentui/react-components/unstable'; + +const useStyles = makeStyles({ + container: { + maxHeight: '300px', + width: '100%', + maxWidth: '100%', + scrollSnapType: 'x mandatory', + scrollBehavior: 'auto', + ...shorthands.padding('10px', '2px'), + ...shorthands.gap('10px'), + }, + child: { + scrollSnapAlign: 'start', + height: '100px', + width: '100px', + midWidth: '100px', + }, + button: { + width: '100%', + height: '100%', + }, +}); + +export const SnapToAlignment = () => { + const styles = useStyles(); + const childLength = 1000; + const attributes = useArrowNavigationGroup({ + axis: 'horizontal', + memorizeCurrent: true, + }); + + return ( + + {(index: number) => { + return ( +
+ +
+ ); + }} +
+ ); +}; diff --git a/packages/react-components/react-virtualizer/stories/VirtualizerScrollView/index.stories.ts b/packages/react-components/react-virtualizer/stories/VirtualizerScrollView/index.stories.ts index 456f3e7ae733f..82d353041b649 100644 --- a/packages/react-components/react-virtualizer/stories/VirtualizerScrollView/index.stories.ts +++ b/packages/react-components/react-virtualizer/stories/VirtualizerScrollView/index.stories.ts @@ -3,6 +3,7 @@ import descriptionMd from './VirtualizerScrollViewDescription.md'; export { Default } from './Default.stories'; export { ScrollTo } from './ScrollTo.stories'; +export { SnapToAlignment } from './SnapToAlignment.stories'; export default { title: 'Preview Components/VirtualizerScrollView', diff --git a/packages/react-components/react-virtualizer/stories/VirtualizerScrollViewDynamic/Default.stories.tsx b/packages/react-components/react-virtualizer/stories/VirtualizerScrollViewDynamic/Default.stories.tsx index 6c804c6c2cef6..63fff1f9724f8 100644 --- a/packages/react-components/react-virtualizer/stories/VirtualizerScrollViewDynamic/Default.stories.tsx +++ b/packages/react-components/react-virtualizer/stories/VirtualizerScrollViewDynamic/Default.stories.tsx @@ -23,7 +23,7 @@ export const Default = () => { useEffect(() => { let _totalSize = 0; for (let i = 0; i < childLength; i++) { - arraySize.current[i] = Math.random() * 150 + minHeight; + arraySize.current[i] = Math.floor(Math.random() * 150 + minHeight); _totalSize += arraySize.current[i]; } setTotalSize(_totalSize);