Private
Public Access
1
0

feat: Fluent UI Outlook Lite + connections mockup

This commit is contained in:
2026-04-14 18:52:25 +00:00
parent 1199eff6c3
commit dfa4010406
34820 changed files with 1003813 additions and 205 deletions

View File

@@ -0,0 +1,18 @@
'use client';
import * as React from 'react';
import { useVirtualizerStyles_unstable } from './useVirtualizerStyles.styles';
import { useVirtualizer_unstable } from './useVirtualizer';
import { renderVirtualizer_unstable } from './renderVirtualizer';
import { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';
/**
* Virtualizer pseudo-component, this functional wrapper
* provides a simple interface for reducing the total number
* of elements rendered at one time in large lists.
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/ export const Virtualizer = (props)=>{
const state = useVirtualizer_unstable(props);
useVirtualizerStyles_unstable(state);
useCustomStyleHook_unstable('useVirtualizerStyles_unstable')(state);
return renderVirtualizer_unstable(state);
};
Virtualizer.displayName = 'Virtualizer';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Virtualizer/Virtualizer.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport type { VirtualizerProps } from './Virtualizer.types';\nimport { useVirtualizerStyles_unstable } from './useVirtualizerStyles.styles';\nimport { useVirtualizer_unstable } from './useVirtualizer';\nimport { renderVirtualizer_unstable } from './renderVirtualizer';\nimport { useCustomStyleHook_unstable } from '@fluentui/react-shared-contexts';\n\n/**\n * Virtualizer pseudo-component, this functional wrapper\n * provides a simple interface for reducing the total number\n * of elements rendered at one time in large lists.\n * @deprecated migrated to \\@fluentui\\-contrib/react\\-virtualizer for stable release.\n */\nexport const Virtualizer: React.FC<VirtualizerProps> = (props: VirtualizerProps) => {\n const state = useVirtualizer_unstable(props);\n useVirtualizerStyles_unstable(state);\n useCustomStyleHook_unstable('useVirtualizerStyles_unstable')(state);\n\n return renderVirtualizer_unstable(state);\n};\n\nVirtualizer.displayName = 'Virtualizer';\n"],"names":["React","useVirtualizerStyles_unstable","useVirtualizer_unstable","renderVirtualizer_unstable","useCustomStyleHook_unstable","Virtualizer","props","state","displayName"],"mappings":"AAAA;AAEA,YAAYA,WAAW,QAAQ;AAE/B,SAASC,6BAA6B,QAAQ,gCAAgC;AAC9E,SAASC,uBAAuB,QAAQ,mBAAmB;AAC3D,SAASC,0BAA0B,QAAQ,sBAAsB;AACjE,SAASC,2BAA2B,QAAQ,kCAAkC;AAE9E;;;;;CAKC,GACD,OAAO,MAAMC,cAA0C,CAACC;IACtD,MAAMC,QAAQL,wBAAwBI;IACtCL,8BAA8BM;IAC9BH,4BAA4B,iCAAiCG;IAE7D,OAAOJ,2BAA2BI;AACpC,EAAE;AAEFF,YAAYG,WAAW,GAAG"}

View File

@@ -0,0 +1 @@
import * as React from 'react';

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
export { Virtualizer } from './Virtualizer';
export { useVirtualizer_unstable } from './useVirtualizer';
export { renderVirtualizerChildPlaceholder, renderVirtualizer_unstable } from './renderVirtualizer';
export { useVirtualizerStyles_unstable, virtualizerClassNames } from './useVirtualizerStyles.styles';

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Virtualizer/index.ts"],"sourcesContent":["export { Virtualizer } from './Virtualizer';\nexport type {\n VirtualizerChildRenderFunction,\n VirtualizerConfigProps,\n VirtualizerConfigState,\n VirtualizerDataRef,\n VirtualizerProps,\n VirtualizerSlots,\n VirtualizerState,\n} from './Virtualizer.types';\nexport { useVirtualizer_unstable } from './useVirtualizer';\nexport { renderVirtualizerChildPlaceholder, renderVirtualizer_unstable } from './renderVirtualizer';\nexport { useVirtualizerStyles_unstable, virtualizerClassNames } from './useVirtualizerStyles.styles';\n"],"names":["Virtualizer","useVirtualizer_unstable","renderVirtualizerChildPlaceholder","renderVirtualizer_unstable","useVirtualizerStyles_unstable","virtualizerClassNames"],"mappings":"AAAA,SAASA,WAAW,QAAQ,gBAAgB;AAU5C,SAASC,uBAAuB,QAAQ,mBAAmB;AAC3D,SAASC,iCAAiC,EAAEC,0BAA0B,QAAQ,sBAAsB;AACpG,SAASC,6BAA6B,EAAEC,qBAAqB,QAAQ,gCAAgC"}

View File

@@ -0,0 +1,27 @@
import { jsx as _jsx, jsxs as _jsxs } from "@fluentui/react-jsx-runtime/jsx-runtime";
import * as React from 'react';
import { assertSlots } from '@fluentui/react-utilities';
/**
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/ export const renderVirtualizer_unstable = (state)=>{
assertSlots(state);
return /*#__PURE__*/ _jsxs(React.Fragment, {
children: [
/*#__PURE__*/ _jsx(state.beforeContainer, {
children: /*#__PURE__*/ _jsx(state.before, {})
}),
state.virtualizedChildren,
/*#__PURE__*/ _jsx(state.afterContainer, {
children: /*#__PURE__*/ _jsx(state.after, {})
})
]
});
};
/**
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/ export const renderVirtualizerChildPlaceholder = (child, index)=>{
return /*#__PURE__*/ _jsx(React.Suspense, {
fallback: null,
children: child
}, `fui-virtualizer-placeholder-${index}`);
};

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../src/components/Virtualizer/renderVirtualizer.tsx"],"sourcesContent":["/** @jsxRuntime automatic */\n/** @jsxImportSource @fluentui/react-jsx-runtime */\n\nimport * as React from 'react';\nimport type { VirtualizerSlots, VirtualizerState } from './Virtualizer.types';\n\nimport { assertSlots } from '@fluentui/react-utilities';\n\n/**\n * @deprecated migrated to \\@fluentui\\-contrib/react\\-virtualizer for stable release.\n */\nexport const renderVirtualizer_unstable = (state: VirtualizerState): React.ReactElement => {\n assertSlots<VirtualizerSlots>(state);\n return (\n <React.Fragment>\n {/* The 'before' bookend to hold items in place and detect scroll previous */}\n <state.beforeContainer>\n <state.before />\n </state.beforeContainer>\n {/* The reduced list of non-virtualized children to be rendered */}\n {state.virtualizedChildren}\n {/* The 'after' bookend to hold items in place and detect scroll next */}\n <state.afterContainer>\n <state.after />\n </state.afterContainer>\n </React.Fragment>\n );\n};\n/**\n * @deprecated migrated to \\@fluentui\\-contrib/react\\-virtualizer for stable release.\n */\nexport const renderVirtualizerChildPlaceholder = (child: React.ReactNode, index: number): React.ReactElement => {\n return (\n <React.Suspense key={`fui-virtualizer-placeholder-${index}`} fallback={null}>\n {child}\n </React.Suspense>\n );\n};\n"],"names":["React","assertSlots","renderVirtualizer_unstable","state","Fragment","beforeContainer","before","virtualizedChildren","afterContainer","after","renderVirtualizerChildPlaceholder","child","index","Suspense","fallback"],"mappings":"AAAA,0BAA0B,GAC1B,iDAAiD;AAEjD,YAAYA,WAAW,QAAQ;AAG/B,SAASC,WAAW,QAAQ,4BAA4B;AAExD;;CAEC,GACD,OAAO,MAAMC,6BAA6B,CAACC;IACzCF,YAA8BE;IAC9B,qBACE,MAACH,MAAMI,QAAQ;;0BAEb,KAACD,MAAME,eAAe;0BACpB,cAAA,KAACF,MAAMG,MAAM;;YAGdH,MAAMI,mBAAmB;0BAE1B,KAACJ,MAAMK,cAAc;0BACnB,cAAA,KAACL,MAAMM,KAAK;;;;AAIpB,EAAE;AACF;;CAEC,GACD,OAAO,MAAMC,oCAAoC,CAACC,OAAwBC;IACxE,qBACE,KAACZ,MAAMa,QAAQ;QAA8CC,UAAU;kBACpEH;OADkB,CAAC,4BAA4B,EAAEC,OAAO;AAI/D,EAAE"}

View File

@@ -0,0 +1,535 @@
'use client';
import * as React from 'react';
import { useIntersectionObserver } from '../../hooks/useIntersectionObserver';
import { useVirtualizerContextState_unstable } from '../../Utilities';
import { slot, useTimeout } from '@fluentui/react-utilities';
import { flushSync } from 'react-dom';
/**
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/ export function useVirtualizer_unstable(props) {
'use no memo';
const { itemSize, numItems, virtualizerLength, children: renderChild, getItemSize, bufferItems = Math.round(virtualizerLength / 4.0), bufferSize = Math.floor(bufferItems / 2.0) * itemSize, axis = 'vertical', reversed = false, virtualizerContext, onRenderedFlaggedIndex, imperativeVirtualizerRef, containerSizeRef, scrollViewRef, enableScrollLoad, updateScrollPosition, gap = 0 } = props;
/* The context is optional, it's useful for injecting additional index logic, or performing uniform state updates*/ const _virtualizerContext = useVirtualizerContextState_unstable(virtualizerContext);
// We use this ref as a constant source to access the virtualizer's state imperatively
const actualIndexRef = React.useRef(_virtualizerContext.contextIndex);
const flaggedIndex = React.useRef(null);
const actualIndex = _virtualizerContext.contextIndex;
// Just in case our ref gets out of date vs the context during a re-render
if (_virtualizerContext.contextIndex !== actualIndexRef.current) {
actualIndexRef.current = _virtualizerContext.contextIndex;
}
const setActualIndex = React.useCallback((index)=>{
actualIndexRef.current = index;
_virtualizerContext.setContextIndex(index);
}, [
_virtualizerContext
]);
// Store ref to before padding element
const beforeElementRef = React.useRef(null);
// Store ref to before padding element
const afterElementRef = React.useRef(null);
// We need to store an array to track dynamic sizes, we can use this to incrementally update changes
const childSizes = React.useRef(new Array(getItemSize ? numItems : 0));
/* We keep track of the progressive sizing/placement down the list,
this helps us skip re-calculations unless children/size changes */ const childProgressiveSizes = React.useRef(new Array(getItemSize ? numItems : 0));
if (virtualizerContext === null || virtualizerContext === void 0 ? void 0 : virtualizerContext.childProgressiveSizes) {
virtualizerContext.childProgressiveSizes.current = childProgressiveSizes.current;
}
// The internal tracking REF for child array (updates often).
const childArray = React.useRef(new Array(virtualizerLength));
const populateSizeArrays = ()=>{
if (!getItemSize) {
// Static sizes, never mind!
return;
}
if (numItems !== childSizes.current.length) {
childSizes.current = new Array(numItems);
}
if (numItems !== childProgressiveSizes.current.length) {
childProgressiveSizes.current = new Array(numItems);
if (virtualizerContext === null || virtualizerContext === void 0 ? void 0 : virtualizerContext.childProgressiveSizes) {
virtualizerContext.childProgressiveSizes.current = childProgressiveSizes.current;
}
}
for(let index = 0; index < numItems; index++){
const _gap = index < numItems - 1 ? gap : 0;
childSizes.current[index] = getItemSize(index) + _gap;
if (index === 0) {
childProgressiveSizes.current[index] = childSizes.current[index];
} else {
childProgressiveSizes.current[index] = childProgressiveSizes.current[index - 1] + childSizes.current[index];
}
}
};
const [isScrolling, setIsScrolling] = React.useState(false);
const [setScrollTimer, clearScrollTimer] = useTimeout();
const scrollCounter = React.useRef(0);
const initializeScrollingTimer = React.useCallback(()=>{
if (!enableScrollLoad) {
// Disabled by default for reduction of render callbacks
setIsScrolling(false);
clearScrollTimer();
return;
}
/*
* This can be considered the 'velocity' required to start 'isScrolling'
* INIT_SCROLL_FLAG_REQ: Number of renders required to activate isScrolling
* INIT_SCROLL_FLAG_DELAY: Amount of time (ms) before current number of renders is reset
* - Maybe we should let users customize these in the future.
*/ const INIT_SCROLL_FLAG_REQ = 10;
const INIT_SCROLL_FLAG_DELAY = 100;
scrollCounter.current++;
if (scrollCounter.current >= INIT_SCROLL_FLAG_REQ) {
setIsScrolling(true);
}
clearScrollTimer();
setScrollTimer(()=>{
setIsScrolling(false);
scrollCounter.current = 0;
}, INIT_SCROLL_FLAG_DELAY);
}, [
clearScrollTimer,
setScrollTimer,
enableScrollLoad
]);
React.useEffect(()=>{
initializeScrollingTimer();
}, [
actualIndex,
initializeScrollingTimer
]);
const updateChildRows = React.useCallback((newIndex)=>{
if (numItems === 0) {
/* Nothing to virtualize */ return;
}
/*
We reset the array every time to ensure children are re-rendered
This function should only be called when update is nessecary
*/ childArray.current = new Array(virtualizerLength);
const _actualIndex = Math.max(newIndex, 0);
const end = Math.min(_actualIndex + virtualizerLength, numItems);
for(let i = _actualIndex; i < end; i++){
childArray.current[i - _actualIndex] = renderChild(i, isScrolling);
}
}, [
isScrolling,
numItems,
renderChild,
virtualizerLength
]);
const updateCurrentItemSizes = React.useCallback((newIndex)=>{
if (!getItemSize) {
// Static sizes, not required.
return;
}
// We should always call our size function on index change (only for the items that will be rendered)
// This ensures we request the latest data for incoming items in case sizing has changed.
const endIndex = Math.min(newIndex + virtualizerLength, numItems);
const startIndex = Math.max(newIndex, 0);
let didUpdate = false;
for(let i = startIndex; i < endIndex; i++){
const _gap = i < numItems - 1 ? gap : 0;
const newSize = getItemSize(i) + _gap;
if (newSize !== childSizes.current[i]) {
childSizes.current[i] = newSize;
didUpdate = true;
}
}
if (didUpdate) {
// Update our progressive size array
for(let i = startIndex; i < numItems; i++){
const prevSize = i > 0 ? childProgressiveSizes.current[i - 1] : 0;
childProgressiveSizes.current[i] = prevSize + childSizes.current[i];
}
}
}, [
getItemSize,
numItems,
virtualizerLength,
gap
]);
const batchUpdateNewIndex = React.useCallback((index)=>{
// Local updates
updateChildRows(index);
updateCurrentItemSizes(index);
// State setters
setActualIndex(index);
}, [
setActualIndex,
updateChildRows,
updateCurrentItemSizes
]);
const findIndexRecursive = React.useCallback((scrollPos, lowIndex, highIndex)=>{
if (lowIndex > highIndex) {
// We shouldn't get here - but no-op the index if we do.
return actualIndex;
}
const midpoint = Math.floor((lowIndex + highIndex) / 2);
const iBefore = Math.max(midpoint - 1, 0);
const iAfter = Math.min(midpoint + 1, childProgressiveSizes.current.length - 1);
const indexValue = childProgressiveSizes.current[midpoint];
const afterIndexValue = childProgressiveSizes.current[iAfter];
const beforeIndexValue = childProgressiveSizes.current[iBefore];
if (scrollPos <= afterIndexValue && scrollPos >= beforeIndexValue) {
/* We've found our index - if we are exactly matching before/after index that's ok,
better to reduce checks if it's right on the boundary. */ return midpoint;
}
if (indexValue > scrollPos) {
return findIndexRecursive(scrollPos, lowIndex, midpoint - 1);
} else {
return findIndexRecursive(scrollPos, midpoint + 1, highIndex);
}
}, [
actualIndex
]);
const getIndexFromSizeArray = React.useCallback((scrollPos)=>{
/* Quick searches our progressive height array */ if (scrollPos === 0 || childProgressiveSizes.current.length === 0 || scrollPos <= childProgressiveSizes.current[0]) {
// Check start
return 0;
}
if (scrollPos >= childProgressiveSizes.current[childProgressiveSizes.current.length - 1]) {
// Check end
return childProgressiveSizes.current.length - 1;
}
return findIndexRecursive(scrollPos, 0, childProgressiveSizes.current.length - 1);
}, [
findIndexRecursive
]);
const getIndexFromScrollPosition = React.useCallback((scrollPos)=>{
if (!getItemSize) {
return Math.round(scrollPos / (itemSize + gap));
}
return getIndexFromSizeArray(scrollPos);
}, [
getIndexFromSizeArray,
getItemSize,
itemSize,
gap
]);
const calculateTotalSize = React.useCallback(()=>{
if (!getItemSize) {
return (itemSize + gap) * numItems;
}
// Time for custom size calcs
return childProgressiveSizes.current[numItems - 1];
}, [
getItemSize,
itemSize,
numItems,
gap
]);
const calculateBefore = React.useCallback(()=>{
const currentIndex = Math.min(actualIndex, numItems - 1);
if (!getItemSize) {
// The missing items from before virtualization starts height
return currentIndex * (itemSize + gap);
}
if (currentIndex <= 0) {
return 0;
}
// Time for custom size calcs
return childProgressiveSizes.current[currentIndex - 1];
}, [
actualIndex,
getItemSize,
itemSize,
numItems,
gap
]);
const calculateAfter = React.useCallback(()=>{
if (numItems === 0 || actualIndex + virtualizerLength >= numItems) {
return 0;
}
const lastItemIndex = Math.min(actualIndex + virtualizerLength, numItems);
if (!getItemSize) {
// The missing items from after virtualization ends height
const remainingItems = numItems - lastItemIndex;
return remainingItems * (itemSize + gap) - gap;
}
// Time for custom size calcs
return childProgressiveSizes.current[numItems - 1] - childProgressiveSizes.current[lastItemIndex - 1];
}, [
actualIndex,
getItemSize,
itemSize,
numItems,
virtualizerLength,
gap
]);
// We store the number of items since last render, we will allow an update if the number of items changes
const previousNumItems = React.useRef(numItems);
// Observe intersections of virtualized components
const { setObserverList } = useIntersectionObserver(React.useCallback(// TODO: exclude types from this lint rule: https://github.com/microsoft/fluentui/issues/31286
(entries, observer)=>{
/* Sanity check - do we even need virtualization? */ if (virtualizerLength > numItems) {
if (actualIndex !== 0) {
batchUpdateNewIndex(0);
}
// No-op
return;
}
if (entries.length === 0) {
// No entries found, return.
return;
}
// Find the latest entry that is intersecting
const sortedEntries = entries.sort((entry1, entry2)=>entry2.time - entry1.time);
const latestEntry = sortedEntries.find((entry)=>{
return entry.isIntersecting;
});
if (!latestEntry) {
return;
}
// We have to be sure our item sizes are up to date with current indexed ref before calculation
// Check if we still need
updateCurrentItemSizes(actualIndexRef.current);
const calculateOverBuffer = ()=>{
/**
* We avoid using the scroll ref scrollTop, it may be incorrect
* as virtualization may exist within a scroll view with other elements
* The benefit of using IO is that we can detect relative scrolls,
* so any items can be placed around the virtualizer in the scroll view
*/ let measurementPos = 0;
if (latestEntry.target === afterElementRef.current) {
// Get after buffers position
measurementPos = calculateTotalSize() - calculateAfter();
// Get exact intersection position based on overflow size (how far into IO did we scroll?)
const overflowAmount = axis === 'vertical' ? latestEntry.intersectionRect.height : latestEntry.intersectionRect.width;
// Add to original after position
measurementPos += overflowAmount;
// Ignore buffer size (IO offset)
measurementPos -= bufferSize;
var _containerSizeRef_current;
// we hit the after buffer and detected the end of view, we need to find the start index.
measurementPos -= (_containerSizeRef_current = containerSizeRef.current) !== null && _containerSizeRef_current !== void 0 ? _containerSizeRef_current : 0;
// Calculate how far past the window bounds we are (this will be zero if IO is within window)
const hOverflow = latestEntry.boundingClientRect.top - latestEntry.intersectionRect.top;
const hOverflowReversed = latestEntry.boundingClientRect.bottom - latestEntry.intersectionRect.bottom;
const wOverflow = latestEntry.boundingClientRect.left - latestEntry.intersectionRect.left;
const wOverflowReversed = latestEntry.boundingClientRect.right - latestEntry.intersectionRect.right;
const widthOverflow = reversed ? wOverflowReversed : wOverflow;
const heightOverflow = reversed ? hOverflowReversed : hOverflow;
const additionalOverflow = axis === 'vertical' ? heightOverflow : widthOverflow;
if (reversed) {
measurementPos += additionalOverflow;
} else {
measurementPos -= additionalOverflow;
}
} else if (latestEntry.target === beforeElementRef.current) {
// Get before buffers position
measurementPos = calculateBefore();
// Get exact intersection position based on overflow size (how far into window did we scroll IO?)
const overflowAmount = axis === 'vertical' ? latestEntry.intersectionRect.height : latestEntry.intersectionRect.width;
// Minus from original before position
measurementPos -= overflowAmount;
// Ignore buffer size (IO offset)
measurementPos += bufferSize;
// Calculate how far past the window bounds we are (this will be zero if IO is within window)
const hOverflow = latestEntry.boundingClientRect.bottom - latestEntry.intersectionRect.bottom;
const hOverflowReversed = latestEntry.boundingClientRect.top - latestEntry.intersectionRect.top;
const wOverflow = latestEntry.boundingClientRect.right - latestEntry.intersectionRect.right;
const wOverflowReversed = latestEntry.boundingClientRect.left - latestEntry.intersectionRect.left;
const widthOverflow = reversed ? wOverflowReversed : wOverflow;
const heightOverflow = reversed ? hOverflowReversed : hOverflow;
const additionalOverflow = axis === 'vertical' ? heightOverflow : widthOverflow;
if (reversed) {
measurementPos += additionalOverflow;
} else {
measurementPos -= additionalOverflow;
}
}
return measurementPos;
};
// Get exact relative 'scrollTop' via IO values
const measurementPos = calculateOverBuffer();
const maxIndex = Math.max(numItems - virtualizerLength, 0);
const startIndex = getIndexFromScrollPosition(measurementPos) - bufferItems;
// Safety limits
const newStartIndex = Math.min(Math.max(startIndex, 0), maxIndex);
flushSync(()=>{
// Callback to allow measure functions to check virtualizer length
if (previousNumItems.current === numItems && newStartIndex + virtualizerLength >= numItems && actualIndex + virtualizerLength >= numItems) {
// We've already hit the end, no need to update state.
return;
}
// We should ensure we update virtualizer calculations if the length changes
previousNumItems.current = virtualizerLength;
updateScrollPosition === null || updateScrollPosition === void 0 ? void 0 : updateScrollPosition(measurementPos);
if (actualIndex !== newStartIndex) {
batchUpdateNewIndex(newStartIndex);
}
});
}, [
actualIndex,
virtualizerLength,
axis,
reversed,
numItems,
bufferSize,
bufferItems,
containerSizeRef,
updateScrollPosition,
batchUpdateNewIndex,
calculateAfter,
calculateBefore,
calculateTotalSize,
getIndexFromScrollPosition,
updateCurrentItemSizes
]), {
root: scrollViewRef ? scrollViewRef === null || scrollViewRef === void 0 ? void 0 : scrollViewRef.current : null,
rootMargin: '0px',
threshold: 0
});
const setBeforeRef = React.useCallback((element)=>{
if (!element || beforeElementRef.current === element) {
return;
}
beforeElementRef.current = element;
const newList = [];
newList.push(beforeElementRef.current);
if (afterElementRef.current) {
newList.push(afterElementRef.current);
}
// Ensure we update array if before element changed
setObserverList(newList);
}, [
setObserverList
]);
const setAfterRef = React.useCallback((element)=>{
if (!element || afterElementRef.current === element) {
return;
}
afterElementRef.current = element;
const newList = [];
if (beforeElementRef.current) {
newList.push(beforeElementRef.current);
}
newList.push(afterElementRef.current);
// Ensure we update array if after element changed
setObserverList(newList);
}, [
setObserverList
]);
// Initialize the size array before first render.
const hasInitialized = React.useRef(false);
const initializeSizeArray = ()=>{
if (hasInitialized.current === false) {
hasInitialized.current = true;
populateSizeArrays();
}
};
React.useImperativeHandle(imperativeVirtualizerRef, ()=>{
return {
progressiveSizes: childProgressiveSizes,
nodeSizes: childSizes,
setFlaggedIndex: (index)=>flaggedIndex.current = index,
currentIndex: actualIndexRef
};
}, [
childProgressiveSizes,
childSizes
]);
// Initialization on mount - update array index to 0 (ready state).
// Only fire on mount (no deps).
React.useEffect(()=>{
if (actualIndex < 0) {
batchUpdateNewIndex(0);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
/*
* forceUpdate:
* We only want to trigger this when child render or scroll loading changes,
* it will force re-render all children elements
*/ const forceUpdate = React.useReducer(()=>({}), {})[1];
// If the user passes in an updated renderChild function - update current children
React.useEffect(()=>{
if (actualIndex >= 0) {
updateChildRows(actualIndex);
forceUpdate();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
renderChild,
isScrolling
]);
React.useEffect(()=>{
// Ensure we repopulate if getItemSize callback changes
populateSizeArrays();
// We only run this effect on getItemSize change (recalc dynamic sizes)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
getItemSize,
gap
]);
// Effect to check flag index on updates
React.useEffect(()=>{
if (!onRenderedFlaggedIndex || flaggedIndex.current === null) {
return;
}
if (actualIndex <= flaggedIndex.current && actualIndex + virtualizerLength >= flaggedIndex.current) {
onRenderedFlaggedIndex(flaggedIndex.current);
flaggedIndex.current = null;
}
}, [
actualIndex,
onRenderedFlaggedIndex,
virtualizerLength
]);
// Ensure we have run through and updated the whole size list array at least once.
initializeSizeArray();
if (getItemSize && (numItems !== childSizes.current.length || numItems !== childProgressiveSizes.current.length)) {
// Child length mismatch, repopulate size arrays.
populateSizeArrays();
}
// Ensure we recalc if virtualizer length changes
const maxCompare = Math.min(virtualizerLength, numItems);
if (childArray.current.length !== maxCompare && actualIndex + childArray.current.length < numItems) {
updateChildRows(actualIndex);
}
const isFullyInitialized = hasInitialized.current && actualIndex >= 0;
return {
components: {
before: 'div',
after: 'div',
beforeContainer: 'div',
afterContainer: 'div'
},
virtualizedChildren: childArray.current,
before: slot.always(props.before, {
defaultProps: {
ref: setBeforeRef,
role: 'none'
},
elementType: 'div'
}),
after: slot.always(props.after, {
defaultProps: {
ref: setAfterRef,
role: 'none'
},
elementType: 'div'
}),
beforeContainer: slot.always(props.beforeContainer, {
defaultProps: {
role: 'none'
},
elementType: 'div'
}),
afterContainer: slot.always(props.afterContainer, {
defaultProps: {
role: 'none'
},
elementType: 'div'
}),
beforeBufferHeight: isFullyInitialized ? calculateBefore() : 0,
afterBufferHeight: isFullyInitialized ? calculateAfter() : 0,
totalVirtualizerHeight: isFullyInitialized ? calculateTotalSize() : virtualizerLength * itemSize,
virtualizerStartIndex: actualIndex,
axis,
bufferSize,
reversed,
childSizes,
childProgressiveSizes
};
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,115 @@
'use client';
import { __styles, mergeClasses } from '@griffel/react';
const virtualizerClassName = 'fui-Virtualizer';
/**
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/
export const virtualizerClassNames = {
before: `${virtualizerClassName}__before`,
beforeContainer: `${virtualizerClassName}__beforeContainer`,
after: `${virtualizerClassName}__after`,
afterContainer: `${virtualizerClassName}__afterContainer`
};
const useStyles = /*#__PURE__*/__styles({
base: {
mc9l5x: "ftgm304",
Bkecrkj: "f1aehjj5"
},
relative: {
qhf8xq: "f10pi13n"
},
horizontal: {
sshi5w: "fan4evk"
},
vertical: {
Bf4jedk: "f11qra4b"
}
}, {
d: [".ftgm304{display:block;}", ".f1aehjj5{pointer-events:none;}", ".f10pi13n{position:relative;}", ".fan4evk{min-height:100%;}", ".f11qra4b{min-width:100%;}"]
});
/**
* Apply styling to the Virtualizer states
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/
export const useVirtualizerStyles_unstable = state => {
'use no memo';
const styles = useStyles();
const {
reversed,
axis,
beforeBufferHeight,
afterBufferHeight,
bufferSize
} = state;
const horizontal = axis === 'horizontal';
state.before.className = mergeClasses(virtualizerClassNames.before, styles.base, styles.relative, horizontal ? styles.horizontal : styles.vertical, state.before.className);
state.after.className = mergeClasses(virtualizerClassNames.after, styles.base, styles.relative, horizontal ? styles.horizontal : styles.vertical, state.after.className);
state.beforeContainer.className = mergeClasses(virtualizerClassNames.beforeContainer, styles.base, horizontal ? styles.horizontal : styles.vertical, state.beforeContainer.className);
state.afterContainer.className = mergeClasses(virtualizerClassNames.afterContainer, styles.base, horizontal ? styles.horizontal : styles.vertical, state.afterContainer.className);
const beforeHeightPx = beforeBufferHeight + 'px';
const afterHeightPx = afterBufferHeight + 'px';
const beforeBufferHeightPx = beforeBufferHeight + bufferSize + 'px';
const afterBufferHeightPx = afterBufferHeight + bufferSize + 'px';
const bufferPx = bufferSize + 'px';
const beforeBuffer = {
// Column
...(!reversed && !horizontal && {
marginBottom: `-${bufferPx}`
}),
// Column-Reverse
...(reversed && !horizontal && {
marginTop: `-${bufferPx}`
}),
// Row
...(!reversed && horizontal && {
marginRight: `-${bufferPx}`
}),
// Row-Reverse
...(reversed && horizontal && {
marginLeft: `-${bufferPx}`
})
};
const afterBuffer = {
// Column
...(!reversed && !horizontal && {
marginTop: `-${bufferPx}`
}),
// Column-Reverse
...(reversed && !horizontal && {
marginBottom: `-${bufferPx}`
}),
// Row
...(!reversed && horizontal && {
marginLeft: `-${bufferPx}`
}),
// Row-Reverse
...(reversed && horizontal && {
marginRight: `-${bufferPx}`
})
};
state.before.style = {
height: horizontal ? '100%' : beforeBufferHeightPx,
width: horizontal ? beforeBufferHeightPx : '100%',
...beforeBuffer,
...state.before.style
};
state.beforeContainer.style = {
height: horizontal ? 'auto' : beforeHeightPx,
width: horizontal ? beforeHeightPx : 'auto',
...state.beforeContainer.style
};
state.after.style = {
height: horizontal ? '100%' : afterBufferHeightPx,
width: horizontal ? afterBufferHeightPx : '100%',
...afterBuffer,
...state.after.style
};
state.afterContainer.style = {
height: horizontal ? 'auto' : afterHeightPx,
width: horizontal ? afterHeightPx : 'auto',
...state.afterContainer.style
};
return state;
};

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,103 @@
'use client';
import { makeStyles, mergeClasses } from '@griffel/react';
const virtualizerClassName = 'fui-Virtualizer';
/**
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/ export const virtualizerClassNames = {
before: `${virtualizerClassName}__before`,
beforeContainer: `${virtualizerClassName}__beforeContainer`,
after: `${virtualizerClassName}__after`,
afterContainer: `${virtualizerClassName}__afterContainer`
};
const useStyles = makeStyles({
base: {
display: 'block',
pointerEvents: 'none'
},
relative: {
position: 'relative'
},
horizontal: {
minHeight: '100%'
},
vertical: {
minWidth: '100%'
}
});
/**
* Apply styling to the Virtualizer states
* @deprecated migrated to \@fluentui\-contrib/react\-virtualizer for stable release.
*/ export const useVirtualizerStyles_unstable = (state)=>{
'use no memo';
const styles = useStyles();
const { reversed, axis, beforeBufferHeight, afterBufferHeight, bufferSize } = state;
const horizontal = axis === 'horizontal';
state.before.className = mergeClasses(virtualizerClassNames.before, styles.base, styles.relative, horizontal ? styles.horizontal : styles.vertical, state.before.className);
state.after.className = mergeClasses(virtualizerClassNames.after, styles.base, styles.relative, horizontal ? styles.horizontal : styles.vertical, state.after.className);
state.beforeContainer.className = mergeClasses(virtualizerClassNames.beforeContainer, styles.base, horizontal ? styles.horizontal : styles.vertical, state.beforeContainer.className);
state.afterContainer.className = mergeClasses(virtualizerClassNames.afterContainer, styles.base, horizontal ? styles.horizontal : styles.vertical, state.afterContainer.className);
const beforeHeightPx = beforeBufferHeight + 'px';
const afterHeightPx = afterBufferHeight + 'px';
const beforeBufferHeightPx = beforeBufferHeight + bufferSize + 'px';
const afterBufferHeightPx = afterBufferHeight + bufferSize + 'px';
const bufferPx = bufferSize + 'px';
const beforeBuffer = {
// Column
...!reversed && !horizontal && {
marginBottom: `-${bufferPx}`
},
// Column-Reverse
...reversed && !horizontal && {
marginTop: `-${bufferPx}`
},
// Row
...!reversed && horizontal && {
marginRight: `-${bufferPx}`
},
// Row-Reverse
...reversed && horizontal && {
marginLeft: `-${bufferPx}`
}
};
const afterBuffer = {
// Column
...!reversed && !horizontal && {
marginTop: `-${bufferPx}`
},
// Column-Reverse
...reversed && !horizontal && {
marginBottom: `-${bufferPx}`
},
// Row
...!reversed && horizontal && {
marginLeft: `-${bufferPx}`
},
// Row-Reverse
...reversed && horizontal && {
marginRight: `-${bufferPx}`
}
};
state.before.style = {
height: horizontal ? '100%' : beforeBufferHeightPx,
width: horizontal ? beforeBufferHeightPx : '100%',
...beforeBuffer,
...state.before.style
};
state.beforeContainer.style = {
height: horizontal ? 'auto' : beforeHeightPx,
width: horizontal ? beforeHeightPx : 'auto',
...state.beforeContainer.style
};
state.after.style = {
height: horizontal ? '100%' : afterBufferHeightPx,
width: horizontal ? afterBufferHeightPx : '100%',
...afterBuffer,
...state.after.style
};
state.afterContainer.style = {
height: horizontal ? 'auto' : afterHeightPx,
width: horizontal ? afterHeightPx : 'auto',
...state.afterContainer.style
};
return state;
};

File diff suppressed because one or more lines are too long