diff --git a/app/soapbox/components/status-reaction-wrapper.tsx b/app/soapbox/components/status-reaction-wrapper.tsx index 545d6fe7d..c2ce020f9 100644 --- a/app/soapbox/components/status-reaction-wrapper.tsx +++ b/app/soapbox/components/status-reaction-wrapper.tsx @@ -1,3 +1,4 @@ +import { Portal } from '@reach/portal'; import React, { useState, useEffect, useRef } from 'react'; import { simpleEmojiReact } from 'soapbox/actions/emoji-reacts'; @@ -105,12 +106,14 @@ const StatusReactionWrapper: React.FC = ({ statusId, chi ref: setReferenceElement, })} - + + + ); }; diff --git a/app/soapbox/components/ui/emoji-selector/emoji-selector.tsx b/app/soapbox/components/ui/emoji-selector/emoji-selector.tsx index 32851a4bf..7f8336035 100644 --- a/app/soapbox/components/ui/emoji-selector/emoji-selector.tsx +++ b/app/soapbox/components/ui/emoji-selector/emoji-selector.tsx @@ -3,7 +3,8 @@ import clsx from 'clsx'; import React, { useEffect, useState } from 'react'; import { usePopper } from 'react-popper'; -import { Emoji, HStack } from 'soapbox/components/ui'; +import { Emoji, HStack, IconButton } from 'soapbox/components/ui'; +import { Picker } from 'soapbox/features/emoji/emoji-picker'; import { useSoapboxConfig } from 'soapbox/hooks'; interface IEmojiButton { @@ -42,6 +43,8 @@ interface IEmojiSelector { placement?: Placement /** Whether the selector should be visible. */ visible?: boolean + /** Whether to allow any emoji to be chosen. */ + all?: boolean } /** Panel with a row of emoji buttons. */ @@ -51,9 +54,12 @@ const EmojiSelector: React.FC = ({ onReact, placement = 'top', visible = false, + all = true, }): JSX.Element => { const soapboxConfig = useSoapboxConfig(); + const [expanded, setExpanded] = useState(false); + // `useRef` won't trigger a re-render, while `useState` does. // https://popper.js.org/react-popper/v2/ const [popperElement, setPopperElement] = useState(null); @@ -80,6 +86,14 @@ const EmojiSelector: React.FC = ({ ], }); + const handleExpand: React.MouseEventHandler = () => { + setExpanded(true); + }; + + useEffect(() => { + setExpanded(false); + }, [visible]); + useEffect(() => { document.addEventListener('mousedown', handleClickOutside); @@ -103,18 +117,34 @@ const EmojiSelector: React.FC = ({ style={styles.popper} {...attributes.popper} > - - {Array.from(soapboxConfig.allowedEmoji).map((emoji, i) => ( - - ))} - + {expanded ? ( + require('emoji-datasource/img/twitter/sheets/32.png')} + onClick={(emoji: any) => onReact(emoji.native)} + /> + ) : ( + + {Array.from(soapboxConfig.allowedEmoji).map((emoji, i) => ( + + ))} + + {all && ( + + )} + + )} ); }; diff --git a/app/soapbox/features/chats/components/chat-message-reaction-wrapper/chat-message-reaction-wrapper.tsx b/app/soapbox/features/chats/components/chat-message-reaction-wrapper/chat-message-reaction-wrapper.tsx index f6c8b7f82..d9403af4a 100644 --- a/app/soapbox/features/chats/components/chat-message-reaction-wrapper/chat-message-reaction-wrapper.tsx +++ b/app/soapbox/features/chats/components/chat-message-reaction-wrapper/chat-message-reaction-wrapper.tsx @@ -41,6 +41,7 @@ function ChatMessageReactionWrapper(props: IChatMessageReactionWrapper) { referenceElement={referenceElement} onReact={handleSelect} onClose={() => setIsOpen(false)} + all={false} /> ); diff --git a/app/soapbox/features/emoji/emoji-picker.js b/app/soapbox/features/emoji/emoji-picker.ts similarity index 77% rename from app/soapbox/features/emoji/emoji-picker.js rename to app/soapbox/features/emoji/emoji-picker.ts index 8725d39ec..f4dd98a51 100644 --- a/app/soapbox/features/emoji/emoji-picker.js +++ b/app/soapbox/features/emoji/emoji-picker.ts @@ -1,4 +1,6 @@ +// @ts-ignore no types import Emoji from 'emoji-mart/dist-es/components/emoji/emoji'; +// @ts-ignore no types import Picker from 'emoji-mart/dist-es/components/picker/picker'; export { diff --git a/jest.config.cjs b/jest.config.cjs index 300e2c3ba..62139dedb 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -39,7 +39,7 @@ module.exports = { 'transformIgnorePatterns': [ // FIXME: react-sticky-box doesn't provide a CJS build, so transform it for now // https://github.com/codecks-io/react-sticky-box/issues/79 - `/node_modules/(?!(react-sticky-box|blurhash|.+\\.(${ASSET_EXTS})$))`, + `/node_modules/(?!(react-sticky-box|blurhash|emoji-mart|.+\\.(${ASSET_EXTS})$))`, // Ignore node_modules, except static assets // `/node_modules/(?!.+\\.(${ASSET_EXTS})$)`, ],