UNPKG

@mojis/skin-tone

Version:

utilities to work with emoji skin tones

82 lines (80 loc) 2.74 kB
// 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 };