diff --git a/src/app/organisms/emoji-board/EmojiBoard.jsx b/src/app/organisms/emoji-board/EmojiBoard.jsx
index d976232..84c4130 100644
--- a/src/app/organisms/emoji-board/EmojiBoard.jsx
+++ b/src/app/organisms/emoji-board/EmojiBoard.jsx
@@ -13,6 +13,7 @@ import cons from '../../../client/state/cons';
import navigation from '../../../client/state/navigation';
import AsyncSearch from '../../../util/AsyncSearch';
import { addRecentEmoji, getRecentEmojis } from './recent';
+import { TWEMOJI_BASE_URL } from '../../../util/twemojify';
import Text from '../../atoms/text/Text';
import RawIcon from '../../atoms/system-icons/RawIcon';
@@ -46,45 +47,49 @@ const EmojiGroup = React.memo(({ name, groupEmojis }) => {
const emoji = groupEmojis[emojiIndex];
emojiRow.push(
- {
- emoji.hexcode
- // This is a unicode emoji, and should be rendered with twemoji
- ? parse(twemoji.parse(
- emoji.unicode,
- {
- attributes: () => ({
- unicode: emoji.unicode,
- shortcodes: emoji.shortcodes?.toString(),
- hexcode: emoji.hexcode,
- loading: 'lazy',
- }),
- },
- ))
- // This is a custom emoji, and should be render as an mxc
- : (
-
- )
- }
- ,
+ {emoji.hexcode ? (
+ // This is a unicode emoji, and should be rendered with twemoji
+ parse(
+ twemoji.parse(emoji.unicode, {
+ attributes: () => ({
+ unicode: emoji.unicode,
+ shortcodes: emoji.shortcodes?.toString(),
+ hexcode: emoji.hexcode,
+ loading: 'lazy',
+ }),
+ base: TWEMOJI_BASE_URL,
+ })
+ )
+ ) : (
+ // This is a custom emoji, and should be render as an mxc
+
+ )}
+
);
}
- emojiBoard.push(
{emojiRow}
);
+ emojiBoard.push(
+
+ {emojiRow}
+
+ );
}
return emojiBoard;
}
return (
-
{name}
+
+ {name}
+
{groupEmojis.length !== 0 &&
{getEmojiBoard()}
}
);
@@ -92,17 +97,16 @@ const EmojiGroup = React.memo(({ name, groupEmojis }) => {
EmojiGroup.propTypes = {
name: PropTypes.string.isRequired,
- groupEmojis: PropTypes.arrayOf(PropTypes.shape({
- length: PropTypes.number,
- unicode: PropTypes.string,
- hexcode: PropTypes.string,
- mxc: PropTypes.string,
- shortcode: PropTypes.string,
- shortcodes: PropTypes.oneOfType([
- PropTypes.string,
- PropTypes.arrayOf(PropTypes.string),
- ]),
- })).isRequired,
+ groupEmojis: PropTypes.arrayOf(
+ PropTypes.shape({
+ length: PropTypes.number,
+ unicode: PropTypes.string,
+ hexcode: PropTypes.string,
+ mxc: PropTypes.string,
+ shortcode: PropTypes.string,
+ shortcodes: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
+ })
+ ).isRequired,
};
const asyncSearch = new AsyncSearch();
@@ -128,7 +132,13 @@ function SearchedEmoji() {
if (searchedEmojis === null) return false;
- return ;
+ return (
+
+ );
}
function EmojiBoard({ onSelect, searchRef }) {
@@ -146,7 +156,10 @@ function EmojiBoard({ onSelect, searchRef }) {
if (typeof shortcodes === 'undefined') shortcodes = undefined;
else shortcodes = shortcodes.split(',');
return {
- unicode, hexcode, shortcodes, mxc,
+ unicode,
+ hexcode,
+ shortcodes,
+ mxc,
};
}
@@ -211,10 +224,9 @@ function EmojiBoard({ onSelect, searchRef }) {
const parentIds = initMatrix.roomList.getAllParentSpaces(room.roomId);
const parentRooms = [...parentIds].map((id) => mx.getRoom(id));
if (room) {
- const packs = getRelevantPacks(
- room.client,
- [room, ...parentRooms],
- ).filter((pack) => pack.getEmojis().length !== 0);
+ const packs = getRelevantPacks(room.client, [room, ...parentRooms]).filter(
+ (pack) => pack.getEmojis().length !== 0
+ );
// Set an index for each pack so that we know where to jump when the user uses the nav
for (let i = 0; i < packs.length; i += 1) {
@@ -263,44 +275,41 @@ function EmojiBoard({ onSelect, searchRef }) {
/>
)}
- {
- availableEmojis.map((pack) => {
- const src = initMatrix.matrixClient
- .mxcUrlToHttp(pack.avatarUrl ?? pack.getEmojis()[0].mxc);
- return (
- openGroup(recentOffset + pack.packIndex)}
- src={src}
- key={pack.packIndex}
- tooltip={pack.displayName ?? 'Unknown'}
- tooltipPlacement="left"
- isImage
- />
- );
- })
- }
+ {availableEmojis.map((pack) => {
+ const src = initMatrix.matrixClient.mxcUrlToHttp(
+ pack.avatarUrl ?? pack.getEmojis()[0].mxc
+ );
+ return (
+ openGroup(recentOffset + pack.packIndex)}
+ src={src}
+ key={pack.packIndex}
+ tooltip={pack.displayName ?? 'Unknown'}
+ tooltipPlacement="left"
+ isImage
+ />
+ );
+ })}
- {
- [
- [0, EmojiIC, 'Smilies'],
- [1, DogIC, 'Animals'],
- [2, CupIC, 'Food'],
- [3, BallIC, 'Activities'],
- [4, PhotoIC, 'Travel'],
- [5, BulbIC, 'Objects'],
- [6, PeaceIC, 'Symbols'],
- [7, FlagIC, 'Flags'],
- ].map(([indx, ico, name]) => (
- openGroup(recentOffset + availableEmojis.length + indx)}
- key={indx}
- src={ico}
- tooltip={name}
- tooltipPlacement="left"
- />
- ))
- }
+ {[
+ [0, EmojiIC, 'Smilies'],
+ [1, DogIC, 'Animals'],
+ [2, CupIC, 'Food'],
+ [3, BallIC, 'Activities'],
+ [4, PhotoIC, 'Travel'],
+ [5, BulbIC, 'Objects'],
+ [6, PeaceIC, 'Symbols'],
+ [7, FlagIC, 'Flags'],
+ ].map(([indx, ico, name]) => (
+ openGroup(recentOffset + availableEmojis.length + indx)}
+ key={indx}
+ src={ico}
+ tooltip={name}
+ tooltipPlacement="left"
+ />
+ ))}
@@ -313,27 +322,25 @@ function EmojiBoard({ onSelect, searchRef }) {
- {recentEmojis.length > 0 && }
- {
- availableEmojis.map((pack) => (
-
- ))
- }
- {
- emojiGroups.map((group) => (
-
- ))
- }
+ {recentEmojis.length > 0 && (
+
+ )}
+ {availableEmojis.map((pack) => (
+
+ ))}
+ {emojiGroups.map((group) => (
+
+ ))}
-
{ parse(twemoji.parse('🙂')) }
+
{parse(twemoji.parse('🙂', { base: TWEMOJI_BASE_URL }))}
:slight_smile:
diff --git a/src/app/organisms/room/RoomViewCmdBar.jsx b/src/app/organisms/room/RoomViewCmdBar.jsx
index 8c390a0..0d21123 100644
--- a/src/app/organisms/room/RoomViewCmdBar.jsx
+++ b/src/app/organisms/room/RoomViewCmdBar.jsx
@@ -5,7 +5,7 @@ import './RoomViewCmdBar.scss';
import parse from 'html-react-parser';
import twemoji from 'twemoji';
-import { twemojify } from '../../../util/twemojify';
+import { twemojify, TWEMOJI_BASE_URL } from '../../../util/twemojify';
import initMatrix from '../../../client/initMatrix';
import { getEmojiForCompletion } from '../emoji-board/custom-emoji';
@@ -31,7 +31,7 @@ CmdItem.propTypes = {
function renderSuggestions({ prefix, option, suggestions }, fireCmd) {
function renderCmdSuggestions(cmdPrefix, cmds) {
- const cmdOptString = (typeof option === 'string') ? `/${option}` : '/?';
+ const cmdOptString = typeof option === 'string' ? `/${option}` : '/?';
return cmds.map((cmd) => (
({
unicode: emoji.unicode,
shortcodes: emoji.shortcodes?.toString(),
}),
- },
- ));
+ base: TWEMOJI_BASE_URL,
+ })
+ );
}
// Render a custom emoji
@@ -87,10 +87,12 @@ function renderSuggestions({ prefix, option, suggestions }, fireCmd) {
return emos.map((emoji) => (
fireCmd({
- prefix: emPrefix,
- result: emoji,
- })}
+ onClick={() =>
+ fireCmd({
+ prefix: emPrefix,
+ result: emoji,
+ })
+ }
>
{renderEmoji(emoji)}
{`:${emoji.shortcode}:`}
@@ -187,10 +189,13 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
});
},
'@': () => {
- const members = mx.getRoom(roomId).getJoinedMembers().map((member) => ({
- name: member.name,
- userId: member.userId.slice(1),
- }));
+ const members = mx
+ .getRoom(roomId)
+ .getJoinedMembers()
+ .map((member) => ({
+ name: member.name,
+ userId: member.userId.slice(1),
+ }));
asyncSearch.setup(members, { keys: ['name', 'userId'], limit: 20 });
const endIndex = members.length > 20 ? 20 : members.length;
setCmd({ prefix, suggestions: members.slice(0, endIndex) });
@@ -277,9 +282,7 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
-
- { renderSuggestions(cmd, fireCmd) }
-
+ {renderSuggestions(cmd, fireCmd)}
diff --git a/src/util/twemojify.jsx b/src/util/twemojify.jsx
index 0a4fede..abe82a6 100644
--- a/src/util/twemojify.jsx
+++ b/src/util/twemojify.jsx
@@ -6,6 +6,8 @@ import parse from 'html-react-parser';
import twemoji from 'twemoji';
import { sanitizeText } from './sanitize';
+export const TWEMOJI_BASE_URL = 'https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/';
+
const Math = lazy(() => import('../app/atoms/math/Math'));
const mathOptions = {
@@ -38,11 +40,16 @@ const mathOptions = {
export function twemojify(text, opts, linkify = false, sanitize = true, maths = false) {
if (typeof text !== 'string') return text;
let content = text;
+ const options = opts ?? { base: TWEMOJI_BASE_URL };
+ if (!options.base) {
+ options.base = TWEMOJI_BASE_URL;
+ }
if (sanitize) {
content = sanitizeText(content);
}
- content = twemoji.parse(content, opts);
+
+ content = twemoji.parse(content, options);
if (linkify) {
content = linkifyHtml(content, {
target: '_blank',