// Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { useVirtualizer } from '@tanstack/react-virtual'; import { chunk } from 'lodash'; import React, { useCallback, useEffect, useRef } from 'react'; import { type ComponentMeta } from '../../storybook/types'; import type { FunStaticEmojiProps } from './FunEmoji'; import { FunStaticEmoji } from './FunEmoji'; import { _allEmojiVariantKeys, getEmojiParentByKey, getEmojiParentKeyByVariantKey, getEmojiVariantByKey, } from './data/emojis'; export default { title: 'Components/Fun/FunEmoji', component: All, args: { size: 16, }, argTypes: { size: { control: { type: 'select' }, options: [16, 32] }, }, } satisfies ComponentMeta; const COLUMNS = 8; type AllProps = Pick; export function All(props: AllProps): JSX.Element { const scrollerRef = useRef(null); const data = Array.from(_allEmojiVariantKeys()); const rows = chunk(data, COLUMNS); const getScrollElement = useCallback(() => { return scrollerRef.current; }, []); const estimateSize = useCallback(() => { return props.size; }, [props.size]); const rowVirtualizer = useVirtualizer({ count: rows.length, getScrollElement, estimateSize, gap: 4, }); const lastMeasuredSizeRef = useRef(props.size); useEffect(() => { if (lastMeasuredSizeRef.current !== props.size) { rowVirtualizer.measure(); lastMeasuredSizeRef.current = props.size; } }, [rowVirtualizer, props.size]); return (
{rowVirtualizer.getVirtualItems().map(rowItem => { const row = rows[rowItem.index]; return (
{row.map(emojiVariantKey => { const variant = getEmojiVariantByKey(emojiVariantKey); const parentKey = getEmojiParentKeyByVariantKey(emojiVariantKey); const parent = getEmojiParentByKey(parentKey); return (
); })}
); })}
); }