Skip to content

Commit 17869ec

Browse files
authored
feat: select icons from emoji picker (#10119)
1 parent bda68b1 commit 17869ec

31 files changed

+169
-45
lines changed

site/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
},
3333
"dependencies": {
3434
"@emoji-mart/data": "1.1.2",
35-
"@emoji-mart/react": "1.0.1",
35+
"@emoji-mart/react": "1.1.1",
3636
"@emotion/css": "11.11.2",
3737
"@emotion/react": "11.11.1",
3838
"@emotion/styled": "11.11.0",

site/pnpm-lock.yaml

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

site/src/@types/emoji-mart.d.ts

+37-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,42 @@
11
declare module "@emoji-mart/react" {
2-
const Picker: React.FC<{
2+
interface CustomCategory {
3+
id: string;
4+
name: string;
5+
emojis: CustomEmoji[];
6+
}
7+
8+
interface CustomEmoji {
9+
id: string;
10+
name: string;
11+
keywords: string[];
12+
skins: CustomEmojiSkin[];
13+
}
14+
15+
interface CustomEmojiSkin {
16+
src: string;
17+
}
18+
19+
type EmojiData = EmojiResource & {
20+
id: string;
21+
keywords: string[];
22+
name: string;
23+
native?: string;
24+
shortcodes: string;
25+
};
26+
27+
type EmojiResource =
28+
| { unified: undefined; src: string }
29+
| { unified: string; src: undefined };
30+
31+
const EmojiPicker: React.FC<{
32+
set: "native" | "apple" | "facebook" | "google" | "twitter";
333
theme: "dark" | "light";
4-
data: Record<string, unknown>;
5-
onEmojiSelect: (emojiData: { unified: string }) => void;
34+
data: unknown;
35+
custom: CustomCategory[];
36+
emojiButtonSize?: number;
37+
emojiSize?: number;
38+
onEmojiSelect: (emoji: EmojiData) => void;
639
}>;
740

8-
export default Picker;
41+
export default EmojiPicker;
942
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { action } from "@storybook/addon-actions";
2+
import IconField from "./IconField";
3+
import type { Meta, StoryObj } from "@storybook/react";
4+
5+
const meta: Meta<typeof IconField> = {
6+
title: "components/IconField",
7+
component: IconField,
8+
args: {
9+
onPickEmoji: action("onPickEmoji"),
10+
},
11+
};
12+
13+
export default meta;
14+
type Story = StoryObj<typeof IconField>;
15+
16+
export const Example: Story = {};
17+
18+
export const EmojiSelected: Story = {
19+
args: {
20+
value: "/emojis/1f3f3-fe0f-200d-26a7-fe0f.png",
21+
},
22+
};
23+
24+
export const IconSelected: Story = {
25+
args: {
26+
value: "/icon/fedora.svg",
27+
},
28+
};

site/src/components/IconField/IconField.tsx

+34-10
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,40 @@ import Button from "@mui/material/Button";
22
import InputAdornment from "@mui/material/InputAdornment";
33
import Popover from "@mui/material/Popover";
44
import TextField, { TextFieldProps } from "@mui/material/TextField";
5-
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
6-
import { useRef, FC, useState } from "react";
7-
import Picker from "@emoji-mart/react";
85
import { makeStyles } from "@mui/styles";
6+
import Picker from "@emoji-mart/react";
7+
import { useRef, FC, useState } from "react";
8+
import { DropdownArrow } from "components/DropdownArrow/DropdownArrow";
9+
import { Stack } from "components/Stack/Stack";
910
import { colors } from "theme/colors";
1011
import data from "@emoji-mart/data/sets/14/twitter.json";
11-
import { Stack } from "components/Stack/Stack";
12+
import icons from "theme/icons.json";
13+
14+
// See: https://github.com/missive/emoji-mart/issues/51#issuecomment-287353222
15+
const urlFromUnifiedCode = (unified: string) =>
16+
`/emojis/${unified.replace(/-fe0f$/, "")}.png`;
1217

1318
type IconFieldProps = TextFieldProps & {
1419
onPickEmoji: (value: string) => void;
1520
};
1621

22+
const custom = [
23+
{
24+
id: "icons",
25+
name: "Icons",
26+
emojis: icons.map((icon) => {
27+
const id = icon.split(".")[0];
28+
29+
return {
30+
id,
31+
name: id,
32+
keywords: id.split("-"),
33+
skins: [{ src: `/icon/${icon}` }],
34+
};
35+
}),
36+
},
37+
];
38+
1739
const IconField: FC<IconFieldProps> = ({ onPickEmoji, ...textFieldProps }) => {
1840
if (
1941
typeof textFieldProps.value !== "string" &&
@@ -69,14 +91,12 @@ const IconField: FC<IconFieldProps> = ({ onPickEmoji, ...textFieldProps }) => {
6991
}}
7092
>
7193
<Picker
94+
set="twitter"
7295
theme="dark"
7396
data={data}
74-
onEmojiSelect={(emojiData) => {
75-
// See: https://github.com/missive/emoji-mart/issues/51#issuecomment-287353222
76-
const value = `/emojis/${emojiData.unified.replace(
77-
/-fe0f$/,
78-
"",
79-
)}.png`;
97+
custom={custom}
98+
onEmojiSelect={(emoji) => {
99+
const value = emoji.src ?? urlFromUnifiedCode(emoji.unified);
80100
onPickEmoji(value);
81101
setIsEmojiPickerOpen(false);
82102
}}
@@ -92,6 +112,9 @@ const useStyles = makeStyles((theme) => ({
92112
"--rgb-background": theme.palette.background.paper,
93113
"--rgb-input": colors.gray[17],
94114
"--rgb-color": colors.gray[4],
115+
116+
// Hack to prevent the right side from being cut off
117+
width: 350,
95118
},
96119
},
97120
adornment: {
@@ -103,6 +126,7 @@ const useStyles = makeStyles((theme) => ({
103126

104127
"& img": {
105128
maxWidth: "100%",
129+
objectFit: "contain",
106130
},
107131
},
108132
}));

site/src/components/IconField/LazyIconField.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { lazy, Suspense, ComponentProps } from "react";
1+
import { lazy, Suspense, type ComponentProps } from "react";
22

33
const IconField = lazy(() => import("./IconField"));
44

site/static/icon/android-studio.svg

+1-1
Loading

site/static/icon/azure-devops.svg

+1-1
Loading

site/static/icon/bitbucket.svg

+1-1
Loading

site/static/icon/clion.svg

+1-1
Loading

site/static/icon/code.svg

+1-1
Loading

site/static/icon/conda.svg

+2-1
Loading

0 commit comments

Comments
 (0)