import React, { FC, memo, useCallback, useEffect, useLayoutEffect, useRef, useState, } from '../../../lib/teact/teact'; import { withGlobal } from '../../../lib/teact/teactn'; import { ApiSticker, ApiVideo } from '../../../api/types'; import { IAllowedAttachmentOptions } from '../../../modules/helpers'; import { IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../../util/environment'; import { fastRaf } from '../../../util/schedulers'; import buildClassName from '../../../util/buildClassName'; import useShowTransition from '../../../hooks/useShowTransition'; import useMouseInside from '../../../hooks/useMouseInside'; import useLang from '../../../hooks/useLang'; import Button from '../../ui/Button'; import Menu from '../../ui/Menu'; import Transition from '../../ui/Transition'; import EmojiPicker from './EmojiPicker'; import StickerPicker from './StickerPicker'; import GifPicker from './GifPicker'; import SymbolMenuFooter, { SYMBOL_MENU_TAB_TITLES, SymbolMenuTabs } from './SymbolMenuFooter'; import Portal from '../../ui/Portal'; import './SymbolMenu.scss'; const ANIMATION_DURATION = 350; export type OwnProps = { isOpen: boolean; allowedAttachmentOptions: IAllowedAttachmentOptions; onLoad: () => void; onClose: () => void; onEmojiSelect: (emoji: string) => void; onStickerSelect: (sticker: ApiSticker, shouldPreserveInput?: boolean) => void; onGifSelect: (gif: ApiVideo) => void; onRemoveSymbol: () => void; onSearchOpen: (type: 'stickers' | 'gifs') => void; addRecentEmoji: AnyToVoidFunction; }; type StateProps = { isLeftColumnShown: boolean; }; let isActivated = false; const SymbolMenu: FC = ({ isOpen, allowedAttachmentOptions, isLeftColumnShown, onLoad, onClose, onEmojiSelect, onStickerSelect, onGifSelect, onRemoveSymbol, onSearchOpen, addRecentEmoji, }) => { const [activeTab, setActiveTab] = useState(0); const [recentEmojis, setRecentEmojis] = useState([]); const [handleMouseEnter, handleMouseLeave] = useMouseInside(isOpen, onClose, undefined, IS_SINGLE_COLUMN_LAYOUT); const { shouldRender, transitionClassNames } = useShowTransition(isOpen, onClose, false, false); if (!isActivated && isOpen) { isActivated = true; } useEffect(() => { onLoad(); }, [onLoad]); useLayoutEffect(() => { if (!IS_SINGLE_COLUMN_LAYOUT) { return undefined; } if (isOpen) { document.body.classList.add('enable-symbol-menu-transforms'); document.body.classList.add('is-symbol-menu-open'); } return () => { if (isOpen) { fastRaf(() => { document.body.classList.remove('is-symbol-menu-open'); setTimeout(() => { document.body.classList.remove('enable-symbol-menu-transforms'); }, ANIMATION_DURATION); }); } }; }, [isOpen]); const recentEmojisRef = useRef(recentEmojis); recentEmojisRef.current = recentEmojis; useEffect(() => { if (!recentEmojisRef.current.length) { return; } recentEmojisRef.current.forEach((name) => { addRecentEmoji({ emoji: name }); }); setRecentEmojis([]); }, [isOpen, activeTab, addRecentEmoji]); const handleEmojiSelect = useCallback((emoji: string, name: string) => { setRecentEmojis((emojis) => { return [...emojis, name]; }); onEmojiSelect(emoji); }, [onEmojiSelect]); const handleSearch = useCallback((type: 'stickers' | 'gifs') => { onClose(); onSearchOpen(type); }, [onClose, onSearchOpen]); const handleStickerSelect = useCallback((sticker: ApiSticker) => { onStickerSelect(sticker, true); }, [onStickerSelect]); const lang = useLang(); const { canSendStickers, canSendGifs } = allowedAttachmentOptions; function renderContent(isActive: boolean, isFrom: boolean) { switch (activeTab) { case SymbolMenuTabs.Emoji: return ( ); case SymbolMenuTabs.Stickers: return ( ); case SymbolMenuTabs.GIFs: return ( ); } return undefined; } function stopPropagation(event: any) { event.stopPropagation(); } const content = ( <>
{isActivated && ( {renderContent} )}
{IS_SINGLE_COLUMN_LAYOUT && ( )} ); if (IS_SINGLE_COLUMN_LAYOUT) { if (!shouldRender) { return undefined; } const className = buildClassName( 'SymbolMenu mobile-menu', transitionClassNames, !isLeftColumnShown && 'middle-column-open', ); return (
{content}
); } return ( {content} ); }; export default memo(withGlobal( (global): StateProps => { return { isLeftColumnShown: global.isLeftColumnShown, }; }, )(SymbolMenu));