Use individual images in emoji picker rather than a spritesheet

This commit is contained in:
Ken Powers 2019-06-17 14:46:42 -04:00 committed by Scott Nonnenberg
parent cc7b9da0cf
commit dcf6a5f59c
5 changed files with 80 additions and 36 deletions

View file

@ -276,8 +276,7 @@
"!node_modules/emoji-datasource/emoji_pretty.json",
"!node_modules/emoji-datasource/*.png",
"!node_modules/emoji-datasource-apple/emoji_pretty.json",
"!node_modules/emoji-datasource-apple/img/apple/{sheets,sheets-128}/*.png",
"!node_modules/emoji-datasource-apple/img/apple/sheets-256/{16,20,32}.png",
"!node_modules/emoji-datasource-apple/img/apple/sheets*",
"!node_modules/spellchecker/vendor/hunspell/**/*",
"!**/node_modules/*/{CHANGELOG.md,README.md,README,readme.md,readme,test,__tests__,tests,powered-test,example,examples,*.d.ts}",
"!**/node_modules/.bin",

View file

@ -4424,17 +4424,20 @@
}
// Module: Emoji
@mixin emoji-size($size, $emoji-sheet-columns: 52) {
@mixin emoji-size($size) {
&--#{$size} {
width: $size;
height: $size;
background-size: $emoji-sheet-columns * $size;
}
&__image--#{$size} {
width: $size;
height: $size;
transform: translate3d(0, 0, 0);
}
}
.module-emoji {
display: block;
background-image: url('../node_modules/emoji-datasource-apple/img/apple/sheets-256/64.png');
@include emoji-size(16px);
@include emoji-size(20px);

View file

@ -28,12 +28,19 @@ function getImageTag({
const result = getReplacementData(match[0], match[1], match[2]);
if (is.string(result)) {
return <span key={key}>{match[0]}</span>;
return match[0];
}
const img = findImage(result.value, result.variation);
const title = getTitle(result.value);
if (
!img.path ||
!img.path.startsWith('node_modules/emoji-datasource-apple')
) {
return match[0];
}
return (
// tslint:disable-next-line react-a11y-img-has-alt
<img

View file

@ -1,6 +1,6 @@
import * as React from 'react';
import classNames from 'classnames';
import { getSheetCoordinates, SkinToneKey } from './lib';
import { getImagePath, SkinToneKey } from './lib';
export type OwnProps = {
inline?: boolean;
@ -18,9 +18,7 @@ export const Emoji = React.memo(
{ style = {}, size = 28, shortName, skinTone, inline, className }: Props,
ref
) => {
const [sheetX, sheetY] = getSheetCoordinates(shortName, skinTone);
const x = -(size * sheetX);
const y = -(size * sheetY);
const image = getImagePath(shortName, skinTone);
return (
<div
@ -31,12 +29,14 @@ export const Emoji = React.memo(
inline ? 'module-emoji--inline' : null,
className
)}
style={{
...style,
backgroundPositionX: `${x}px`,
backgroundPositionY: `${y}px`,
}}
/>
style={style}
>
<img
className={`module-emoji__image--${size}px`}
src={image}
alt={shortName}
/>
</div>
);
}
)

View file

@ -18,6 +18,21 @@ export const skinTones = ['1F3FB', '1F3FC', '1F3FD', '1F3FE', '1F3FF'];
export type SkinToneKey = '1F3FB' | '1F3FC' | '1F3FD' | '1F3FE' | '1F3FF';
export type EmojiSkinVariation = {
unified: string;
non_qualified: null;
image: string;
sheet_x: number;
sheet_y: number;
added_in: string;
has_img_apple: boolean;
has_img_google: boolean;
has_img_twitter: boolean;
has_img_emojione: boolean;
has_img_facebook: boolean;
has_img_messenger: boolean;
};
export type EmojiData = {
name: string;
unified: string;
@ -43,24 +58,36 @@ export type EmojiData = {
has_img_facebook: boolean;
has_img_messenger: boolean;
skin_variations?: {
[key: string]: {
unified: string;
non_qualified: null;
image: string;
sheet_x: number;
sheet_y: number;
added_in: string;
has_img_apple: boolean;
has_img_google: boolean;
has_img_twitter: boolean;
has_img_emojione: boolean;
has_img_facebook: boolean;
has_img_messenger: boolean;
};
[key: string]: EmojiSkinVariation;
};
};
const data: Array<EmojiData> = untypedData;
const data = (untypedData as Array<EmojiData>).filter(
emoji => emoji.has_img_apple
);
const makeImagePath = (src: string) => {
return `node_modules/emoji-datasource-apple/img/apple/64/${src}`;
};
export const images = new Set();
// Preload images
const preload = (src: string) => {
const img = new Image();
img.src = src;
images.add(img);
};
data.forEach(emoji => {
preload(makeImagePath(emoji.image));
if (emoji.skin_variations) {
Object.values(emoji.skin_variations).forEach(variation => {
preload(makeImagePath(variation.image));
});
}
});
export const dataByShortName = keyBy(data, 'short_name');
@ -112,20 +139,28 @@ export const dataByCategory = mapValues(
arr => sortBy(arr, 'sort_order')
);
export function getSheetCoordinates(
export function getEmojiData(
shortName: keyof typeof dataByShortName,
skinTone?: SkinToneKey | number
): [number, number] {
): EmojiData | EmojiSkinVariation {
const base = dataByShortName[shortName];
if (skinTone && base.skin_variations) {
const variation = isNumber(skinTone) ? skinTones[skinTone - 1] : skinTone;
const { sheet_x, sheet_y } = base.skin_variations[variation];
return [sheet_x, sheet_y];
return base.skin_variations[variation];
}
return [base.sheet_x, base.sheet_y];
return base;
}
export function getImagePath(
shortName: keyof typeof dataByShortName,
skinTone?: SkinToneKey | number
): string {
const { image } = getEmojiData(shortName, skinTone);
return makeImagePath(image);
}
const fuse = new Fuse(data, {