sparkletown / sparkle

Building an open, community-owned hyperverse town
GNU Affero General Public License v3.0
33 stars 30 forks source link

chat: render emojis #1393

Closed yarikoptic closed 3 years ago

yarikoptic commented 3 years ago

emojis already used for reactions etc. But they are absent where IMHO most needed -- in the chat. I wonder if it might be easy to implement using e.g. https://www.npmjs.com/package/react-emoji-render to render chat messages? I think it would be ok to not have some fancy completions etc to start with and just rely on people to know to type :smile: or :)


Edit by @0xdevalias: See also https://github.com/sparkletown/sparkle/issues/1395 as a tightly related issue/feature.

0xdevalias commented 3 years ago

@yarikoptic Interesting you should raise this, as it's something I had looked into a bit and included on part of our backlog. I hadn't gone deep on making all of the decisions/explorations around this yet, but I'll include relevant snippets below (note: you won't be able to see any of the 'internal' issues that are linked)

See also my notes in https://github.com/sparkletown/sparkle/issues/1395#issuecomment-841594823 that refer to https://github.com/sparkletown/internal-sparkle-issues/issues/188#issuecomment-817416820


  1. Emoji support

Originally posted by @jess-sparkles in https://github.com/sparkletown/internal-sparkle-issues/issues/484#issuecomment-796006117


Some resources I stumbled across the other day, capturing here for posterity:

Originally posted by @0xdevalias in https://github.com/sparkletown/internal-sparkle-issues/issues/188#issuecomment-817416820

0xdevalias commented 3 years ago

@yarikoptic Given I was already thinking/planning about using emoji-mart when we came to implementing this feature, I wonder what react-emoji-render adds above/beyond that (if anything)?

Note that emoji-mart already seemingly contains a component for rendering emoji:

The last release of emoji-mart seems to have been in March 2019:

And will add 97.7kB (minified + gzipped) to the bundle size (before bundler optimisations/tree shaking/etc):

https://bundlephobia.com/result?p=emoji-mart@3.0.1


The last release of react-emoji-render seems to have been in December 2019:

And will add 35kB (minified + gzipped) to the bundle size (note that this doesn't appear to be tree shakeable):

It depends on a couple of packages, including emoji-regex:

0xdevalias commented 3 years ago

[OOS] While it's OOS for this PR, in future we could likely use this same lib/pattern to enhance our existing 'reactions' feature as well. Currently it just uses hardcoded emoji:

Some of the related files:

We also have a backlog issue (scheduled to be worked on soon, after a couple of higher priority features) to clean up all of the 'send reaction' buttons/etc across the codebase into a single canonical component + logic in a hook, etc (currently each venue template has it's own duplicated code for rendering the 'reaction buttons' in places like the Jazz Bar, Auditorium (Audience), etc:

Originally posted by @0xdevalias in https://github.com/sparkletown/sparkle/issues/1394#issuecomment-841598849

yarikoptic commented 3 years ago

My thinking currently is: add -render one and if we arrive at a good (not just rendering but selector) use of -mart it should be easy to "upgrade":

Waiting on ultimate solution using -mart might just lead ending up without any emoji support. And it would be useful to test drive and ensure integration with other developments (threaded chat etc).

Having said that, waiting for few days on that PR is ok, may be someone does arrive with -mart solution

0xdevalias commented 3 years ago

Waiting on ultimate solution using -mart might just lead ending up without any emoji support.

@yarikoptic I don’t see this as ‘waiting on ultimate solution’ so much as just ‘use the library we intend to ultimately use for everything from the beginning’.

There’s no point doing the double work of assessing/adding a library just to rip it out again later. Given the plan is most likely to use emoji-mart, and it has the ‘render’ capability we need here, we may as well use it from the beginning.

That said, I don’t feel like we need to block the ‘render emojis’ part on waiting for all of the other features that can be built on top of that later (eg. emoji picker, etc)

yarikoptic commented 3 years ago

Ah gotcha: so I (or someone) should refactor this PR to use emoji-mart for rendering even though we wouldn't use all the features of heavier emoji-mart library. Will do (if as easy as -render) when get back to the laptop

yarikoptic commented 3 years ago

Sorry -- I do not see (I ain't web developer) from RTFM how to easily replace react-emoji-render with emoji-mart given some text where to replace occurrences of emojis with their corresponding Emoji constructs -- would need someone better at JS etc.

0xdevalias commented 3 years ago

Ah gotcha: so I (or someone) should refactor this PR to use emoji-mart for rendering even though we wouldn't use all the features of heavier emoji-mart library.

@yarikoptic Exactly :)


Sorry -- I do not see (I ain't web developer) from RTFM how to easily replace react-emoji-render with emoji-mart given some text where to replace occurrences of emojis with their corresponding Emoji constructs -- would need someone better at JS etc.

@yarikoptic That's fair enough. I haven't looked deeply at the functionality of both and compared/contrasted, but the part that jumped out at me earlier (mentioned in https://github.com/sparkletown/sparkle/issues/1393#issuecomment-841595445) is the Emoji component:

Though looking a little closer at that component now, it looks like it's used for rendering the emoji directly, not for 'rendering' a block of text like https://github.com/tommoor/react-emoji-render does


Looking at their code, it looks like the Emoji component is imported from ./renderer:

Within the Emoji component, the text prop is parsed with toArray:

toArray is defined here, and includes some inner functions (replaceUnicodeEmoji, replaceAliases), that are then used in the main function call (replace(replaceAliases(text), unicodeEmojiRegex, replaceUnicodeEmoji)):

replaceAliases uses aliasRegex, and then iterates over the matches, handling some edge cases, etc to basically 'normalize' the 'input text' before it gets processed by unicodeEmojiRegex/replaceUnicodeEmoji:

From a quick skim, unicodeEmojiRegex seems to do the actual matching (after the text is normalised by replaceAliases), and replaceUnicodeEmoji mostly seems concerned with the actual 'rendering' part (which would probably be handled by emoji-mart in our case):


Googling about this, I came across https://github.com/missive/emoji-mart/issues/264 which talks about our exact situation here:

Is there any internal available parsing method to look for emojis in a text string, looking for all the supported encodings (unicode, colons, ascii, ...)?

Something like npmjs.com/package/react-emoji-render, but for all of the supported emojis in your set(s).

Which suggests looking at https://github.com/mathiasbynens/emoji-regex for this purpose:

You may want to look into emoji-regex, which should handle this use case. Thanks!

Note that emoji-regex is the same underlying library that react-emoji-render uses (which it calls unicodeEmojiRegex).

Looking at the README, there are different flavours of the regular expression that we could use. It sounds like we would want to use emojiRegexRGI:

Looking in the issues for the project, I came across https://github.com/mathiasbynens/emoji-regex/issues/85, which suggests that the RGI_Emoji logic has been extracted into rgi-emoji-regex-pattern:

I would need to check both emoji-regex and rgi-emoji-regex-pattern closer to see which one we would want to 'consume' for our code.

0xdevalias commented 3 years ago

RE: https://github.com/sparkletown/sparkle/issues/1393#issuecomment-842005128

Based on the above investigation, the rough 'high level plan' for how to implement similar functionality as react-emoji-render that we can use directly with emoji-mart would probably be to:

yarikoptic commented 3 years ago

FWIW, if we are to analyze "parts" then it might make sense to generalize getLinkFromText (ref: #1408) into formatShortText or alike which would take care about formatting URLs and emojis.

edit: might want to account-for/address #1412 if to go this route

0xdevalias commented 3 years ago

FWIW, if we are to analyze "parts" then it might make sense to generalize getLinkFromText (ref: #1408) into formatShortText or alike which would take care about formatting URLs and emojis

@yarikoptic They definitely seem like similar/related ‘patterns’. Even further than that, I sort of expect that the work @margulies is doing with the markdown rendering may replace getLinkFromText entirely as well.

yarikoptic commented 3 years ago

yeah, we exchanged a few messages with @margulies , but insofar agreed that "markdown" might be too heavy for the chat.

0xdevalias commented 3 years ago

but insofar agreed that "markdown" might be too heavy for the chat

Yeah, would definitely want to be disabling a few features in it (eg. images) for a v1 implementation if we ever do use it for the chat.

0xdevalias commented 3 years ago

Potentially relevant snippet I found today RE: implementing our own 'emoji render'/etc https://github.com/sparkletown/sparkle/issues/1393#issuecomment-842005274 and/or https://github.com/sparkletown/sparkle/issues/1393#issuecomment-842564896

I haven't tested that yet, but at an initial skim/read, it sounds like it might allow us to easily do string-replace-to-array type things eg. using String.split with a regex with capturing groups to get an array, then processing that array (eg .map()) and checking for matches against the same regex pattern to then replace the emoji/etc as desired.

Not sure if that would be easier/better than just looping through the regex matches directly, but figured I would capture it here in case it's relevant.

0xdevalias commented 3 years ago

Latest deepdive into remark (markdown parser), associated plugins for rendering emoji, and how to make custom plugins (fairly easy looking) so we could wire it up how we want it to work.


  • no emoticons support but emojis are supported. I guess I could live with that

@yarikoptic If by emoticons you mean things like ;)/etc, then these are handled as custom 'aliases' within react-emoji-render, as explored in my deepdive in https://github.com/sparkletown/sparkle/issues/1393#issuecomment-842005128 (replaceAliases + aliasRegex):

It looks like remark-emoji is used to render the emoji here:

The actual plugin code for remark-emoji is trivially small, and it looks like it wouldn't take much effort to implement our own remark plugin that wires into emoji-mart if we choose to use that:

There also seems to be a bunch of existing plugins:

Originally posted by @0xdevalias in https://github.com/sparkletown/sparkle/issues/1383#issuecomment-842957000

0xdevalias commented 3 years ago

Note: https://github.com/sparkletown/sparkle/pull/1383 is the current forerunner PR in getting this feature implemented.