Emoji Tooltip: Update recent emojis (#1066)
This commit is contained in:
parent
0cf1bbb72c
commit
1436cb6908
@ -811,6 +811,7 @@ const Composer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
emojis={filteredEmojis}
|
emojis={filteredEmojis}
|
||||||
onClose={closeEmojiTooltip}
|
onClose={closeEmojiTooltip}
|
||||||
onEmojiSelect={insertEmoji}
|
onEmojiSelect={insertEmoji}
|
||||||
|
addRecentEmoji={addRecentEmoji}
|
||||||
/>
|
/>
|
||||||
<AttachMenu
|
<AttachMenu
|
||||||
isOpen={isAttachMenuOpen}
|
isOpen={isAttachMenuOpen}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import findInViewport from '../../../util/findInViewport';
|
|||||||
import isFullyVisible from '../../../util/isFullyVisible';
|
import isFullyVisible from '../../../util/isFullyVisible';
|
||||||
import fastSmoothScrollHorizontal from '../../../util/fastSmoothScrollHorizontal';
|
import fastSmoothScrollHorizontal from '../../../util/fastSmoothScrollHorizontal';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useShowTransition from '../../../hooks/useShowTransition';
|
||||||
|
import usePrevDuringAnimation from '../../../hooks/usePrevDuringAnimation';
|
||||||
|
|
||||||
import Loading from '../../ui/Loading';
|
import Loading from '../../ui/Loading';
|
||||||
import EmojiButton from './EmojiButton';
|
import EmojiButton from './EmojiButton';
|
||||||
@ -51,18 +52,23 @@ export type OwnProps = {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onEmojiSelect: (text: string) => void;
|
onEmojiSelect: (text: string) => void;
|
||||||
onClose: NoneToVoidFunction;
|
onClose: NoneToVoidFunction;
|
||||||
|
addRecentEmoji: AnyToVoidFunction;
|
||||||
emojis: Emoji[];
|
emojis: Emoji[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CLOSE_DURATION = 350;
|
||||||
|
|
||||||
const EmojiTooltip: FC<OwnProps> = ({
|
const EmojiTooltip: FC<OwnProps> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
emojis,
|
emojis,
|
||||||
onClose,
|
onClose,
|
||||||
onEmojiSelect,
|
onEmojiSelect,
|
||||||
|
addRecentEmoji,
|
||||||
}) => {
|
}) => {
|
||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const { shouldRender, transitionClassNames } = useShowTransition(isOpen, undefined, undefined, false);
|
const { shouldRender, transitionClassNames } = useShowTransition(isOpen, undefined, undefined, false);
|
||||||
|
const listEmojis: Emoji[] = usePrevDuringAnimation(emojis.length ? emojis : undefined, CLOSE_DURATION) || [];
|
||||||
|
|
||||||
const [selectedIndex, setSelectedIndex] = useState(-1);
|
const [selectedIndex, setSelectedIndex] = useState(-1);
|
||||||
|
|
||||||
@ -95,9 +101,10 @@ const EmojiTooltip: FC<OwnProps> = ({
|
|||||||
if (emoji) {
|
if (emoji) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
onEmojiSelect(emoji.native);
|
onEmojiSelect(emoji.native);
|
||||||
|
addRecentEmoji({ emoji: emoji.id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [emojis, onEmojiSelect, selectedIndex]);
|
}, [addRecentEmoji, emojis, onEmojiSelect, selectedIndex]);
|
||||||
|
|
||||||
useEffect(() => (isOpen ? captureKeyboardListeners({
|
useEffect(() => (isOpen ? captureKeyboardListeners({
|
||||||
onEsc: onClose,
|
onEsc: onClose,
|
||||||
@ -126,8 +133,8 @@ const EmojiTooltip: FC<OwnProps> = ({
|
|||||||
onMouseEnter={!IS_TOUCH_ENV ? handleMouseEnter : undefined}
|
onMouseEnter={!IS_TOUCH_ENV ? handleMouseEnter : undefined}
|
||||||
onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined}
|
onMouseLeave={!IS_TOUCH_ENV ? handleMouseLeave : undefined}
|
||||||
>
|
>
|
||||||
{shouldRender && emojis ? (
|
{shouldRender && listEmojis ? (
|
||||||
emojis.map((emoji, index) => (
|
listEmojis.map((emoji, index) => (
|
||||||
<EmojiButton
|
<EmojiButton
|
||||||
key={emoji.id}
|
key={emoji.id}
|
||||||
emoji={emoji}
|
emoji={emoji}
|
||||||
|
|||||||
@ -15,7 +15,7 @@ let emojiRawData: EmojiRawData;
|
|||||||
let emojiData: EmojiData;
|
let emojiData: EmojiData;
|
||||||
|
|
||||||
const RE_NOT_EMOJI_SEARCH = /[^-:_a-z\d]+/i;
|
const RE_NOT_EMOJI_SEARCH = /[^-:_a-z\d]+/i;
|
||||||
const EMOJIS_LIMIT = 50;
|
const EMOJIS_LIMIT = 36;
|
||||||
|
|
||||||
export default function useEmojiTooltip(
|
export default function useEmojiTooltip(
|
||||||
isAllowed: boolean,
|
isAllowed: boolean,
|
||||||
@ -25,24 +25,26 @@ export default function useEmojiTooltip(
|
|||||||
onUpdateHtml: (html: string) => void,
|
onUpdateHtml: (html: string) => void,
|
||||||
) {
|
) {
|
||||||
const [isOpen, markIsOpen, unmarkIsOpen] = useFlag();
|
const [isOpen, markIsOpen, unmarkIsOpen] = useFlag();
|
||||||
const [emojis, setEmojis] = useState<Emoji[]>([]);
|
const [emojiIds, setEmojiIds] = useState<string[]>([]);
|
||||||
const [filteredEmojis, setFilteredEmojis] = useState<Emoji[]>([]);
|
const [filteredEmojis, setFilteredEmojis] = useState<Emoji[]>([]);
|
||||||
|
|
||||||
const recentEmojis = useMemo(
|
const recentEmojis = useMemo(
|
||||||
() => {
|
() => {
|
||||||
if (!emojis && !recentEmojiIds.length) {
|
if (!emojiIds.length || !recentEmojiIds.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return emojis.filter((emoji) => recentEmojiIds.includes(emoji.id)) as Emoji[];
|
return recentEmojiIds
|
||||||
|
.map((emojiId) => emojiData.emojis[emojiId])
|
||||||
|
.filter<Emoji>(Boolean as any);
|
||||||
},
|
},
|
||||||
[emojis, recentEmojiIds],
|
[emojiIds, recentEmojiIds],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Initialize data on first render.
|
// Initialize data on first render.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const exec = () => {
|
const exec = () => {
|
||||||
setEmojis(Object.values(emojiData.emojis));
|
setEmojiIds(Object.keys(emojiData.emojis));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (emojiData) {
|
if (emojiData) {
|
||||||
@ -54,7 +56,7 @@ export default function useEmojiTooltip(
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!html || !emojis) {
|
if (!html || !emojiIds.length) {
|
||||||
unmarkIsOpen();
|
unmarkIsOpen();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -67,17 +69,20 @@ export default function useEmojiTooltip(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const filter = code.substr(1);
|
const filter = code.substr(1);
|
||||||
const matched = filter === '' ? recentEmojis : emojis.filter((emoji) => {
|
const matched = filter === ''
|
||||||
return 'names' in emoji && (!filter || emoji.names.find((name) => name.includes(filter)));
|
? recentEmojis
|
||||||
}) as Emoji[];
|
: emojiIds
|
||||||
|
.filter((emojiId) => emojiData.emojis[emojiId].names.find((name) => name.includes(filter)))
|
||||||
|
.slice(0, EMOJIS_LIMIT)
|
||||||
|
.map((emojiId) => emojiData.emojis[emojiId]);
|
||||||
|
|
||||||
if (matched.length) {
|
if (matched.length) {
|
||||||
markIsOpen();
|
markIsOpen();
|
||||||
setFilteredEmojis(matched.slice(0, EMOJIS_LIMIT));
|
setFilteredEmojis(matched);
|
||||||
} else {
|
} else {
|
||||||
unmarkIsOpen();
|
unmarkIsOpen();
|
||||||
}
|
}
|
||||||
}, [emojis, html, markIsOpen, recentEmojis, unmarkIsOpen]);
|
}, [emojiIds, html, markIsOpen, recentEmojis, unmarkIsOpen]);
|
||||||
|
|
||||||
const insertEmoji = useCallback((textEmoji: string) => {
|
const insertEmoji = useCallback((textEmoji: string) => {
|
||||||
const atIndex = html.lastIndexOf(':');
|
const atIndex = html.lastIndexOf(':');
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user