@@ -35,49 +35,61 @@ function reactReplaceEmojis(reactChild, options) {
3535}
3636
3737function replaceEmojis ( string , options ) {
38+ if ( ! string ) return ;
39+ let array = [ string ]
40+
3841 options = {
3942 size : typeof options ?. size === 'string' ? options . size : undefined ,
4043 outline : typeof options ?. outline === 'boolean' ? options . outline : undefined
41- }
42- if ( ! string ) return ;
43- const emojis = string . match ( / [ \p{ Emoji} \u200d \ufe0f ] + / gu) ;
44- if ( ! emojis ) return string ;
44+ } ;
4545
46- string = string . split ( / ( [ \p{ Emoji} \u200d \ufe0f ] + ) / gu) ;
46+ // matches all emojis matches all attached components matches that is joined (zwj)
47+ // \p{Extended_Pictographic}[\u{1f3fb}-\u{1f3ff}\u{1f9b0}-\u{1f9b3}]?(\u200d.)?\ufe0f?(?!\ufe0e)
48+ // matches only non-"text style" emojis
4749
48- // replace emojis with SVGs
49- emojis . forEach ( ( emoji , i ) => {
50- // get the char codes of the emojis
51- let unicode = "" ;
50+ const regex = / \p{ Extended_Pictographic} [ \u{1f3fb} - \u{1f3ff} \u{1f9b0} - \u{1f9b3} ] ? ( \u200d .) ? \ufe0f ? (? ! \ufe0e ) / gu;
51+ let m ;
5252
53- function getNextChar ( pointer ) {
54- const subUnicode = emoji . codePointAt ( pointer ) ;
55- if ( ! subUnicode ) return ;
56- if ( ! ( subUnicode >= 56320 && subUnicode <= 57343 ) ) { // 56320-57343: Low Surrogates Character
57- unicode += '-' + subUnicode . toString ( 16 ) ;
58- }
59- getNextChar ( ++ pointer ) ;
53+ while ( ( m = regex . exec ( string ) ) !== null ) {
54+ // This is necessary to avoid infinite loops with zero-width matches
55+ if ( m . index === regex . lastIndex ) {
56+ regex . lastIndex ++ ;
6057 }
6158
62- getNextChar ( 0 ) ;
63- unicode = unicode . substr ( 1 ) ;
59+ // find the code for the emoji
60+ let emojiName = 'U' , done = false
61+ for ( let i = 0 ; ! done ; i ++ ) {
62+ let subUnicode = m [ 0 ] . codePointAt ( i )
63+ // dismiss low surrogates characters (56320-57343)
64+ if ( ( subUnicode >= 56320 && subUnicode <= 57343 ) ) continue
65+ emojiName += '_' + subUnicode ?. toString ( 16 ) . toUpperCase ( )
6466
65- const emojiName = `U_${ unicode . toUpperCase ( ) . replace ( / - / g, '_' ) } ` ;
67+ // check if is done: if this hexcode is longer than 4, check the next but one codepoint
68+ done = m [ 0 ] . codePointAt ( i ) ?. toString ( 16 ) . length > 4
69+ ? ! m [ 0 ] . codePointAt ( i + 2 )
70+ : ! m [ 0 ] . codePointAt ( i + 1 )
71+ }
6672
67- const emojiIndex = string . indexOf ( emoji ) ;
6873 let emojiSvg = Emoji [ emojiName ] ;
69-
70- options . key = i
71-
7274 if ( emojiSvg ) {
73- string [ emojiIndex ] = React . createElement ( emojiSvg , options ) ;
75+ // gets last string ['String with {Emoji} and {Emoji} in it'] -> 'String with {Emoji} and {Emoji} in it'
76+ let workingString = array . pop ( )
77+ // 'String with {Emoji} and {Emoji} in it' -> ['String with ', ' and ', ' in it']
78+ workingString = workingString . split ( m [ 0 ] )
79+ // [] -> ['String with ']
80+ // ['String with ', ' and ', ' in it'] -> [' and ', ' in it']
81+ array . push ( workingString . shift ( ) )
82+ // ['String with '] -> ['String with ', <Emoji>]
83+ array . push ( React . createElement ( emojiSvg , options ) )
84+ // [' and ', ' in it'] -> ' and {Emoji} in it'
85+ // ['String with ', <Emoji>] -> ['String with ', <Emoji>, ' and {Emoji} in it']
86+ array . push ( workingString . join ( m [ 0 ] ) )
7487 } else {
7588 console . warn ( 'SVG not found: ' + emojiName ) ;
7689 }
77- } )
90+ }
7891
79- // return converted react HTML
80- return string ;
92+ return array ;
8193}
8294
8395reactReplaceEmojis . replaceEmojis = replaceEmojis
0 commit comments