Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature to highlight active emoji #35140

Merged
2 changes: 2 additions & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,8 @@ const CONST = {
EMOJI: /[\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu,
// eslint-disable-next-line max-len, no-misleading-character-class
EMOJIS: /[\p{Extended_Pictographic}](\u200D[\p{Extended_Pictographic}]|[\u{1F3FB}-\u{1F3FF}]|[\u{E0020}-\u{E007F}]|\uFE0F|\u20E3)*|[\u{1F1E6}-\u{1F1FF}]{2}|[#*0-9]\uFE0F?\u20E3/gu,
// eslint-disable-next-line max-len, no-misleading-character-class
EMOJI_SKIN_TONES: /[\u{1f3fb}-\u{1f3ff}]/gu,

TAX_ID: /^\d{9}$/,
NON_NUMERIC: /\D/g,
Expand Down
6 changes: 5 additions & 1 deletion src/components/EmojiPicker/EmojiPicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const EmojiPicker = forwardRef((props, ref) => {
const emojiPopoverAnchorRef = useRef(null);
const onModalHide = useRef(() => {});
const onEmojiSelected = useRef(() => {});
const activeEmoji = useRef();
const emojiSearchInput = useRef();
const {isSmallScreenWidth, windowHeight} = useWindowDimensions();

Expand All @@ -55,10 +56,12 @@ const EmojiPicker = forwardRef((props, ref) => {
* @param {Object} [anchorOrigin=DEFAULT_ANCHOR_ORIGIN] - Anchor origin for Popover
* @param {Function} [onWillShow=() => {}] - Run a callback when Popover will show
* @param {String} id - Unique id for EmojiPicker
* @param {String} activeEmojiValue - Selected emoji to be highlighted
*/
const showEmojiPicker = (onModalHideValue, onEmojiSelectedValue, emojiPopoverAnchorValue, anchorOrigin, onWillShow = () => {}, id) => {
const showEmojiPicker = (onModalHideValue, onEmojiSelectedValue, emojiPopoverAnchorValue, anchorOrigin, onWillShow = () => {}, id, activeEmojiValue) => {
onModalHide.current = onModalHideValue;
onEmojiSelected.current = onEmojiSelectedValue;
activeEmoji.current = activeEmojiValue;
emojiPopoverAnchorRef.current = emojiPopoverAnchorValue;
const emojiPopoverAnchor = getEmojiPopoverAnchor();
if (emojiPopoverAnchor.current && emojiPopoverAnchor.current.blur) {
Expand Down Expand Up @@ -190,6 +193,7 @@ const EmojiPicker = forwardRef((props, ref) => {
>
<EmojiPickerMenu
onEmojiSelected={selectEmoji}
activeEmoji={activeEmoji.current}
ref={(el) => (emojiSearchInput.current = el)}
/>
</PopoverWithMeasuredContent>
Expand Down
19 changes: 13 additions & 6 deletions src/components/EmojiPicker/EmojiPickerButtonDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,25 @@ function EmojiPickerButtonDropdown(props) {
const StyleUtils = useStyleUtils();
const emojiPopoverAnchor = useRef(null);
useEffect(() => EmojiPickerAction.resetEmojiPopoverAnchor, []);

const onPress = () => {
if (EmojiPickerAction.isEmojiPickerVisible()) {
EmojiPickerAction.hideEmojiPicker();
return;
}

EmojiPickerAction.showEmojiPicker(props.onModalHide, (emoji) => props.onInputChange(emoji), emojiPopoverAnchor, {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
shiftVertical: 4,
});
EmojiPickerAction.showEmojiPicker(
props.onModalHide,
(emoji) => props.onInputChange(emoji),
emojiPopoverAnchor,
{
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
shiftVertical: 4,
},
() => {},
undefined,
props.value,
);
};

return (
Expand Down
7 changes: 5 additions & 2 deletions src/components/EmojiPicker/EmojiPickerMenu/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
import * as EmojiUtils from '@libs/EmojiUtils';
import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition';
import * as ReportUtils from '@libs/ReportUtils';
import CONST from '@src/CONST';
Expand All @@ -34,7 +35,7 @@ const defaultProps = {

const throttleTime = Browser.isMobile() ? 200 : 50;

function EmojiPickerMenu({forwardedRef, onEmojiSelected}) {
function EmojiPickerMenu({forwardedRef, onEmojiSelected, activeEmoji}) {
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isSmallScreenWidth, windowWidth} = useWindowDimensions();
Expand Down Expand Up @@ -259,7 +260,8 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected}) {
const emojiCode = types && types[preferredSkinTone] ? types[preferredSkinTone] : code;

const isEmojiFocused = index === focusedIndex && isUsingKeyboardMovement;
const shouldEmojiBeHighlighted = index === focusedIndex && highlightEmoji;
const shouldEmojiBeHighlighted =
(index === focusedIndex && highlightEmoji) || (Boolean(activeEmoji) && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji));
const shouldFirstEmojiBeHighlighted = index === 0 && highlightFirstEmoji;

return (
Expand Down Expand Up @@ -293,6 +295,7 @@ function EmojiPickerMenu({forwardedRef, onEmojiSelected}) {
translate,
onEmojiSelected,
setFocusedIndex,
activeEmoji,
],
);

Expand Down
7 changes: 5 additions & 2 deletions src/components/EmojiPicker/EmojiPickerMenu/index.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ import useSingleExecution from '@hooks/useSingleExecution';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as EmojiUtils from '@libs/EmojiUtils';
import CONST from '@src/CONST';
import BaseEmojiPickerMenu from './BaseEmojiPickerMenu';
import emojiPickerMenuPropTypes from './emojiPickerMenuPropTypes';
import useEmojiPickerMenu from './useEmojiPickerMenu';

const propTypes = emojiPickerMenuPropTypes;

function EmojiPickerMenu({onEmojiSelected}) {
function EmojiPickerMenu({onEmojiSelected, activeEmoji}) {
const styles = useThemeStyles();
const {windowWidth, isSmallScreenWidth} = useWindowDimensions();
const {translate} = useLocalize();
Expand Down Expand Up @@ -94,15 +95,17 @@ function EmojiPickerMenu({onEmojiSelected}) {
}

const emojiCode = types && types[preferredSkinTone] ? types[preferredSkinTone] : code;
const shouldEmojiBeHighlighted = Boolean(activeEmoji) && EmojiUtils.getRemovedSkinToneEmoji(emojiCode) === EmojiUtils.getRemovedSkinToneEmoji(activeEmoji);

return (
<EmojiPickerMenuItem
onPress={singleExecution((emoji) => onEmojiSelected(emoji, item))}
emoji={emojiCode}
isHighlighted={shouldEmojiBeHighlighted}
/>
);
},
[styles, windowWidth, preferredSkinTone, singleExecution, onEmojiSelected, translate],
[styles, windowWidth, preferredSkinTone, singleExecution, onEmojiSelected, translate, activeEmoji],
);

return (
Expand Down
6 changes: 6 additions & 0 deletions src/libs/EmojiUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,11 @@ const getEmojiReactionDetails = (emojiName: string, reaction: ReportActionReacti
};
};

/**
* Given an emoji code, returns an base emoji code without skin tone
*/
const getRemovedSkinToneEmoji = (emoji: string) => emoji.replace(CONST.REGEX.EMOJI_SKIN_TONES, '');

function getSpacersIndexes(allEmojis: EmojiPickerList): number[] {
const spacersIndexes: number[] = [];
allEmojis.forEach((emoji, index) => {
Expand Down Expand Up @@ -582,5 +587,6 @@ export {
getAddedEmojis,
isFirstLetterEmoji,
hasAccountIDEmojiReacted,
getRemovedSkinToneEmoji,
getSpacersIndexes,
};
4 changes: 3 additions & 1 deletion src/libs/actions/EmojiPickerAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type EmojiPickerRef = {
anchorOrigin?: AnchorOrigin,
onWillShow?: OnWillShowPicker,
id?: string,
activeEmoji?: string,
) => void;
isActive: (id: string) => boolean;
clearActive: () => void;
Expand Down Expand Up @@ -55,12 +56,13 @@ function showEmojiPicker(
anchorOrigin?: AnchorOrigin,
onWillShow: OnWillShowPicker = () => {},
id?: string,
activeEmoji?: string,
) {
if (!emojiPickerRef.current) {
return;
}

emojiPickerRef.current.showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow, id);
emojiPickerRef.current.showEmojiPicker(onModalHide, onEmojiSelected, emojiPopoverAnchor, anchorOrigin, onWillShow, id, activeEmoji);
}

/**
Expand Down
Loading