Add Emoji functional component

merge-requests/1161/head
Alex Gleason 2022-03-31 20:32:53 -05:00
rodzic ee1ef09201
commit 52982706fe
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
3 zmienionych plików z 61 dodań i 8 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
import emojify from 'soapbox/features/emoji/emoji';
import { Emoji } from 'soapbox/components/ui';
import type { List as ImmutableList } from 'immutable';
import type { RootState } from 'soapbox/store';
@ -109,12 +109,9 @@ class EmojiSelector extends ImmutablePureComponent<IEmojiSelector> {
const { visible, focused, allowedEmoji } = this.props;
return (
<HotKeys
handlers={this.handlers}
className='emoji-react-selector-container'
>
<HotKeys handlers={this.handlers}>
<div
className={classNames('emoji-react-selector w-max', { 'emoji-react-selector--visible': visible, 'emoji-react-selector--focused': focused })}
className={classNames('flex absolute bg-white dark:bg-slate-500 px-2 py-3 rounded-full shadow-md opacity-0 pointer-events-none duration-100 w-max', { 'opacity-100 pointer-events-auto z-[999]': visible || focused })}
onBlur={this.handleBlur}
ref={this.setRef}
>
@ -122,11 +119,12 @@ class EmojiSelector extends ImmutablePureComponent<IEmojiSelector> {
<button
key={i}
className='emoji-react-selector__emoji'
dangerouslySetInnerHTML={{ __html: emojify(emoji) }}
onClick={this.handleReact(emoji)}
onKeyDown={this.handleKeyDown(i)}
tabIndex={(visible || focused) ? 0 : -1}
/>
>
<Emoji emoji={emoji} />
</button>
))}
</div>
</HotKeys>

Wyświetl plik

@ -0,0 +1,54 @@
import classNames from 'classnames';
import React from 'react';
import { joinPublicPath } from 'soapbox/utils/static';
// Taken from twemoji-parser
// https://github.com/twitter/twemoji-parser/blob/a97ef3994e4b88316812926844d51c296e889f76/src/index.js
const removeVS16s = (rawEmoji: string): string => {
const vs16RegExp = /\uFE0F/g;
const zeroWidthJoiner = String.fromCharCode(0x200d);
return rawEmoji.indexOf(zeroWidthJoiner) < 0 ? rawEmoji.replace(vs16RegExp, '') : rawEmoji;
};
const toCodePoints = (unicodeSurrogates: string): string[] => {
const points = [];
let char = 0;
let previous = 0;
let i = 0;
while (i < unicodeSurrogates.length) {
char = unicodeSurrogates.charCodeAt(i++);
if (previous) {
points.push((0x10000 + ((previous - 0xd800) << 10) + (char - 0xdc00)).toString(16));
previous = 0;
} else if (char > 0xd800 && char <= 0xdbff) {
previous = char;
} else {
points.push(char.toString(16));
}
}
return points;
};
interface IEmoji {
className?: string,
emoji: string,
}
const Emoji: React.FC<IEmoji> = ({ className, emoji }): JSX.Element | null => {
const codepoints = toCodePoints(removeVS16s(emoji));
const filename = codepoints.join('-');
if (!filename) return null;
return (
<img
draggable='false'
className={classNames('emojione', className)}
alt={emoji}
src={joinPublicPath(`packs/emoji/${filename}.svg`)}
/>
);
};
export default Emoji;

Wyświetl plik

@ -2,6 +2,7 @@ export { default as Avatar } from './avatar/avatar';
export { default as Button } from './button/button';
export { Card, CardBody, CardHeader, CardTitle } from './card/card';
export { default as Column } from './column/column';
export { default as Emoji } from './emoji/emoji';
export { default as Form } from './form/form';
export { default as FormActions } from './form-actions/form-actions';
export { default as FormGroup } from './form-group/form-group';