| 1 | // Emoji shortcode interpolation: ":tada:" โ "๐". A curated set of the common |
| 2 | // ones (not the full ~1800 โ smaller and less obscure for a family/kids' chat). |
| 3 | // Pure + framework-free so it's unit-testable in Node. Replacement happens on |
| 4 | // send, so the encrypted message stores the real emoji and renders natively |
| 5 | // everywhere (bubbles, previews, notifications). Only known names convert, so |
| 6 | // URLs and times like 10:30 are left alone. Easily extended โ just add entries. |
| 7 | export const EMOJI = { |
| 8 | // smileys & emotion |
| 9 | grinning: "๐", smiley: "๐", smile: "๐", grin: "๐", laughing: "๐", satisfied: "๐", |
| 10 | sweat_smile: "๐
", rofl: "๐คฃ", joy: "๐", slightly_smiling_face: "๐", upside_down_face: "๐", |
| 11 | wink: "๐", blush: "๐", innocent: "๐", heart_eyes: "๐", star_struck: "๐คฉ", kissing_heart: "๐", |
| 12 | yum: "๐", stuck_out_tongue: "๐", stuck_out_tongue_winking_eye: "๐", zany_face: "๐คช", |
| 13 | money_mouth_face: "๐ค", hugs: "๐ค", thinking: "๐ค", shushing_face: "๐คซ", zipper_mouth_face: "๐ค", |
| 14 | neutral_face: "๐", expressionless: "๐", no_mouth: "๐ถ", smirk: "๐", unamused: "๐", |
| 15 | roll_eyes: "๐", grimacing: "๐ฌ", lying_face: "๐คฅ", relieved: "๐", pensive: "๐", sleepy: "๐ช", |
| 16 | sleeping: "๐ด", mask: "๐ท", face_with_thermometer: "๐ค", nauseated_face: "๐คข", vomiting: "๐คฎ", |
| 17 | sneezing_face: "๐คง", hot_face: "๐ฅต", cold_face: "๐ฅถ", woozy_face: "๐ฅด", dizzy_face: "๐ต", |
| 18 | exploding_head: "๐คฏ", cowboy_hat_face: "๐ค ", partying_face: "๐ฅณ", sunglasses: "๐", nerd_face: "๐ค", |
| 19 | confused: "๐", worried: "๐", frowning_face: "๐", open_mouth: "๐ฎ", hushed: "๐ฏ", astonished: "๐ฒ", |
| 20 | flushed: "๐ณ", pleading_face: "๐ฅบ", cry: "๐ข", sob: "๐ญ", scream: "๐ฑ", confounded: "๐", |
| 21 | persevere: "๐ฃ", disappointed: "๐", sweat: "๐", weary: "๐ฉ", tired_face: "๐ซ", yawning_face: "๐ฅฑ", |
| 22 | triumph: "๐ค", rage: "๐ก", angry: "๐ ", cursing_face: "๐คฌ", smiling_imp: "๐", imp: "๐ฟ", |
| 23 | skull: "๐", poop: "๐ฉ", hankey: "๐ฉ", clown_face: "๐คก", ghost: "๐ป", alien: "๐ฝ", robot: "๐ค", |
| 24 | // hearts & symbols |
| 25 | heart: "โค๏ธ", orange_heart: "๐งก", yellow_heart: "๐", green_heart: "๐", blue_heart: "๐", |
| 26 | purple_heart: "๐", black_heart: "๐ค", broken_heart: "๐", two_hearts: "๐", sparkling_heart: "๐", |
| 27 | heartbeat: "๐", heartpulse: "๐", cupid: "๐", gift_heart: "๐", "100": "๐ฏ", anger: "๐ข", |
| 28 | boom: "๐ฅ", collision: "๐ฅ", sweat_drops: "๐ฆ", dash: "๐จ", zzz: "๐ค", fire: "๐ฅ", star: "โญ", |
| 29 | star2: "๐", sparkles: "โจ", dizzy: "๐ซ", tada: "๐", confetti_ball: "๐", balloon: "๐", |
| 30 | gift: "๐", white_check_mark: "โ
", heavy_check_mark: "โ๏ธ", x: "โ", warning: "โ ๏ธ", question: "โ", |
| 31 | exclamation: "โ", bell: "๐", crown: "๐", gem: "๐", lock: "๐", key: "๐", bulb: "๐ก", |
| 32 | // hands & people |
| 33 | "+1": "๐", thumbsup: "๐", "-1": "๐", thumbsdown: "๐", ok_hand: "๐", punch: "๐", fist: "โ", |
| 34 | wave: "๐", raised_hands: "๐", clap: "๐", pray: "๐", muscle: "๐ช", point_up: "โ๏ธ", |
| 35 | point_down: "๐", point_left: "๐", point_right: "๐", v: "โ๏ธ", crossed_fingers: "๐ค", |
| 36 | handshake: "๐ค", writing_hand: "โ๏ธ", eyes: "๐", brain: "๐ง ", baby: "๐ถ", |
| 37 | shrug: "๐คท", facepalm: "๐คฆ", strong: "๐ช", lol: "๐", |
| 38 | // animals & nature |
| 39 | dog: "๐ถ", cat: "๐ฑ", mouse: "๐ญ", fox: "๐ฆ", bear: "๐ป", panda_face: "๐ผ", koala: "๐จ", |
| 40 | tiger: "๐ฏ", lion: "๐ฆ", cow: "๐ฎ", pig: "๐ท", frog: "๐ธ", monkey_face: "๐ต", chicken: "๐", |
| 41 | penguin: "๐ง", bird: "๐ฆ", unicorn: "๐ฆ", bee: "๐", bug: "๐", butterfly: "๐ฆ", snail: "๐", |
| 42 | turtle: "๐ข", fish: "๐", dolphin: "๐ฌ", whale: "๐ณ", paw_prints: "๐พ", sun: "โ๏ธ", cloud: "โ๏ธ", |
| 43 | rainbow: "๐", snowflake: "โ๏ธ", snowman: "โ", zap: "โก", umbrella: "โ", droplet: "๐ง", |
| 44 | ocean: "๐", christmas_tree: "๐", earth_africa: "๐", moon: "๐", |
| 45 | // food & drink |
| 46 | pizza: "๐", hamburger: "๐", fries: "๐", hotdog: "๐ญ", taco: "๐ฎ", popcorn: "๐ฟ", |
| 47 | doughnut: "๐ฉ", cookie: "๐ช", cake: "๐ฐ", birthday: "๐", icecream: "๐ฆ", candy: "๐ฌ", |
| 48 | lollipop: "๐ญ", chocolate_bar: "๐ซ", apple: "๐", banana: "๐", strawberry: "๐", |
| 49 | watermelon: "๐", grapes: "๐", avocado: "๐ฅ", coffee: "โ", tea: "๐ต", beer: "๐บ", |
| 50 | wine_glass: "๐ท", cocktail: "๐ธ", champagne: "๐พ", |
| 51 | // activity, objects & travel |
| 52 | soccer: "โฝ", basketball: "๐", football: "๐", baseball: "โพ", tennis: "๐พ", trophy: "๐", |
| 53 | medal: "๐
", dart: "๐ฏ", game_die: "๐ฒ", video_game: "๐ฎ", musical_note: "๐ต", notes: "๐ถ", |
| 54 | guitar: "๐ธ", microphone: "๐ค", headphones: "๐ง", art: "๐จ", camera: "๐ท", iphone: "๐ฑ", |
| 55 | computer: "๐ป", money_with_wings: "๐ธ", moneybag: "๐ฐ", dollar: "๐ต", mag: "๐", link: "๐", |
| 56 | pushpin: "๐", calendar: "๐
", memo: "๐", pencil: "๐", book: "๐", books: "๐", email: "โ๏ธ", |
| 57 | package: "๐ฆ", rocket: "๐", airplane: "โ๏ธ", car: "๐", bike: "๐ฒ", house: "๐ ", school: "๐ซ", |
| 58 | // flags & misc |
| 59 | checkered_flag: "๐", tada_alias: "๐", jack_o_lantern: "๐", santa: "๐
", |
| 60 | }; |
| 61 | |
| 62 | // emojiMatches ranks shortcodes for a typed ":query" (prefix hits first, then |
| 63 | // substring), returning up to `limit` { code, emoji } for the composer typeahead. |
| 64 | // De-dupes aliases that resolve to the same emoji (e.g. joy/laughing) โ keeping |
| 65 | // the first (shortest-name) match โ so the menu isn't full of duplicate glyphs. |
| 66 | export function emojiMatches(query, limit = 8) { |
| 67 | const q = String(query || "").toLowerCase(); |
| 68 | if (!q) return []; |
| 69 | const names = Object.keys(EMOJI).filter((n) => n.includes(q)); |
| 70 | names.sort((a, b) => { |
| 71 | const ap = a.startsWith(q) ? 0 : 1; |
| 72 | const bp = b.startsWith(q) ? 0 : 1; |
| 73 | return ap - bp || a.length - b.length || a.localeCompare(b); |
| 74 | }); |
| 75 | const out = []; |
| 76 | const seen = new Set(); |
| 77 | for (const code of names) { |
| 78 | if (seen.has(EMOJI[code])) continue; |
| 79 | seen.add(EMOJI[code]); |
| 80 | out.push({ code, emoji: EMOJI[code] }); |
| 81 | if (out.length >= limit) break; |
| 82 | } |
| 83 | return out; |
| 84 | } |
| 85 | |
| 86 | const SHORTCODE_RE = /:([a-z0-9_+-]+):/gi; |
| 87 | |
| 88 | // emojify replaces known :shortcodes: with their emoji, leaving unknown ones |
| 89 | // (and anything that isn't a :name: token) untouched. |
| 90 | export function emojify(text) { |
| 91 | if (text == null) return ""; |
| 92 | return String(text).replace(SHORTCODE_RE, (m, name) => EMOJI[name.toLowerCase()] || m); |
| 93 | } |
| 94 | |