import { ReactNode, useEffect } from 'react'; import * as React from 'react'; import { useBodyRef } from '../components/context/ElementRefContext'; import { useActiveSkinToneState } from '../components/context/PickerContext'; import { ClickableEmoji } from '../components/emoji/Emoji'; import { useEmojiStyleConfig, useGetEmojiUrlConfig, useLazyLoadEmojisConfig, useSkinTonesDisabledConfig, } from '../config/useConfig'; import { DataEmojis } from '../dataUtils/DataTypes'; import { emojiUnified } from '../dataUtils/emojiUtils'; import { getEmojiPositionStyle, shouldVirtualize, } from '../virtualization/virtualizationHelpers'; import { preloadEmojiIfNeeded } from './preloadEmoji'; import { useCategoryHeight } from './useCategoryHeight'; import { useIsEmojiDisallowed } from './useDisallowedEmojis'; import { useIsEmojiHidden } from './useIsEmojiHidden'; export function useEmojiVirtualization({ categoryEmojis, topOffset, onHeightReady, scrollTop, isCategoryVisible, }: { categoryEmojis: DataEmojis; topOffset: number; onHeightReady: (height: number) => void; scrollTop: number; isCategoryVisible: boolean; }) { const isEmojiHidden = useIsEmojiHidden(); const lazyLoadEmojis = useLazyLoadEmojisConfig(); const emojiStyle = useEmojiStyleConfig(); const [activeSkinTone] = useActiveSkinToneState(); const isEmojiDisallowed = useIsEmojiDisallowed(); const getEmojiUrl = useGetEmojiUrlConfig(); const showVariations = !useSkinTonesDisabledConfig(); const BodyRef = useBodyRef(); let virtualizedCounter = 0; const emojisToPush = categoryEmojis.filter((emoji) => { const isDisallowed = isEmojiDisallowed(emoji); const { failedToLoad, filteredOut, hidden } = isEmojiHidden(emoji); return !failedToLoad && !filteredOut && !hidden && !isDisallowed; }); const dimensions = useCategoryHeight(emojisToPush.length); useEffect(() => { if (dimensions) { onHeightReady(dimensions.categoryHeight); } }, [dimensions, onHeightReady, emojisToPush.length]); const isVirtualized = (style: { top: number; left: number } | undefined) => dimensions && BodyRef.current && shouldVirtualize({ scrollTop, clientHeight: BodyRef.current?.clientHeight ?? 0, topOffset, style, dimensions, }); const emojis = emojisToPush.reduce((accumulator, emoji, index) => { const unified = emojiUnified(emoji, activeSkinTone); const style = getEmojiPositionStyle(dimensions, index); if (isVirtualized(style)) { virtualizedCounter++; preloadEmojiIfNeeded( emoji, emojiStyle, scrollTop, BodyRef.current?.clientHeight ?? 0, topOffset, style, dimensions, getEmojiUrl, ); return accumulator; } if (!isCategoryVisible) { virtualizedCounter++; return accumulator; } accumulator.push( , ); return accumulator; }, [] as ReactNode[]); return { virtualizedCounter, emojis, dimensions, }; }