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/emoji_pretty.json",
"!node_modules/emoji-datasource/*.png", "!node_modules/emoji-datasource/*.png",
"!node_modules/emoji-datasource-apple/emoji_pretty.json", "!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*",
"!node_modules/emoji-datasource-apple/img/apple/sheets-256/{16,20,32}.png",
"!node_modules/spellchecker/vendor/hunspell/**/*", "!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/*/{CHANGELOG.md,README.md,README,readme.md,readme,test,__tests__,tests,powered-test,example,examples,*.d.ts}",
"!**/node_modules/.bin", "!**/node_modules/.bin",

View file

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

View file

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

View file

@ -1,6 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { getSheetCoordinates, SkinToneKey } from './lib'; import { getImagePath, SkinToneKey } from './lib';
export type OwnProps = { export type OwnProps = {
inline?: boolean; inline?: boolean;
@ -18,9 +18,7 @@ export const Emoji = React.memo(
{ style = {}, size = 28, shortName, skinTone, inline, className }: Props, { style = {}, size = 28, shortName, skinTone, inline, className }: Props,
ref ref
) => { ) => {
const [sheetX, sheetY] = getSheetCoordinates(shortName, skinTone); const image = getImagePath(shortName, skinTone);
const x = -(size * sheetX);
const y = -(size * sheetY);
return ( return (
<div <div
@ -31,12 +29,14 @@ export const Emoji = React.memo(
inline ? 'module-emoji--inline' : null, inline ? 'module-emoji--inline' : null,
className className
)} )}
style={{ style={style}
...style, >
backgroundPositionX: `${x}px`, <img
backgroundPositionY: `${y}px`, 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 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 = { export type EmojiData = {
name: string; name: string;
unified: string; unified: string;
@ -43,24 +58,36 @@ export type EmojiData = {
has_img_facebook: boolean; has_img_facebook: boolean;
has_img_messenger: boolean; has_img_messenger: boolean;
skin_variations?: { skin_variations?: {
[key: string]: { [key: string]: 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;
};
}; };
}; };
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'); export const dataByShortName = keyBy(data, 'short_name');
@ -112,20 +139,28 @@ export const dataByCategory = mapValues(
arr => sortBy(arr, 'sort_order') arr => sortBy(arr, 'sort_order')
); );
export function getSheetCoordinates( export function getEmojiData(
shortName: keyof typeof dataByShortName, shortName: keyof typeof dataByShortName,
skinTone?: SkinToneKey | number skinTone?: SkinToneKey | number
): [number, number] { ): EmojiData | EmojiSkinVariation {
const base = dataByShortName[shortName]; const base = dataByShortName[shortName];
if (skinTone && base.skin_variations) { if (skinTone && base.skin_variations) {
const variation = isNumber(skinTone) ? skinTones[skinTone - 1] : skinTone; 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, { const fuse = new Fuse(data, {