Skip to content

Commit

Permalink
feat: add onCharTyped and onCharDeleted callback
Browse files Browse the repository at this point in the history
add typeSpeed and deletionSpeed prop to TypeAnimation component
  • Loading branch information
Benjamin committed Jun 20, 2024
1 parent f896e25 commit 6f39cb2
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 20 deletions.
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,15 @@ The following props allows you to configure the properties for the type animatio
| `direction` | no | String | front | Specifies the direction in which to perform the typing/deleting animation. It accepts two possible values: 'front' and 'back'. |
| `initialDelay` | no | Number | 0 | The delay before the animation begins (in milliseconds). |
| `loop` | no | Boolean | false | Whether to loop the typing animation indefinitely. |
| `onCharTyped` | no | Function | | Callback function triggered when a character is typed. |
| `onCharDeleted` | no | Function | | Callback function triggered when a character is deleted. |
| `preRenderText` | no | String | None | Specifies the initial text to display. |
| `repeat` | no | Number | 1 | The number of times to repeat the sequence. |
| `sequence` | yes | Array | | An array of objects defining the text to be typed and animation options. |
| `splitter` | no | Function | | A function to split text into individual characters or chunks for typing. |
| `style` | no | TextStyle | | Additional styles for the typewriter animation container. |
| `typeSpeed` | no | Number | 100 | The speed at which characters are typed. |
| `deletionSpeed` | no | Number | 100 | The speed at which characters are deleted. |

#### `sequence` Array

Expand All @@ -99,9 +103,9 @@ The `sequence` prop is an array of objects, where each object defines a part of

- `deleteCount`: The number of characters to delete before typing (backspacing).

- `deletionSpeed`: The speed at which characters are deleted (backspace speed, in milliseconds). The default is 100, but you can specify a custom value for individual sequences.
- `deletionSpeed`: The speed at which characters are deleted from this sequence (backspace speed, in milliseconds). The default is 100, but you can specify a custom value for individual sequences.

- `typeSpeed`: The speed at which characters are typed (typing speed, in milliseconds). The default is 100, but you can specify a custom value for individual sequences.
- `typeSpeed`: The speed at which characters are typed in this sequence(typing speed, in milliseconds). The default is 100, but you can specify a custom value for individual sequences.

#### `direction` String

Expand Down Expand Up @@ -135,6 +139,20 @@ The `cursorStyle` prop is used to apply additional styles to the cursor element.

The `cursor` prop determines whether the cursor is displayed during the animation. By default, it is set to `true`, but you can set it to `false` if you don't want to display the cursor.

#### `onCharTyped` Callback

This callback function is triggered each time a character is typed. It receives an object as an argument containing two properties:

- character: The character that was just typed.
- currentText: The current state of the text after the character has been typed.

#### `onCharDeleted` Callback

This callback function is triggered each time a character is deleted. It receives an object as an argument containing two properties:

- character: The character that was just deleted.
- currentText: The current state of the text after the character has been deleted.

**Note:** When using the `sequence` prop, you can define complex typing animations with different text, delays, and actions. Each object in the `sequence` array represents a step in the animation.

Example usage of `TypeAnimationProps`:
Expand Down
33 changes: 33 additions & 0 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,42 @@ export default function App() {
},
{ text: 'One' },
]}
onCharDeleted={({ character, currentText }) => {
console.log('char deleted', { character, currentText });
}}
onCharTyped={({ character, currentText }) => {
console.log('char typed', { character, currentText });
}}
loop
style={styles.text}
/>
<TypeAnimation
sequence={[
{ text: 'One' },
{
text: 'One Two',
},
{
action: () => {
console.log('Finished first two sequences');
},
},
{ text: 'One Two Three' },
{
text: 'One Two',
},
{ text: 'One' },
]}
loop
direction="back"
style={styles.text}
onCharDeleted={({ character, currentText }) => {
console.log('char deleted', { character, currentText });
}}
onCharTyped={({ character, currentText }) => {
console.log('char typed', { character, currentText });
}}
/>
</View>
);
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-type-animation",
"version": "0.3.0",
"version": "0.3.1",
"description": "React Native Type Animation is a component library that allows you to create engaging typewriter-style text animations in your React Native applications.",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
111 changes: 94 additions & 17 deletions src/TypeAnimation.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import type { TextStyle } from 'react-native';
import { Animated, Text } from 'react-native';
import {
Expand Down Expand Up @@ -45,7 +51,7 @@ const Cursor: React.FC<CursorProps> = ({
Animated.delay(blinkSpeed),
])
).start();
}, []);
}, [blinkSpeed, opacity]);

return (
<Animated.Text style={{ opacity, ...style, ...cursorStyle }}>
Expand Down Expand Up @@ -80,12 +86,12 @@ type TypeAnimationProps = {
*/
deleteCount?: number;
/**
* The speed at which characters are deleted (backspace speed, in milliseconds). Default: 100
* The speed at which characters are deleted from this sequence (backspace speed, in milliseconds). Default: 100
*/
deletionSpeed?: number;

/**
* The speed at which characters are typed (typing speed, in milliseconds). Default: 100
* The speed at which characters are typed in this sequence (typing speed, in milliseconds). Default: 100
*/
typeSpeed?: number;
} & (
Expand Down Expand Up @@ -147,6 +153,23 @@ type TypeAnimationProps = {
* The delay before the animation begins (in milliseconds). Default: 0
*/
initialDelay?: number;
/**
* Callback function triggered when a character is typed.
*/
onCharTyped?: (data: { character: string; currentText: string }) => void;
/**
* Callback function triggered when a character is deleted.
*/
onCharDeleted?: (data: { character: string; currentText: string }) => void;
/**
* The speed at which characters are deleted (backspace speed, in milliseconds). Default: 100
*/
deletionSpeed?: number;

/**
* The speed at which characters are typed (typing speed, in milliseconds). Default: 100
*/
typeSpeed?: number;
};

/**
Expand All @@ -165,6 +188,10 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
direction = 'front',
preRenderText = '',
initialDelay = 0,
onCharTyped,
onCharDeleted,
typeSpeed = 100,
deletionSpeed = 100,
}) => {
const [text, setText] = useState<string>(preRenderText);
let currentText = preRenderText;
Expand All @@ -174,7 +201,7 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
* @param textToType - The text to type.
* @param speed - The typing speed.
*/
const typeLetters = (textToType: string, speed = 100) => {
const typeLetters = (textToType: string, speed = typeSpeed) => {
return new Promise<void>((resolve) => {
let i = 0;
const textArray = splitter(textToType);
Expand All @@ -184,11 +211,35 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
resolve();
} else {
if (direction === 'front') {
setText((currText) => `${currText}${textArray[i]}`);
setText((currText) => {
const character = textArray[i];
const word = `${currText}${character}`;
if (character) {
const data = {
character,
currentText: word,
};
if (onCharTyped) {
onCharTyped(data);
}
}
return word;
});
} else {
setText(
(currText) => `${textArray[textArray.length - i - 1]}${currText}`
);
setText((currText) => {
const character = textArray[textArray.length - i - 1];
const word = `${character}${currText}`;
if (character) {
const data = {
character,
currentText: word,
};
if (onCharTyped) {
onCharTyped(data);
}
}
return word;
});
}
}
i++;
Expand All @@ -201,7 +252,7 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
* @param count - The number of letters to delete.
* @param speed - The deletion speed.
*/
const deleteLetters = (count: number, speed = 100) => {
const deleteLetters = (count: number, speed = deletionSpeed) => {
return new Promise<void>((resolve) => {
let i = 0;
const interval = setInterval(() => {
Expand All @@ -210,11 +261,35 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
resolve();
} else {
if (direction === 'front') {
setText(
(currtext) => `${currtext.substring(0, currtext.length - 1)}`
);
setText((currtext) => {
const word = `${currtext.substring(0, currtext.length - 1)}`;
const character = currtext[currtext.length - 1];
if (character) {
const data = {
character,
currentText: word,
};
if (onCharDeleted) {
onCharDeleted(data);
}
}
return word;
});
} else {
setText((currtext) => `${currtext.substring(1, currtext.length)}`);
setText((currtext) => {
const word = `${currtext.substring(1, currtext.length)}`;
const character = currtext[0];
if (character) {
const data = {
character,
currentText: word,
};
if (onCharDeleted) {
onCharDeleted(data);
}
}
return word;
});
}
}
i++;
Expand Down Expand Up @@ -267,7 +342,7 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
}
};

const firstFunction = () => {
const firstFunction = useCallback(() => {
if (loop) {
const run = async () => {
await runSequence();
Expand All @@ -277,7 +352,9 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
} else {
repeatFunctionNTimes(runSequence, repeat);
}
};
/* eslint-disable react-hooks/exhaustive-deps */
}, []);

useEffect(() => {
if (initialDelay) {
setTimeout(() => {
Expand All @@ -286,7 +363,7 @@ const TypeAnimation: React.FC<TypeAnimationProps> = ({
} else {
firstFunction();
}
}, []);
}, [initialDelay, firstFunction]);

const cursorComponent = useMemo(() => {
return cursor ? (
Expand Down

0 comments on commit 6f39cb2

Please sign in to comment.