@mojis/skin-tone
Version:
utilities to work with emoji skin tones
82 lines (80 loc) • 2.74 kB
JavaScript
// src/index.ts
var FITZPATRICK_SCALE = /* @__PURE__ */ new Map([
["none", ""],
["light", "\u{1F3FB}"],
["medium-light", "\u{1F3FC}"],
["medium", "\u{1F3FD}"],
["medium-dark", "\u{1F3FE}"],
["dark", "\u{1F3FF}"]
]);
var EMOJI_PRESENTATION_SELECTOR = "\uFE0F";
var TWO_FAMILY_EMOJIS = /* @__PURE__ */ new Set(["\u{1F469}\u200D\u{1F466}", "\u{1F469}\u200D\u{1F467}", "\u{1F468}\u200D\u{1F467}", "\u{1F468}\u200D\u{1F466}"]);
function setSkinTone(emoji, tone) {
if (!FITZPATRICK_SCALE.has(tone)) {
throw new Error(`invalid skin tone: ${tone}`);
}
emoji = emoji.replace(/[\u{1F3FB}-\u{1F3FF}]/gu, "");
const EMOJI_MODIFIER_BASE_REGEX = /\p{Emoji_Modifier_Base}/gu;
if (tone === "none" || (emoji.match(EMOJI_MODIFIER_BASE_REGEX)?.length ?? 0) > 2 || TWO_FAMILY_EMOJIS.has(emoji)) {
return emoji;
}
let processedEmoji = "";
for (const codePoint of emoji) {
if (codePoint === EMOJI_PRESENTATION_SELECTOR) {
continue;
}
processedEmoji += codePoint;
if (EMOJI_MODIFIER_BASE_REGEX.test(codePoint)) {
processedEmoji += FITZPATRICK_SCALE.get(tone);
}
}
return processedEmoji;
}
function setSkinTones(emoji, tones) {
if (tones.some((tone) => !FITZPATRICK_SCALE.has(tone))) {
throw new Error(`invalid skin tone in: ${tones.join(", ")}`);
}
emoji = emoji.replace(/[\u{1F3FB}-\u{1F3FF}]/gu, "");
const EMOJI_MODIFIER_BASE_REGEX = /\p{Emoji_Modifier_Base}/gu;
if (!tones.length || tones.every((tone) => tone === "none") || (emoji.match(EMOJI_MODIFIER_BASE_REGEX)?.length ?? 0) > 2 || TWO_FAMILY_EMOJIS.has(emoji)) {
return emoji;
}
let processedEmoji = "";
let toneIndex = 0;
for (const codePoint of emoji) {
if (codePoint === EMOJI_PRESENTATION_SELECTOR) {
continue;
}
processedEmoji += codePoint;
if (EMOJI_MODIFIER_BASE_REGEX.test(codePoint)) {
const currentTone = tones[toneIndex % tones.length];
if (currentTone == null) continue;
processedEmoji += FITZPATRICK_SCALE.get(currentTone);
toneIndex++;
}
}
return processedEmoji;
}
function getSkinTone(emoji) {
const SKIN_TONE_REGEX = /[\u{1F3FB}-\u{1F3FF}]/gu;
const match = emoji.match(SKIN_TONE_REGEX);
if (match && match.length > 0) {
const tones = [];
for (const skinToneModifier of match) {
for (const [tone, modifier] of FITZPATRICK_SCALE.entries()) {
if (modifier === skinToneModifier) {
tones.push(tone);
}
}
}
if (tones.length === 1 && tones[0] != null) {
return tones[0];
}
return tones;
}
return "none";
}
function hasSkinTone(emoji) {
return getSkinTone(emoji) !== "none";
}
export { FITZPATRICK_SCALE, getSkinTone, hasSkinTone, setSkinTone, setSkinTones };