Remove old emoji and sticker pickers

This commit is contained in:
Jamie
2025-10-07 12:01:24 -07:00
committed by GitHub
parent 8b8f9a8f91
commit b73563ad9d
80 changed files with 533 additions and 4693 deletions

View File

@@ -117,7 +117,6 @@ const defaultMessageProps: TimelineMessagesProps = {
previews: [],
reactToMessage: action('default--reactToMessage'),
readStatus: ReadStatus.Read,
renderEmojiPicker: () => <div />,
renderReactionPicker: () => <div />,
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
setMessageToEdit: action('setMessageToEdit'),

View File

@@ -6,29 +6,10 @@ import { action } from '@storybook/addon-actions';
import type { Meta } from '@storybook/react';
import type { Props as ReactionPickerProps } from './ReactionPicker.js';
import { ReactionPicker } from './ReactionPicker.js';
import { EmojiPicker } from '../emoji/EmojiPicker.js';
import { DEFAULT_PREFERRED_REACTION_EMOJI } from '../../reactions/constants.js';
import { EmojiSkinTone } from '../fun/data/emojis.js';
const { i18n } = window.SignalContext;
const renderEmojiPicker: ReactionPickerProps['renderEmojiPicker'] = ({
onClose,
onPickEmoji,
onEmojiSkinToneDefaultChange,
ref,
}) => (
<EmojiPicker
i18n={i18n}
emojiSkinToneDefault={EmojiSkinTone.None}
ref={ref}
onClose={onClose}
onPickEmoji={onPickEmoji}
onEmojiSkinToneDefaultChange={onEmojiSkinToneDefaultChange}
wasInvokedFromKeyboard={false}
/>
);
export default {
title: 'Components/Conversation/ReactionPicker',
} satisfies Meta<ReactionPickerProps>;
@@ -38,12 +19,7 @@ export function Base(): JSX.Element {
<ReactionPicker
i18n={i18n}
onPick={action('onPick')}
onEmojiSkinToneDefaultChange={action('onEmojiSkinToneDefaultChange')}
openCustomizePreferredReactionsModal={action(
'openCustomizePreferredReactionsModal'
)}
preferredReactionEmoji={DEFAULT_PREFERRED_REACTION_EMOJI}
renderEmojiPicker={renderEmojiPicker}
/>
);
}
@@ -57,14 +33,7 @@ export function SelectedReaction(): JSX.Element {
i18n={i18n}
selected={e}
onPick={action('onPick')}
onEmojiSkinToneDefaultChange={action(
'onEmojiSkinToneDefaultChange'
)}
openCustomizePreferredReactionsModal={action(
'openCustomizePreferredReactionsModal'
)}
preferredReactionEmoji={DEFAULT_PREFERRED_REACTION_EMOJI}
renderEmojiPicker={renderEmojiPicker}
/>
</div>
))}

View File

@@ -3,39 +3,24 @@
import React, { useCallback, useState, useEffect } from 'react';
import { Button } from 'react-aria-components';
import { convertShortName } from '../emoji/lib.js';
import type { Props as EmojiPickerProps } from '../emoji/EmojiPicker.js';
import { useDelayedRestoreFocus } from '../../hooks/useRestoreFocus.js';
import type { LocalizerType, ThemeType } from '../../types/Util.js';
import {
ReactionPickerPicker,
ReactionPickerPickerEmojiButton,
ReactionPickerPickerMoreButton,
ReactionPickerPickerStyle,
} from '../ReactionPickerPicker.js';
import type { EmojiSkinTone, EmojiVariantKey } from '../fun/data/emojis.js';
import type { EmojiVariantKey } from '../fun/data/emojis.js';
import { getEmojiVariantByKey } from '../fun/data/emojis.js';
import { FunEmojiPicker } from '../fun/FunEmojiPicker.js';
import type { FunEmojiSelection } from '../fun/panels/FunPanelEmojis.js';
import { isFunPickerEnabled } from '../fun/isFunPickerEnabled.js';
export type RenderEmojiPickerProps = Pick<Props, 'onClose' | 'style'> &
Pick<
EmojiPickerProps,
'onClickSettings' | 'onPickEmoji' | 'onEmojiSkinToneDefaultChange'
> & {
ref: React.Ref<HTMLDivElement>;
};
export type OwnProps = {
i18n: LocalizerType;
selected?: string;
onClose?: () => unknown;
onPick: (emoji: string) => unknown;
onEmojiSkinToneDefaultChange: (emojiSkinTone: EmojiSkinTone) => unknown;
openCustomizePreferredReactionsModal?: () => unknown;
preferredReactionEmoji: ReadonlyArray<string>;
renderEmojiPicker: (props: RenderEmojiPickerProps) => React.ReactElement;
theme?: ThemeType;
messageEmojis?: ReadonlyArray<EmojiVariantKey>;
};
@@ -48,10 +33,7 @@ export const ReactionPicker = React.forwardRef<HTMLDivElement, Props>(
i18n,
onClose,
onPick,
onEmojiSkinToneDefaultChange,
openCustomizePreferredReactionsModal,
preferredReactionEmoji,
renderEmojiPicker,
selected,
style,
theme,
@@ -80,14 +62,6 @@ export const ReactionPicker = React.forwardRef<HTMLDivElement, Props>(
setEmojiPickerOpen(open);
}, []);
// Handle EmojiPicker::onPickEmoji
const onPickEmoji: EmojiPickerProps['onPickEmoji'] = React.useCallback(
({ shortName, skinTone: pickedSkinTone }) => {
onPick(convertShortName(shortName, pickedSkinTone));
},
[onPick]
);
const onSelectEmoji = useCallback(
(emojiSelection: FunEmojiSelection) => {
const variant = getEmojiVariantByKey(emojiSelection.variantKey);
@@ -99,17 +73,6 @@ export const ReactionPicker = React.forwardRef<HTMLDivElement, Props>(
// Focus first button and restore focus on unmount
const [focusRef] = useDelayedRestoreFocus();
if (!isFunPickerEnabled() && emojiPickerOpen) {
return renderEmojiPicker({
onClickSettings: openCustomizePreferredReactionsModal,
onClose,
onPickEmoji,
onEmojiSkinToneDefaultChange,
ref,
style,
});
}
const otherSelected =
selected != null && !preferredReactionEmoji.includes(selected);
@@ -149,32 +112,20 @@ export const ReactionPicker = React.forwardRef<HTMLDivElement, Props>(
title={i18n('icu:Reactions--remove')}
/>
) : (
<>
{isFunPickerEnabled() && (
<FunEmojiPicker
open={emojiPickerOpen}
onOpenChange={handleFunEmojiPickerOpenChange}
onSelectEmoji={onSelectEmoji}
theme={theme}
showCustomizePreferredReactionsButton
closeOnSelect
messageEmojis={messageEmojis}
>
<Button
aria-label={i18n('icu:Reactions--more')}
className="module-ReactionPickerPicker__button module-ReactionPickerPicker__button--more"
/>
</FunEmojiPicker>
)}
{!isFunPickerEnabled() && (
<ReactionPickerPickerMoreButton
i18n={i18n}
onClick={() => {
setEmojiPickerOpen(true);
}}
/>
)}
</>
<FunEmojiPicker
open={emojiPickerOpen}
onOpenChange={handleFunEmojiPickerOpenChange}
onSelectEmoji={onSelectEmoji}
theme={theme}
showCustomizePreferredReactionsButton
closeOnSelect
messageEmojis={messageEmojis}
>
<Button
aria-label={i18n('icu:Reactions--more')}
className="module-ReactionPickerPicker__button module-ReactionPickerPicker__button--more"
/>
</FunEmojiPicker>
)}
</ReactionPickerPicker>
);

View File

@@ -10,11 +10,12 @@ import { Avatar } from '../Avatar.js';
import { useRestoreFocus } from '../../hooks/useRestoreFocus.js';
import type { ConversationType } from '../../state/ducks/conversations.js';
import type { PreferredBadgeSelectorType } from '../../state/selectors/badges.js';
import type { EmojiData } from '../emoji/lib.js';
import { emojiToData } from '../emoji/lib.js';
import { useEscapeHandling } from '../../hooks/useEscapeHandling.js';
import type { ThemeType } from '../../types/Util.js';
import type { EmojiParentKey, EmojiVariantKey } from '../fun/data/emojis.js';
import {
EMOJI_PARENT_KEY_CONSTANTS,
getEmojiParentKeyByVariantKey,
getEmojiVariantByKey,
getEmojiVariantKeyByValue,
isEmojiVariantValue,
@@ -23,7 +24,7 @@ import { strictAssert } from '../../util/assert.js';
import { FunStaticEmoji } from '../fun/FunEmoji.js';
import { useFunEmojiLocalizer } from '../fun/useFunEmojiLocalizer.js';
const { groupBy, mapValues, orderBy } = lodash;
const { mapValues, orderBy } = lodash;
export type Reaction = {
emoji: string;
@@ -56,13 +57,13 @@ export type Props = OwnProps &
Pick<AvatarProps, 'i18n'>;
const DEFAULT_EMOJI_ORDER = [
'heart',
'+1',
'-1',
'joy',
'open_mouth',
'cry',
'rage',
EMOJI_PARENT_KEY_CONSTANTS.RED_HEART,
EMOJI_PARENT_KEY_CONSTANTS.THUMBS_UP,
EMOJI_PARENT_KEY_CONSTANTS.THUMBS_DOWN,
EMOJI_PARENT_KEY_CONSTANTS.FACE_WITH_TEARS_OF_JOY,
EMOJI_PARENT_KEY_CONSTANTS.FACE_WITH_OPEN_MOUTH,
EMOJI_PARENT_KEY_CONSTANTS.CRYING_FACE,
EMOJI_PARENT_KEY_CONSTANTS.ENRAGED_FACE,
];
type ReactionCategory = {
@@ -72,7 +73,11 @@ type ReactionCategory = {
index: number;
};
type ReactionWithEmojiData = Reaction & EmojiData;
type ReactionWithEmojiData = Reaction &
Readonly<{
parentKey: EmojiParentKey;
variantKey: EmojiVariantKey;
}>;
function ReactionViewerEmoji(props: {
emojiVariantValue: string | undefined;
@@ -112,37 +117,32 @@ export const ReactionViewer = React.forwardRef<HTMLDivElement, Props>(
() =>
reactions
.map(reaction => {
const emojiData = emojiToData(reaction.emoji);
if (!emojiData) {
return undefined;
if (!isEmojiVariantValue(reaction.emoji)) {
return null;
}
return {
...reaction,
...emojiData,
};
const variantKey = getEmojiVariantKeyByValue(reaction.emoji);
const parentKey = getEmojiParentKeyByVariantKey(variantKey);
return { ...reaction, parentKey, variantKey };
})
.filter(
(
reactionWithEmojiData
): reactionWithEmojiData is ReactionWithEmojiData =>
Boolean(reactionWithEmojiData)
),
.filter((data): data is ReactionWithEmojiData => {
return data != null;
}),
[reactions]
);
const groupedAndSortedReactions = React.useMemo(
() =>
mapValues(
{
all: reactionsWithEmojiData,
...groupBy(reactionsWithEmojiData, 'short_name'),
},
groupedReactions => orderBy(groupedReactions, ['timestamp'], ['desc'])
),
[reactionsWithEmojiData]
);
const groupedAndSortedReactions = React.useMemo(() => {
const groups = Object.groupBy(reactionsWithEmojiData, data => {
return data.parentKey;
});
return mapValues(
{
all: reactionsWithEmojiData,
...groups,
},
groupedReactions => orderBy(groupedReactions, ['timestamp'], ['desc'])
);
}, [reactionsWithEmojiData]);
const reactionCategories: Array<ReactionCategory> = React.useMemo(
() =>
@@ -159,9 +159,9 @@ export const ReactionViewer = React.forwardRef<HTMLDivElement, Props>(
const localUserReaction = groupedReactions.find(r => r.from.isMe);
const firstReaction = localUserReaction || groupedReactions[0];
return {
id: firstReaction.short_name,
index: DEFAULT_EMOJI_ORDER.includes(firstReaction.short_name)
? DEFAULT_EMOJI_ORDER.indexOf(firstReaction.short_name)
id: firstReaction.parentKey,
index: DEFAULT_EMOJI_ORDER.includes(firstReaction.parentKey)
? DEFAULT_EMOJI_ORDER.indexOf(firstReaction.parentKey)
: Infinity,
emoji: firstReaction.emoji,
count: groupedReactions.length,

View File

@@ -376,7 +376,6 @@ const renderItem = ({
item={items[messageId]}
renderAudioAttachment={() => <div>*AudioAttachment*</div>}
renderContact={() => <div>*ContactName*</div>}
renderEmojiPicker={() => <div />}
renderReactionPicker={() => <div />}
renderUniversalTimerNotification={() => (
<div>*UniversalTimerNotification*</div>

View File

@@ -4,7 +4,6 @@
import * as React from 'react';
import { action } from '@storybook/addon-actions';
import type { Meta } from '@storybook/react';
import { EmojiPicker } from '../emoji/EmojiPicker.js';
import { DurationInSeconds } from '../../util/durations/index.js';
import type { PropsType as TimelineItemProps } from './TimelineItem.js';
import { TimelineItem } from './TimelineItem.js';
@@ -16,28 +15,9 @@ import { WidthBreakpoint } from '../_util.js';
import { ThemeType } from '../../types/Util.js';
import { PaymentEventKind } from '../../types/Payment.js';
import { ErrorBoundary } from './ErrorBoundary.js';
import { EmojiSkinTone } from '../fun/data/emojis.js';
const { i18n } = window.SignalContext;
const renderEmojiPicker: TimelineItemProps['renderEmojiPicker'] = ({
onClose,
onPickEmoji,
ref,
}) => (
<EmojiPicker
i18n={i18n}
emojiSkinToneDefault={EmojiSkinTone.None}
onEmojiSkinToneDefaultChange={action(
'EmojiPicker::onEmojiSkinToneDefaultChange'
)}
ref={ref}
onClose={onClose}
onPickEmoji={onPickEmoji}
wasInvokedFromKeyboard={false}
/>
);
const renderReactionPicker: TimelineItemProps['renderReactionPicker'] = () => (
<div />
);
@@ -124,7 +104,6 @@ const getDefaultProps = () => ({
renderContact,
renderUniversalTimerNotification,
renderEmojiPicker,
renderReactionPicker,
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
viewStory: action('viewStory'),

View File

@@ -210,7 +210,6 @@ export type PropsType = PropsLocalType &
AllMessageProps,
| 'containerWidthBreakpoint'
| 'getPreferredBadge'
| 'renderEmojiPicker'
| 'renderAudioAttachment'
| 'renderReactionPicker'
| 'shouldCollapseAbove'

View File

@@ -9,7 +9,6 @@ import type { Meta, StoryFn } from '@storybook/react';
import { SignalService } from '../../protobuf/index.js';
import { ConversationColors } from '../../types/Colors.js';
import { EmojiPicker } from '../emoji/EmojiPicker.js';
import type { AudioAttachmentProps } from './Message.js';
import type { Props } from './TimelineMessage.js';
import { TimelineMessage } from './TimelineMessage.js';
@@ -44,7 +43,6 @@ import { getFakeBadge } from '../../test-helpers/getFakeBadge.js';
import { ThemeType } from '../../types/Util.js';
import { BadgeCategory } from '../../badges/BadgeCategory.js';
import { PaymentEventKind } from '../../types/Payment.js';
import { EmojiSkinTone } from '../fun/data/emojis.js';
const { isBoolean, noop } = lodash;
@@ -110,24 +108,6 @@ function getJoyReaction() {
};
}
const renderEmojiPicker: Props['renderEmojiPicker'] = ({
onClose,
onPickEmoji,
ref,
}) => (
<EmojiPicker
i18n={i18n}
emojiSkinToneDefault={EmojiSkinTone.None}
onEmojiSkinToneDefaultChange={action(
'EmojiPicker::onEmojiSkinToneDefaultChange'
)}
ref={ref}
onClose={onClose}
onPickEmoji={onPickEmoji}
wasInvokedFromKeyboard={false}
/>
);
const renderReactionPicker: Props['renderReactionPicker'] = () => <div />;
/**
@@ -319,7 +299,6 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
overrideProps.readStatus === undefined
? ReadStatus.Read
: overrideProps.readStatus,
renderEmojiPicker,
renderReactionPicker,
renderAudioAttachment,
saveAttachment: action('saveAttachment'),

View File

@@ -31,7 +31,6 @@ import type {
} from './Message.js';
import type { PushPanelForConversationActionType } from '../../state/ducks/conversations.js';
import { doesMessageBodyOverflow } from './MessageBodyReadMore.js';
import type { Props as ReactionPickerProps } from './ReactionPicker.js';
import {
useKeyboardShortcutsConditionally,
useOpenContextMenu,
@@ -90,8 +89,7 @@ export type PropsActions = {
export type Props = PropsData &
PropsActions &
Omit<PropsHousekeeping, 'isAttachmentPending'> &
Pick<ReactionPickerProps, 'renderEmojiPicker'> & {
Omit<PropsHousekeeping, 'isAttachmentPending'> & {
renderReactionPicker: (
props: React.ComponentProps<typeof SmartReactionPicker>
) => JSX.Element;
@@ -123,7 +121,6 @@ export function TimelineMessage(props: Props): JSX.Element {
copyMessageText,
pushPanelForConversation,
reactToMessage,
renderEmojiPicker,
renderReactionPicker,
retryDeleteForEveryone,
retryMessageSend,
@@ -343,7 +340,6 @@ export function TimelineMessage(props: Props): JSX.Element {
remove: emoji === selectedReaction,
});
},
renderEmojiPicker,
messageEmojis,
})
}
@@ -369,7 +365,6 @@ export function TimelineMessage(props: Props): JSX.Element {
renderReactionPicker,
selectedReaction,
reactToMessage,
renderEmojiPicker,
toggleReactionPicker,
id,
messageEmojis,