Skip to content
This repository was archived by the owner on Oct 25, 2021. It is now read-only.

Commit ee151f1

Browse files
committed
Allow children to fully render before initializing.
1 parent 7197af4 commit ee151f1

File tree

7 files changed

+154
-27
lines changed

7 files changed

+154
-27
lines changed

README.md

Lines changed: 91 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,42 @@ import TypeIt from "typeit-react";
2525
export default () => {
2626
return (
2727
<div className="App">
28-
<TypeIt>This will be typed in a `span` element!</TypeIt>
28+
<TypeIt>
29+
This will be typed in a `span` element!
30+
</TypeIt>
2931
</div>
3032
);
3133
};
3234
```
3335

34-
Note: This approach will cause the string to first be rendered in the markup and _then_ picked up by TypeIt, which might be desired if you're using it with a statically rendered application (ex: GatsbyJS). However, it may also cause a brief flash of text when the page loads. For an alternative way to define strings, see below.
36+
### A More Complex Example
37+
38+
The component will allow its children to fully render, and then type whatever HTML is generated. So, in addition to simple strings, you can nest HTML and components like below.
39+
40+
```javascript
41+
import TypeIt from "typeit-react";
42+
43+
// This could be any component that generates HTML.
44+
const SuperStrong = ({children}) => {
45+
return (
46+
<strong style={{fontSize: "80px"}}>{children}</strong>
47+
)
48+
}
49+
50+
export default () => {
51+
return (
52+
<div className="App">
53+
<TypeIt>
54+
Weak text. <SuperStrong>Super strong text.</SuperStrong>
55+
</TypeIt>
56+
</div>
57+
);
58+
};
59+
```
3560

3661
### Customizing Your Options
3762

38-
To tweak the animation to your liking, pass an object as the `options` prop. All options supported by TypeIt can be used here. Using this prop, you can also set strings without passing them as children. To view all options, see [TypeIt's documentation](https://typeitjs.com/docs#options).
63+
To tweak the animation to your liking, pass an object as the `options` prop. All options supported by the core TypeIt library can be used here. Using this prop, you can also set strings without passing them as children. See [TypeIt's documentation](https://typeitjs.com/docs#options) for more details on what's available.
3964

4065
```javascript
4166
import TypeIt from "typeit-react";
@@ -55,7 +80,7 @@ export default () => {
5580
};
5681
```
5782

58-
### Choose Your Own Element
83+
### Choosing Your Own Element
5984

6085
Out of the box, a `span` element is used to contain the typing animation. To choose your own element, use the `element` prop.
6186

@@ -71,6 +96,68 @@ export default () => {
7196
};
7297
```
7398

99+
### Fine-Tuning the Instance w/ Companion Methods
100+
101+
TypeIt comes with a set of [special methods](https://typeitjs.com/docs#instance-methods) that let you fine-tune an animation down to the smallest detail. To leverage them here, pass a function as the `onBeforeInit` prop, which will give you access to the instance you can modify with these methods, and then return back to the component before the animation is initialized.
102+
103+
```javascript
104+
import TypeIt from "typeit-react";
105+
106+
<TypeIt
107+
getBeforeInit={(instance) => {
108+
instance
109+
.type("Hi, I'm Alxe")
110+
.pause(750)
111+
.delete(2)
112+
.pause(500)
113+
.type("ex!");
114+
115+
// Remember to return it!
116+
return instance;
117+
}}
118+
/>
119+
```
120+
121+
### Accessing the Instance After Initalization
122+
123+
Similarly, the `getAfterInit` prop allows you to access the instance _after_ it's been kicked off, so you'll be able to leverage methods like `.freeze()`, `.unfreeze()`, and `.is()`. Read more about those [here](https://typeitjs.com/docs#non-chainable-instance-methods).
124+
125+
```javascript
126+
export default () => {
127+
const [buttonText, setButtonText] = useState("Freeze");
128+
const [instance, setInstance] = useState(null);
129+
130+
const toggleFreeze = () => {
131+
if(instance.is('frozen')) {
132+
instance.unfreeze();
133+
setButtonText('Freeze');
134+
return;
135+
}
136+
137+
instance.freeze();
138+
setButtonText('Unfreeze');
139+
}
140+
141+
return (
142+
<div className="App">
143+
<button onClick={toggleFreeze}>
144+
{buttonText}
145+
</button>
146+
147+
<TypeIt
148+
options={{ loop: true }}
149+
getAfterInit={(instance) => {
150+
setInstance(instance);
151+
return instance;
152+
}}
153+
>
154+
This will just keep on going.
155+
</TypeIt>
156+
</div>
157+
);
158+
}
159+
```
160+
74161
## Need Help?
75162

76163
If you're working with a custom implementation of TypeIt and would like some help, I'm available for hire. [Get in touch!](https://macarthur.me/contact)

dist/typeit-react.es.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/typeit-react.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typeit-react",
3-
"version": "0.0.1",
3+
"version": "0.0.2",
44
"description": "React component for the most versatile JavaScript animated typing utility on the planet.",
55
"main": "dist/typeit-react.min.js",
66
"module": "dist/typeit-react.es.min.js",
@@ -20,7 +20,7 @@
2020
"typing effect",
2121
"typewriter effect",
2222
"type effect",
23-
"text effects",
23+
"text effects",
2424
"react"
2525
],
2626
"repository": {

src/index.tsx

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,76 @@
11
import * as React from 'react';
22
import { default as TypeItCore } from 'typeit';
3-
const { useRef, useEffect } = React;
3+
const { useRef, useEffect, useState } = React;
4+
5+
export interface TypeItOptions {
6+
strings?: Array<string> | string
7+
}
48

59
export interface TypeItProps {
610
element?: string,
7-
options?: object,
8-
children?: React.ReactNode
9-
}
11+
options?: TypeItOptions,
12+
children?: React.ReactNode,
13+
getBeforeInit?: any,
14+
getAfterInit?: any
15+
}
1016

1117
const defaultProps: TypeItProps = {
1218
element: 'span',
13-
options: {}
19+
options: {},
20+
getBeforeInit: (instance: object) => instance,
21+
getAfterInit: (instance: object) => instance
1422
}
1523

1624
const TypeIt: React.FunctionComponent = (props: TypeItProps) => {
17-
const ref = useRef<HTMLElement>(null);
18-
const {options, element, children, ...remainingProps} = props;
25+
const [shouldRenderChildren, setShouldRenderChildren] = useState<boolean>(true);
26+
const ref = useRef<HTMLElement|null>(null);
27+
const {options, element, children, getBeforeInit, getAfterInit, ...remainingProps} = props;
1928
const DynamicElement = element;
2029

30+
/**
31+
* After the component mounts (and any children are rendered),
32+
* we can safely set the strings of the instance using the rendered HTML
33+
* from those optionally-defined children. Otherwise, we'll just use the strings
34+
* defined via the options prop.
35+
*/
36+
useEffect(() => {
37+
if(children) {
38+
options.strings = ref.current.innerHTML;
39+
}
40+
41+
setShouldRenderChildren(false);
42+
}, []);
43+
44+
/**
45+
* Once options (and strings) have been defined, we can hide any children we might
46+
* have rendered to make room for the TypeIt animation. On cleanup, destroy
47+
* that instance.
48+
*/
2149
useEffect(() => {
22-
const instance = (new TypeItCore(ref.current, {
50+
if(shouldRenderChildren) {
51+
return;
52+
}
53+
54+
let i = (new TypeItCore(ref.current, {
2355
...options
24-
})).go();
56+
}));
57+
58+
i = getBeforeInit(i);
59+
i.go();
60+
i = getAfterInit(i);
2561

2662
return () => {
27-
instance.destroy();
63+
// @ts-ignore
64+
i.destroy();
2865
}
29-
}, []);
66+
}, [shouldRenderChildren]);
3067

3168
return (
32-
<DynamicElement ref={ref} {...remainingProps}>
33-
{children}
34-
</DynamicElement>
69+
<div style={{ opacity: shouldRenderChildren ? 0 : 1}}>
70+
<DynamicElement ref={ref} {...remainingProps}>
71+
{shouldRenderChildren && children}
72+
</DynamicElement>
73+
</div>
3574
)
3675
}
3776

types/index.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
declare namespace JSX {
22
interface IntrinsicElements {
3-
DynamicElement: any
3+
DynamicElement: any,
4+
ref: HTMLElement | null
45
}
56
}

0 commit comments

Comments
 (0)