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

Add support for selected Emojis #437

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/DomUtils/classNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export enum ClassNames {
hidden = 'epr-hidden',
visible = 'epr-visible',
active = 'epr-active',
selected = 'epr-selected',
emoji = 'epr-emoji',
category = 'epr-emoji-category',
label = 'epr-emoji-category-label',
Expand Down
10 changes: 9 additions & 1 deletion src/Stylesheet/stylesheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,19 @@ const hidden = {
overflow: 'hidden'
};

const selected = {
backgroundColor: 'var(--epr-emoji-select-color)'
};

export const commonStyles = stylesheet.create({
hidden: {
'.': ClassNames.hidden,
...hidden
}
},
selected: {
'.': ClassNames.selected,
...selected
},
});

export const PickerStyleTag = React.memo(function PickerStyleTag() {
Expand Down
5 changes: 4 additions & 1 deletion src/components/Reactions/Reactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
useEmojiStyleConfig,
useReactionsConfig,
useAllowExpandReactions,
useGetEmojiUrlConfig
useGetEmojiUrlConfig,
useGetIsSelectedEmojis,
} from '../../config/useConfig';
import { DataEmoji } from '../../dataUtils/DataTypes';
import { emojiByUnified } from '../../dataUtils/emojiSelectors';
Expand All @@ -26,6 +27,7 @@ export function Reactions() {
const emojiStyle = useEmojiStyleConfig();
const allowExpandReactions = useAllowExpandReactions();
const getEmojiUrl = useGetEmojiUrlConfig();
const getIsSelectedEmojis = useGetIsSelectedEmojis();

if (!reactionsOpen) {
return null;
Expand All @@ -46,6 +48,7 @@ export function Reactions() {
className={cx(styles.emojiButton)}
noBackground
getEmojiUrl={getEmojiUrl}
selected={getIsSelectedEmojis(reaction)}
/>
</li>
))}
Expand Down
3 changes: 3 additions & 0 deletions src/components/body/EmojiList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
useCategoriesConfig,
useEmojiStyleConfig,
useGetEmojiUrlConfig,
useGetIsSelectedEmojis,
useLazyLoadEmojisConfig,
useSkinTonesDisabledConfig
} from '../../config/useConfig';
Expand Down Expand Up @@ -71,6 +72,7 @@ function RenderCategory({
const isEmojiDisallowed = useIsEmojiDisallowed();
const getEmojiUrl = useGetEmojiUrlConfig();
const showVariations = !useSkinTonesDisabledConfig();
const getIsSelectedEmojis = useGetIsSelectedEmojis();

// Small trick to defer the rendering of all emoji categories until the first category is visible
// This way the user gets to actually see something and not wait for the whole picker to render.
Expand Down Expand Up @@ -110,6 +112,7 @@ function RenderCategory({
emojiStyle={emojiStyle}
lazyLoad={lazyLoadEmojis}
getEmojiUrl={getEmojiUrl}
selected={getIsSelectedEmojis(unified)}
/>
);
});
Expand Down
5 changes: 4 additions & 1 deletion src/components/body/EmojiVariationPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
import { darkMode, stylesheet } from '../../Stylesheet/stylesheet';
import {
useEmojiStyleConfig,
useGetEmojiUrlConfig
useGetEmojiUrlConfig,
useGetIsSelectedEmojis
} from '../../config/useConfig';
import {
emojiHasVariations,
Expand Down Expand Up @@ -49,6 +50,7 @@ export function EmojiVariationPicker() {
const setAnchoredEmojiRef = useSetAnchoredEmojiRef();
const getPointerStyle = usePointerStyle(VariationPickerRef);
const getEmojiUrl = useGetEmojiUrlConfig();
const getIsSelectedEmojis = useGetIsSelectedEmojis();

const button = buttonFromTarget(AnchoredEmojiRef.current);

Expand Down Expand Up @@ -98,6 +100,7 @@ export function EmojiVariationPicker() {
emojiStyle={emojiStyle}
showVariations={false}
getEmojiUrl={getEmojiUrl}
selected={getIsSelectedEmojis(unified)}
/>
))
: null}
Expand Down
3 changes: 3 additions & 0 deletions src/components/body/Suggested.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CategoryConfig } from '../../config/categoryConfig';
import {
useEmojiStyleConfig,
useGetEmojiUrlConfig,
useGetIsSelectedEmojis,
useSuggestedEmojisModeConfig
} from '../../config/useConfig';
import { emojiByUnified } from '../../dataUtils/emojiSelectors';
Expand All @@ -29,6 +30,7 @@ export function Suggested({ categoryConfig }: Props) {
[suggestedUpdated, suggestedEmojisModeConfig]
);
const emojiStyle = useEmojiStyleConfig();
const getIsSelectedEmojis = useGetIsSelectedEmojis();

if (!isMounted) {
return null;
Expand All @@ -55,6 +57,7 @@ export function Suggested({ categoryConfig }: Props) {
emoji={emoji}
key={suggestedItem.unified}
getEmojiUrl={getEmojiUrl}
selected={getIsSelectedEmojis(suggestedItem.unified)}
/>
);
})}
Expand Down
3 changes: 2 additions & 1 deletion src/components/context/PickerConfigContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ export function useSetConfig(config: PickerConfig) {
config.width,
config.searchDisabled,
config.skinTonePickerLocation,
config.allowExpandReactions
config.allowExpandReactions,
config.selectedEmojis
]);

return mergedConfig;
Expand Down
13 changes: 11 additions & 2 deletions src/components/emoji/ClickableEmojiButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Button } from '../atoms/Button';

type ClickableEmojiButtonProps = Readonly<{
hidden?: boolean;
selected?: boolean;
showVariations?: boolean;
hiddenOnSearch?: boolean;
emojiNames: string[];
Expand All @@ -25,6 +26,7 @@ export function ClickableEmojiButton({
emojiNames,
unified,
hidden,
selected,
hiddenOnSearch,
showVariations = true,
hasVariations,
Expand All @@ -37,6 +39,7 @@ export function ClickableEmojiButton({
className={cx(
styles.emoji,
hidden && commonStyles.hidden,
selected && commonStyles.selected,
hiddenOnSearch && commonInteractionStyles.hiddenOnSearch,
{
[ClassNames.visible]: !hidden && !hiddenOnSearch
Expand Down Expand Up @@ -80,7 +83,13 @@ const styles = stylesheet.create({
},
':focus': {
backgroundColor: 'var(--epr-focus-bg-color)'
}
},
[`&.${ClassNames.selected}`]: {
backgroundColor: 'var(--epr-selected-bg-color)',
':focus': {
backgroundColor: 'var(--epr-selected-bg-color)'
},
},
},
noBackground: {
background: 'none',
Expand All @@ -91,7 +100,7 @@ const styles = stylesheet.create({
':focus': {
backgroundColor: 'transparent',
background: 'none'
}
},
},
hasVariations: {
'.': ClassNames.emojiHasVariations,
Expand Down
3 changes: 3 additions & 0 deletions src/components/emoji/Emoji.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ViewOnlyEmoji } from './ViewOnlyEmoji';
type ClickableEmojiProps = Readonly<
BaseEmojiProps & {
hidden?: boolean;
selected?: boolean;
showVariations?: boolean;
hiddenOnSearch?: boolean;
emoji: DataEmoji;
Expand All @@ -22,6 +23,7 @@ export function ClickableEmoji({
emoji,
unified,
hidden,
selected,
hiddenOnSearch,
emojiStyle,
showVariations = true,
Expand All @@ -38,6 +40,7 @@ export function ClickableEmoji({
hasVariations={hasVariations}
showVariations={showVariations}
hidden={hidden}
selected={selected}
hiddenOnSearch={hiddenOnSearch}
emojiNames={emojiNames(emoji)}
unified={unified}
Expand Down
1 change: 1 addition & 0 deletions src/components/main/PickerMain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ const styles = stylesheet.create({
'--epr-hover-bg-color': '#f1f8ff',
'--epr-hover-bg-color-reduced-opacity': '#f1f8ff80',
'--epr-focus-bg-color': '#e0f0ff',
'--epr-selected-bg-color': '#6aa8de',
'--epr-text-color': '#858585',
'--epr-search-input-bg-color': '#f6f6f6',
'--epr-picker-border-color': '#e7e7e7',
Expand Down
1 change: 1 addition & 0 deletions src/config/compareConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function compareConfig(prev: PickerConfig, next: PickerConfig) {
prev.style === next.style &&
prev.searchDisabled === next.searchDisabled &&
prev.skinTonePickerLocation === next.skinTonePickerLocation &&
prev.selectedEmojis === next.selectedEmojis &&
prevCustomEmojis.length === nextCustomEmojis.length
);
}
4 changes: 3 additions & 1 deletion src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ export function basePickerConfig(): PickerConfigInternal {
reactions: DEFAULT_REACTIONS,
open: true,
allowExpandReactions: true,
hiddenEmojis: []
hiddenEmojis: [],
selectedEmojis: []
};
}

Expand Down Expand Up @@ -126,6 +127,7 @@ export type PickerConfigInternal = {
open: boolean;
allowExpandReactions: boolean;
hiddenEmojis: string[];
selectedEmojis: string[];
};

export type PreviewConfig = {
Expand Down
5 changes: 5 additions & 0 deletions src/config/useConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,8 @@ export function useSearchResultsConfig(searchResultsCount: number): string {

return SEARCH_RESULTS_NO_RESULTS_FOUND;
}

export function useGetIsSelectedEmojis(): (emoji: string) => boolean {
const { selectedEmojis } = usePickerConfig();
return (emoji) => selectedEmojis.includes(emoji);
}
18 changes: 18 additions & 0 deletions stories/picker.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,24 @@ export const HideEmojisByUnicode = (args: Props) => (
<Template {...args} emojiStyle={EmojiStyle.NATIVE} />
);

export const SelectedEmojis = () => {
const [selectedEmojis, setSelectedEmojis] = useState<string[]>([]);

return (
<EmojiPicker
selectedEmojis={selectedEmojis}
reactionsDefaultOpen
onEmojiClick={({ unified }) =>
setSelectedEmojis(
selectedEmojis.includes(unified)
? selectedEmojis.filter((emoji) => emoji !== unified)
: [...selectedEmojis, unified],
)
}
/>
);
};

function TemplateDark(args) {
const [open, setOpen] = useState(true);
const [hasBg, setHasBg] = useState(false);
Expand Down