maxeth / react-type-animation

A React typewriter animation based on typical with extended functionality and customization.
https://react-type-animation.netlify.app/
MIT License
391 stars 24 forks source link

Emojis and Unusual Characters are Unsupported #26

Closed andrewpeters9 closed 11 months ago

andrewpeters9 commented 1 year ago

When the animation types out emojis and other abstract characters it will do so an unexpected way.

This is because the strings are broken down by array-spreading in typical.ts and there are references to a string's length via String.prototype.length.

See https://github.com/orling/grapheme-splitter for examples of problematic strings.

IMO, the best solution would be to implement a library such as grapheme-splitter to handle the splitting strings and the determining of their lengths.

maxeth commented 1 year ago

Hey,

I just tried it out but I don't see any issue with emojis/abstract characters. Do you have any concrete examples?

https://github.com/maxeth/react-type-animation/assets/48837036/4c7faf3a-9b37-4869-81bf-ac5dad08da1e

andrewpeters9 commented 1 year ago

@maxeth those basic emojis seem to work for me, but things such as flags cause issues for me:

            <TypeAnimation
              sequence={[
                "Hello 🇬🇧",
                5000,
                "Ciao 🇮🇹",
                5000,
                "Hola 🇪🇸",
                5000,
                "Bonjour 🇫🇷",
                5000,
                "Hello 🇬🇧",
              ]}
              wrapper="span"
              style={{ display: "inline-block" }}
            />

Hindi & Korean characters will also break (see grapheme-splitter examples). Also, demonic characters will cause issues (I sorely hope that no-one is actually using these):

const demonic = "Z͑ͫ̓ͪ̂ͫ̽͏̴̙̤̞͉͚̯̞̠͍A̴̵̜̰͔ͫ͗͢L̠ͨͧͩ͘G̴̻͈͍͔̹̑͗̎̅͛́Ǫ̵̹̻̝̳͂̌̌͘!͖̬̰̙̗̿̋ͥͥ̂ͣ̐́́͜͞";

const complexEmojis = "🌷🎁💩😜👍🏳️‍🌈";
maxeth commented 1 year ago

@andrewpeters9 Okay I see what you mean, thanks for pointing that out. I assume this default splitting of strings into chars is what you mean, right?

The package you linked itself is ~2x the bundle size of this entire package, so I don't think we should add it by default.

Maybe adding a prop that takes a function and lets you customize how strings are split would be a solution.

andrewpeters9 commented 1 year ago

@andrewpeters9 Okay I see what you mean, thanks for pointing that out. I assume this default splitting of strings into chars is what you mean, right?

Yea that was what I was referring to. Maybe sequence could be Array<string | number | Array<string>>?

E.g.

<TypeAnimation
    sequence={[
       "Hello",
       5000,
       ['🇪🇸', '🌷', 'any text here will show up in one animation tick?'],
       5000,
      "Hello again"
     ]}
     wrapper="span"
 />

Edit: ah yea, I think an overwritable splitter function might be a cleaner approach, and the README could just recommend that splitter package to those with funny strings?

maxeth commented 1 year ago

@andrewpeters9 Good idea. I just tried it out and it works for typing, but not for deleting.

Because after the text is typed out, further edits are evaluated based on the contents of the node, which is just a simple string.

async function edit(
  node: any,
  text: any,
  speed: number,
  deletionSpeed: number,
  omitDeletionAnimation: boolean
) {
  const overlap = getOverlap(node.textContent, text);
  await perform(
    node,
    [...deleter(node.textContent, overlap), ...writer(text, overlap)], // <--- "array sequence" is lost
    speed,
    deletionSpeed,
    omitDeletionAnimation
  );
}

So the string splitting would actually have to be modified or we'd have to keep track of the structure of previous sequence entries

andrewpeters9 commented 1 year ago

@maxeth After writing that above comment I made an edit saying that maybe it's a cleaner approach to just allow for a custom splitter and just direct people to the grapheme-splitter dependency in the README if they have a weird string.

What do you think would be better? Happy to open an MR based on your decision.

maxeth commented 1 year ago

@maxeth After writing that above comment I made an edit saying that maybe it's a cleaner approach to just allow for a custom splitter and just direct people to the grapheme-splitter dependency in the README if they have a weird string.

What do you think would be better? Happy to open an MR based on your decision.

I think the custom splitter function is the best solution with the least overhead.

andrewpeters9 commented 1 year ago

I think the custom splitter function is the best solution with the least overhead.

@maxeth want me to open up an MR for this? If so I can have one up over the weekend.

maxeth commented 1 year ago

I think the custom splitter function is the best solution with the least overhead.

@maxeth want me to open up an MR for this? If so I can have one up over the weekend.

sure.

maxeth commented 11 months ago

Added in v3.2.0 https://react-type-animation.netlify.app/examples#typing-complex-characters