DocSpace-buildtools/packages/components/drop-down/VirtualList.tsx
2023-03-30 18:36:17 +05:00

144 lines
3.4 KiB
TypeScript

import React, {
NamedExoticComponent,
ReactElement,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
import { VariableSizeList } from "react-window";
import Scrollbar from "@docspace/components/scrollbar";
import CustomScrollbarsVirtualList from "../scrollbar/custom-scrollbars-virtual-list";
type VirtualListProps = {
width: number;
theme: unknown;
isOpen: boolean;
itemCount: number;
maxHeight: number;
calculatedHeight: number;
isNoFixedHeightOptions: boolean;
cleanChildren: ReactElement[];
children: ReactElement[];
Row: NamedExoticComponent<object>;
enableKeyboardEvents: boolean;
getItemSize: (index: number) => number;
};
function VirtualList({
Row,
width,
theme,
isOpen,
children,
itemCount,
maxHeight,
cleanChildren,
calculatedHeight,
isNoFixedHeightOptions,
getItemSize,
enableKeyboardEvents,
}: VirtualListProps) {
const ref = useRef<VariableSizeList>(null);
const activeIndex = useMemo(() => {
let foundIndex = -1;
React.Children.forEach(cleanChildren, (child, index) => {
if (child.props.disabled) foundIndex = index;
});
return foundIndex;
}, [cleanChildren]);
const [currentIndex, setCurrentIndex] = useState(activeIndex);
const currentIndexRef = useRef<number>(activeIndex);
useEffect(() => {
if (isOpen && maxHeight && enableKeyboardEvents) {
window.addEventListener("keydown", onKeyDown);
}
return () => {
window.removeEventListener("keydown", onKeyDown);
if (itemCount > 0 && ref.current) {
setCurrentIndex(activeIndex);
currentIndexRef.current = activeIndex;
ref.current.scrollToItem(activeIndex, "smart");
}
};
}, [isOpen, activeIndex, maxHeight, enableKeyboardEvents, children]);
const onKeyDown = useCallback(
(event: KeyboardEvent) => {
if (!ref.current || !isOpen) return;
event.preventDefault();
let index = currentIndexRef.current;
switch (event.code) {
case "ArrowDown":
index++;
break;
case "ArrowUp":
index--;
break;
case "Enter":
return children[index]?.props?.onClick();
default:
return;
}
if (index < 0 || index >= React.Children.count(children)) return;
setCurrentIndex(index);
currentIndexRef.current = index;
ref.current.scrollToItem(index, "smart");
},
[isOpen, children]
);
const handleMouseMove = useCallback((index: number) => {
if (currentIndexRef.current === index) return;
setCurrentIndex(index);
currentIndexRef.current = index;
}, []);
if (!maxHeight) return cleanChildren ? cleanChildren : children;
return (
<>
{isNoFixedHeightOptions ? (
//@ts-ignore
<Scrollbar style={{ height: maxHeight }} stype="mediumBlack">
{cleanChildren}
</Scrollbar>
) : (
<VariableSizeList
ref={ref}
width={width}
itemCount={itemCount}
itemSize={getItemSize}
height={calculatedHeight}
itemData={{
children: cleanChildren,
theme: theme,
activeIndex,
activedescendant: currentIndex,
handleMouseMove,
}}
outerElementType={CustomScrollbarsVirtualList}
>
{Row}
</VariableSizeList>
)}
</>
);
}
export default VirtualList;