Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support skin tones for 🧑‍🤝‍🧑 emoji #262

Merged
merged 1 commit into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion db/emoji.json
Original file line number Diff line number Diff line change
Expand Up @@ -6416,7 +6416,7 @@
]
, "unicode_version": "12.0"
, "ios_version": "13.0"
, "skin_tones": false
, "skin_tones": true
}
, {
"emoji": "👭"
Expand Down
23 changes: 17 additions & 6 deletions lib/emoji/character.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,20 @@ def add_alias(name)
# Raw Unicode string for an emoji. Nil if emoji is non-standard.
def raw() unicode_aliases.first end

# Raw Unicode strings for each skin tone variant of this emoji.
# Raw Unicode strings for each skin tone variant of this emoji. The result is an empty array
# unless the emoji supports skin tones.
#
# Note: for emojis that depict multiple people (e.g. couples or families), this will not produce
# every possible permutation of skin tone per person.
def raw_skin_tone_variants
return [] if custom? || !skin_tones?
raw_normalized = raw.sub("\u{fe0f}", "") # strip VARIATION_SELECTOR_16
idx = raw_normalized.index("\u{200d}") # detect zero-width joiner
raw_normalized = raw.sub(VARIATION_SELECTOR_16, "")
idx = raw_normalized.index(ZERO_WIDTH_JOINER)
SKIN_TONES.map do |modifier|
if idx
if raw_normalized == PEOPLE_HOLDING_HANDS
# special case to apply the modifier to both persons
raw_normalized[0...idx] + modifier + raw_normalized[idx..nil] + modifier
elsif idx
# insert modifier before zero-width joiner
raw_normalized[0...idx] + modifier + raw_normalized[idx..nil]
else
Expand Down Expand Up @@ -97,7 +104,11 @@ def image_filename
end

private


VARIATION_SELECTOR_16 = "\u{fe0f}".freeze
ZERO_WIDTH_JOINER = "\u{200d}".freeze
PEOPLE_HOLDING_HANDS = "\u{1f9d1}\u{200d}\u{1f91d}\u{200d}\u{1f9d1}".freeze

SKIN_TONES = [
"\u{1F3FB}", # light skin tone
"\u{1F3FC}", # medium-light skin tone
Expand All @@ -106,7 +117,7 @@ def image_filename
"\u{1F3FF}", # dark skin tone
]

private_constant :SKIN_TONES
private_constant :VARIATION_SELECTOR_16, :ZERO_WIDTH_JOINER, :PEOPLE_HOLDING_HANDS, :SKIN_TONES

def default_image_filename
if custom?
Expand Down
9 changes: 9 additions & 0 deletions test/emoji_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,15 @@ class EmojiTest < TestCase
"1f9d4-1f3fe-200d-2640",
"1f9d4-1f3ff-200d-2640",
], woman_with_beard.raw_skin_tone_variants.map { |u| Emoji::Character.hex_inspect(u) }

people_holding_hands = Emoji.find_by_alias("people_holding_hands")
assert_equal [
"1f9d1-1f3fb-200d-1f91d-200d-1f9d1-1f3fb",
"1f9d1-1f3fc-200d-1f91d-200d-1f9d1-1f3fc",
"1f9d1-1f3fd-200d-1f91d-200d-1f9d1-1f3fd",
"1f9d1-1f3fe-200d-1f91d-200d-1f9d1-1f3fe",
"1f9d1-1f3ff-200d-1f91d-200d-1f9d1-1f3ff",
], people_holding_hands.raw_skin_tone_variants.map { |u| Emoji::Character.hex_inspect(u) }
end

test "no custom emojis" do
Expand Down