Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | 29x 107x 107x 107x 107x 107x 139x 139x 52x 107x 139x 139x 139x 139x 29x 107x 107x 13x 94x | import { CARD_CONTENT_HEIGHT } from "@shared/constants";
import { ElementType, useEffect, useRef } from "react";
import { useTrail, animated, SpringValue } from "react-spring";
type TCustomAnimations = "waterfall" | "";
type ItemComponent<T> = (
data: T,
index: number,
height: SpringValue<number>,
springProps?: any,
) => JSX.Element;
type Props<T> = {
items: T[];
renderKey: (data: T, index: number) => React.Key | null | undefined;
ItemComponent: ItemComponent<T>;
config?: any;
Wrapper?: ElementType;
height?: number;
animationName?: TCustomAnimations;
};
const UnfoldListItems = <T extends object | string>({
items,
renderKey,
ItemComponent,
config,
Wrapper = animated.div,
animationName = "",
height = CARD_CONTENT_HEIGHT,
}: Props<T>) => {
const defaultConfig = getDefaultConfig(animationName, height);
const trail = useTrail(items?.length, config ? config : defaultConfig);
const renderedItemsRef = useRef<Set<React.Key>>(new Set());
useEffect(() => {
// Add newly rendered items to the set
items.forEach((item, index) => {
const key = renderKey(item, index);
if (key && !renderedItemsRef.current.has(key)) {
renderedItemsRef.current.add(key);
}
});
}, [items, renderKey]);
return (
<>
{trail?.map(({ height, ...rest }, index) => {
const data = items[index];
const key = renderKey(data, index);
const isRendered = renderedItemsRef.current.has(key || index);
return (
<Wrapper key={renderKey(data, index)} style={isRendered ? {} : rest}>
{ItemComponent(data, index, height, rest)}
</Wrapper>
);
})}
</>
);
};
const getDefaultConfig = (animationName: TCustomAnimations, height: number) => {
const commonConfig = {
opacity: 1,
height,
from: {
opacity: 0,
height: 0,
},
};
switch (animationName) {
case "waterfall":
return {
config: {
mass: 1,
tension: 1500,
friction: 100,
},
x: 0,
y: 0,
...commonConfig,
transform: "scale(1)",
from: {
x: 10,
y: 50,
transform: "scale(0.8)",
...commonConfig.from,
},
};
default:
return {
config: {
mass: 1,
tension: 1000,
friction: 200,
},
...commonConfig,
};
}
};
export default UnfoldListItems;
|