tameemsafi / typewriterjs

A simple yet powerful native javascript plugin for a cool typewriter effect.
https://www.npmjs.com/package/typewriter-effect
MIT License
2.46k stars 220 forks source link

Please add "initial value" #130

Open lucasshuan opened 3 years ago

lucasshuan commented 3 years ago

I wanted to use the delete effect in React, but I can't figure a way to have a starting text. Option for initial value could be great.

salma-py97 commented 2 years ago

You can write your initial text and then use the component. One problem you might have is that the component is a div and so it has a display: block; property by default. You can wrap your initial text and the component in a div and apply display: inline ! important; property.

ianwensink commented 2 years ago

You can write your initial text and then use the component.

@salma-py97 but when writing a value inside the container and then initialising it, everything get's removed immediately right? That is in the code of the instructor.

So my use case for this is a bit different from @lucroch. I need to support server side rendering, so the string needs to be in the HTML response. This is all working when adding the text by default inside the wrapper element. On the client, though, the typewriter class will be initialised, and will delete the already written text.

lucasshuan commented 2 years ago

I found a workaround for my needs, although having initial value would still be great. On ReactJS, I could put a state inside the onInit function and change it at any point and it's read.

tini2n commented 2 years ago

Have the same problem @lucroch can you share your workable solution? 🙂

Nikola-Milovic commented 2 years ago

@lucroch same issue, can you post your solution?

lucasshuan commented 2 years ago

Hey there @tini2n and @Nikola-Milovic, I'm really sorry for the delay on responding this. I solved this a while ago so I don't exactly remember how I did it, but like I said: I put a state inside the onInit function that I can change at any point.

    const [writer, setWriter] = useState<TypewriterClass>()
    const [transition, setTransition] = useState("Start")

    useEffect(
        () => {
            if (isExit) {
                setTransition("Final")
                writer?.deleteAll().start()
            }
        }, [isExit]
    )

    return(
        <LogoText>
                <p className={transition}>Auth</p>
                <p>
                    <Typewriter
                        options={{cursor: ".", delay:55}}
                        onInit={(typer) => {
                            typer.typeString(text).start();
                            setWriter(typer)
                        }}
                    />
                </p>
        </LogoText>
    )

What I wanted was the typewriter to call a DeleteAll when redirecting to another page and the end result is pretty much just like this:

rohitsachaan commented 2 years ago

@lucroch it will be really helpful if you or anyone else can share their code, to achieve this?

or

@tameemsafi is there any release planned for this feature #118?

HenriqueArtur commented 1 year ago

@rohitsachaan I used the @lucroch solution as a reference and worked perfectly for me.

Note that I used a Hook, but you could change it to a variable using "useState"

import { useEffect, useState } from "react";
import useTitle from "../../hooks/useTitle";
import Typewriter, { TypewriterClass } from 'typewriter-effect';

export default function Title(): JSX.Element {
  const title = useTitle();
  const [writer, setWriter] = useState<TypewriterClass>();

  const animate = (typewriter: any) => {
    typewriter
      .typeString(title)
      .start();
    setWriter(typewriter);
  };

  useEffect(() => {
    if (writer) {
      writer
        .deleteAll(15)
        .typeString(title)
        .start()
      setWriter(writer);
    }
  }, [title]);

  return (
    <h1>
      <Typewriter
        onInit={animate}
        options={{ cursor: ".", delay: 35 }}
      />
    </h1>
  );
};
mwskwong commented 1 year ago

@rohitsachaan I used the @lucroch solution as a reference and worked perfectly for me.

Note that I used a Hook, but you could change it to a variable using "useState"

import { useEffect, useState } from "react";
import useTitle from "../../hooks/useTitle";
import Typewriter, { TypewriterClass } from 'typewriter-effect';

export default function Title(): JSX.Element {
  const title = useTitle();
  const [writer, setWriter] = useState<TypewriterClass>();

  const animate = (typewriter: any) => {
    typewriter
      .typeString(title)
      .start();
    setWriter(typewriter);
  };

  useEffect(() => {
    if (writer) {
      writer
        .deleteAll(15)
        .typeString(title)
        .start()
      setWriter(writer);
    }
  }, [title]);

  return (
    <h1>
      <Typewriter
        onInit={animate}
        options={{ cursor: ".", delay: 35 }}
      />
    </h1>
  );
};

Too bad, the default value will not be available in SSR

viatanas commented 1 year ago

I agree that an initial value attribute is really important and would be a great addition to the package. From a UX perspective, you don't want the user to get on a page, without any initial content on it.

CanRau commented 1 year ago

Came here for the same to get rid of the cumulative layout shift on SSR rendered page when the animation first starts

Update: this works actually good enough for now

const [hasInitialized, setHasInitialized] = useState(false);

return (
  <div className={className}>
    {!hasInitialized && strings.at(0)}

    <TypewriterEffect
      onInit={() => setHasInitialized(true)}
      options={{
        strings: strings.slice(1),
        autoStart: true,
        loop: true,
      }}
    />
  </div>
);