react-text-to-speech
Advanced tools
Comparing version 1.0.1 to 1.0.2
export declare const desktopChunkSize = 1000; | ||
export declare const minChunkSize = 50; | ||
export declare const mobileChunkSize = 250; | ||
export declare const specialSymbol = "\u00A0"; | ||
export declare const symbolMapping: { | ||
@@ -10,2 +9,3 @@ "<": string; | ||
export declare const sanitizeRegex: RegExp; | ||
export declare const specialSymbol = "\u00A0"; | ||
export declare const utterancePropertiesAndEvents: (keyof SpeechSynthesisUtterance)[]; |
export const desktopChunkSize = 1000; | ||
export const minChunkSize = 50; | ||
export const mobileChunkSize = 250; | ||
export const specialSymbol = "\u00A0"; | ||
export const symbolMapping = { "<": "lessthan", ">": "greaterthan" }; | ||
export const sanitizeRegex = new RegExp(`[${Object.keys(symbolMapping).join("")}]|(&[^\s;]+);`, "g"); | ||
export const specialSymbol = "\u00A0"; | ||
const utteranceEvents = ["onstart", "onend", "onerror", "onpause", "onresume", "onmark", "onboundary"]; | ||
const utteranceProperties = ["lang", "voice", "volume", "rate", "pitch"]; | ||
const utteranceEvents = ["onstart", "onend", "onerror", "onpause", "onresume", "onmark", "onboundary"]; | ||
export const utterancePropertiesAndEvents = utteranceProperties.concat(utteranceEvents); |
import React from "react"; | ||
import { dequeue } from "./queue.js"; | ||
import { SpeechStatus, SpeechUtterancesQueue, useSpeechProps } from "./types.js"; | ||
import { SpeechStatus, SpeechUtterancesQueue, UseSpeechOptions } from "./types.js"; | ||
export declare function useQueue(): { | ||
@@ -9,3 +9,3 @@ queue: SpeechUtterancesQueue; | ||
}; | ||
export declare function useSpeech({ text, pitch, rate, volume, lang, voiceURI, autoPlay, preserveUtteranceQueue, highlightText, highlightProps, maxChunkSize, onError, onStart, onResume, onPause, onStop, onBoundary, onQueueChange, }: useSpeechProps): { | ||
export declare function useSpeech({ text, pitch, rate, volume, lang, voiceURI, autoPlay, preserveUtteranceQueue, highlightText, highlightProps, maxChunkSize, onError, onStart, onResume, onPause, onStop, onBoundary, onQueueChange, }: UseSpeechOptions): { | ||
Text: () => React.ReactNode; | ||
@@ -12,0 +12,0 @@ speechStatus: SpeechStatus; |
@@ -1,2 +0,2 @@ | ||
import React, { cloneElement, isValidElement, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; | ||
import React, { cloneElement, isValidElement, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; | ||
import { specialSymbol } from "./constants.js"; | ||
@@ -20,2 +20,3 @@ import { addToQueue, clearQueue, clearQueueHook, clearQueueUnload, dequeue, removeFromQueue, speakFromQueue, subscribe } from "./queue.js"; | ||
}, [text]); | ||
const Text = useCallback(() => highlightedText(text), [speakingWord === null || speakingWord === void 0 ? void 0 : speakingWord.index, highlightText, stringifiedWords]); | ||
function start() { | ||
@@ -134,20 +135,20 @@ const synth = window.speechSynthesis; | ||
} | ||
function highlightedText(element, parentIndex = "") { | ||
function highlightedText(node, parentIndex = "") { | ||
var _a; | ||
if (!highlightText || !isParent(parentIndex, speakingWord === null || speakingWord === void 0 ? void 0 : speakingWord.index)) | ||
return element; | ||
if (Array.isArray(element)) | ||
return element.map((child, index) => highlightedText(child, getIndex(parentIndex, index))); | ||
if (isValidElement(element)) | ||
return cloneElement(element, { key: (_a = element.key) !== null && _a !== void 0 ? _a : Math.random() }, highlightedText(element.props.children, parentIndex)); | ||
if (typeof element === "string" || typeof element === "number") { | ||
element = String(element); | ||
return node; | ||
if (Array.isArray(node)) | ||
return node.map((child, index) => highlightedText(child, getIndex(parentIndex, index))); | ||
if (isValidElement(node)) | ||
return cloneElement(node, { key: (_a = node.key) !== null && _a !== void 0 ? _a : Math.random() }, highlightedText(node.props.children, parentIndex)); | ||
if (typeof node === "string" || typeof node === "number") { | ||
node = String(node); | ||
const { index, length } = speakingWord; | ||
const before = element.slice(0, +index.split("-").at(-1)).length; | ||
const before = node.slice(0, +index.split("-").at(-1)).length; | ||
return (React.createElement("span", { key: index }, | ||
element.slice(0, before), | ||
React.createElement("mark", Object.assign({}, highlightProps), element.slice(before, before + length)), | ||
element.slice(before + length))); | ||
node.slice(0, before), | ||
React.createElement("mark", Object.assign({}, highlightProps), node.slice(before, before + length)), | ||
node.slice(before + length))); | ||
} | ||
return element; | ||
return node; | ||
} | ||
@@ -160,3 +161,3 @@ useEffect(() => { | ||
return { | ||
Text: () => highlightedText(text), | ||
Text, | ||
speechStatus, | ||
@@ -163,0 +164,0 @@ isInQueue: speechStatus === "started" || speechStatus === "queued", |
@@ -26,5 +26,5 @@ var __rest = (this && this.__rest) || function (s, e) { | ||
var { id, startBtn = React.createElement(HiVolumeUp, null), pauseBtn = React.createElement(HiVolumeOff, null), stopBtn = React.createElement(HiMiniStop, null), useStopOverPause = false, props = {}, children } = _a, hookProps = __rest(_a, ["id", "startBtn", "pauseBtn", "stopBtn", "useStopOverPause", "props", "children"]); | ||
const [highlightContainer, setHighlightContainer] = useState(null); | ||
const _b = useSpeech(hookProps), { Text } = _b, childrenOptions = __rest(_b, ["Text"]); | ||
const { isInQueue, start, pause, stop } = childrenOptions; | ||
const [highlightContainer, setHighlightContainer] = useState(null); | ||
useEffect(() => { | ||
@@ -31,0 +31,0 @@ if (hookProps.highlightText) |
import { QueueChangeEventHandler, SpeechQueueItem } from "./types.js"; | ||
export declare function addToQueue(item: SpeechQueueItem, callback?: QueueChangeEventHandler): void; | ||
export declare function clearQueue(cancelSpeech?: boolean, start?: number, emitEvent?: boolean): void; | ||
export declare function addToQueue(item: SpeechQueueItem, callback?: QueueChangeEventHandler): void; | ||
export declare const clearQueueHook: () => void; | ||
@@ -5,0 +5,0 @@ export declare const clearQueueUnload: () => void; |
import { cancel } from "./utils.js"; | ||
const queue = []; | ||
const queueListeners = []; | ||
export function addToQueue(item, callback) { | ||
queue.push(item); | ||
emit(callback); | ||
} | ||
export function clearQueue(cancelSpeech = false, start = 0, emitEvent = false) { | ||
@@ -12,6 +16,2 @@ if (cancelSpeech) | ||
} | ||
export function addToQueue(item, callback) { | ||
queue.push(item); | ||
emit(callback); | ||
} | ||
export const clearQueueHook = () => clearQueue(true, 1, true); | ||
@@ -18,0 +18,0 @@ export const clearQueueUnload = () => clearQueue(true, 1); |
@@ -7,3 +7,3 @@ import { DetailedHTMLProps, HTMLAttributes, JSX, ReactNode } from "react"; | ||
export type SpeechSynthesisEventHandler = (event: SpeechSynthesisEvent) => any; | ||
export type useSpeechProps = { | ||
export type UseSpeechOptions = { | ||
text: string | JSX.Element; | ||
@@ -39,3 +39,3 @@ pitch?: number; | ||
export type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>; | ||
export type SpeechProps = useSpeechProps & { | ||
export type SpeechProps = UseSpeechOptions & { | ||
id?: string; | ||
@@ -42,0 +42,0 @@ startBtn?: Button; |
import { ReactNode } from "react"; | ||
import { Index, StringArray } from "./types.js"; | ||
export declare function ArrayToText(element: StringArray): string; | ||
export declare function JSXToArray(element: ReactNode): StringArray; | ||
export declare function ArrayToText(node: StringArray): string; | ||
export declare function JSXToArray(node: ReactNode): StringArray; | ||
export declare function TextToChunks(text: string, size?: number): string[]; | ||
@@ -6,0 +6,0 @@ export declare function cancel(): void; |
import { isValidElement } from "react"; | ||
import { desktopChunkSize, minChunkSize, mobileChunkSize, sanitizeRegex, specialSymbol, symbolMapping, utterancePropertiesAndEvents } from "./constants.js"; | ||
import { setState } from "./state.js"; | ||
export function ArrayToText(element) { | ||
if (typeof element === "string") | ||
return element; | ||
return element.map(ArrayToText).join(" ") + " "; | ||
export function ArrayToText(node) { | ||
if (typeof node === "string") | ||
return node; | ||
return node.map(ArrayToText).join(" ") + " "; | ||
} | ||
export function JSXToArray(element) { | ||
if (isValidElement(element)) { | ||
const { children } = element.props; | ||
export function JSXToArray(node) { | ||
if (isValidElement(node)) { | ||
const { children } = node.props; | ||
if (Array.isArray(children)) | ||
@@ -16,3 +16,3 @@ return children.map(JSXToArray); | ||
} | ||
return typeof element === "string" ? element : typeof element === "number" ? String(element) : ""; | ||
return typeof node === "string" ? node : typeof node === "number" ? String(node) : ""; | ||
} | ||
@@ -56,4 +56,4 @@ export function TextToChunks(text, size) { | ||
for (let i = 0; i < stringArray.length; i++) { | ||
const element = stringArray[i]; | ||
const result = recursiveSearch(element, i); | ||
const node = stringArray[i]; | ||
const result = recursiveSearch(node, i); | ||
if (result) | ||
@@ -60,0 +60,0 @@ return getIndex(parentIndex, result); |
{ | ||
"name": "react-text-to-speech", | ||
"version": "1.0.1", | ||
"version": "1.0.2", | ||
"description": "An easy-to-use React.js component that leverages the Web Speech API to convert text to speech.", | ||
@@ -35,14 +35,7 @@ "license": "MIT", | ||
"react", | ||
"react-speech-highlight", | ||
"react-text-to-speech", | ||
"react-tts", | ||
"say", | ||
"speak", | ||
"speech", | ||
"speech-synthesis", | ||
"synthesis", | ||
"text", | ||
"text-to-speech", | ||
"tts", | ||
"tts-react", | ||
"typescript", | ||
@@ -49,0 +42,0 @@ "webspeech-api" |
@@ -7,27 +7,34 @@ # react-text-to-speech | ||
- Text-to-speech functionality | ||
- Easy to use | ||
- Highlights words as they are read (see highlighting text using [useSpeech Hook](https://rtts.vercel.app/docs/usage/useSpeech#highlight-text) and [Speech Component](https://rtts.vercel.app/docs/usage/speech#highlight-text)). | ||
- Provides API to handle errors and events (see [Handling Errors and Events](https://rtts.vercel.app/docs/usage/useSpeech#handling-errors-and-events)). | ||
- Handles multiple speech instances easily (see handling using [useSpeech Hook](https://rtts.vercel.app/docs/usage/useSpeech#multiple-instance-usage) and [Speech Component](https://rtts.vercel.app/docs/usage/speech#multiple-instance-usage)). | ||
- Fully Customizable (see [useSpeech Hook Usage](https://rtts.vercel.app/docs/usage/useSpeech) and [usage with FaC](https://rtts.vercel.app/docs/usage/speech#full-customization)). | ||
- Overcomes the [Web Speech API's text limit](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance/text), allowing for infinite text input. | ||
- Automatically stops speech instances on component unmount. | ||
- Converts text to speech using the Web Speech API. | ||
- Highlights words as they are read aloud. See: | ||
- [Highlighting text with `useSpeech`](https://rtts.vercel.app/docs/usage/useSpeech#highlight-text). | ||
- [Highlighting text with `Speech` component](https://rtts.vercel.app/docs/usage/speech#highlight-text). | ||
- Provides an API for handling errors and events: | ||
- [Error handling with `useSpeech`](https://rtts.vercel.app/docs/usage/useSpeech#handling-errors-and-events). | ||
- [Error handling with `Speech` component](https://rtts.vercel.app/docs/usage/speech#handling-errors-and-events). | ||
- Manages multiple speech instances: | ||
- [Multiple instances with `useSpeech`](https://rtts.vercel.app/docs/usage/useSpeech#multiple-instance-usage). | ||
- [Multiple instances with `Speech` component](https://rtts.vercel.app/docs/usage/speech#multiple-instance-usage). | ||
- Fully customizable for various use cases: | ||
- [Customizing `useSpeech`](https://rtts.vercel.app/docs/usage/useSpeech). | ||
- [Customizing `Speech` component](https://rtts.vercel.app/docs/usage/speech#full-customization). | ||
- Overcomes the [Web Speech API's text length limit](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance/text), enabling infinite text input. | ||
- Automatically stops speech instances when the component unmounts. | ||
## Installation | ||
To install `react-text-to-speech`: | ||
Install `react-text-to-speech` using your preferred package manager: | ||
```bash | ||
# with npm: | ||
npm install react-text-to-speech --save | ||
# Using npm: | ||
npm install react-text-to-speech --save | ||
# with yarn: | ||
yarn add react-text-to-speech | ||
# Using Yarn: | ||
yarn add react-text-to-speech | ||
# with pnpm: | ||
pnpm add react-text-to-speech | ||
# Using pnpm: | ||
pnpm add react-text-to-speech | ||
# with bun: | ||
bun add react-text-to-speech | ||
# Using Bun: | ||
bun add react-text-to-speech | ||
``` | ||
@@ -37,5 +44,5 @@ | ||
**react-text-to-speech** offers two main ways to integrate text-to-speech functionality into your React.js applications through the `useSpeech` hook and the `<Speech>` component. | ||
**react-text-to-speech** provides two primary methods to integrate text-to-speech functionality into your React.js applications: the `useSpeech` hook and the `<Speech>` component. | ||
### useSpeech hook | ||
### `useSpeech` Hook | ||
@@ -50,8 +57,8 @@ #### Basic Usage | ||
const { | ||
Text, // Component that returns the modified text property | ||
speechStatus, // String that stores current speech status | ||
isInQueue, // Boolean that stores whether a speech utterance is either being spoken or present in queue | ||
start, // Function to start the speech or put it in queue | ||
pause, // Function to pause the speech | ||
stop, // Function to stop the speech or remove it from queue | ||
Text, // Component that renders the processed text | ||
speechStatus, // Current speech status | ||
isInQueue, // Indicates if the speech is active or queued | ||
start, // Starts or queues the speech | ||
pause, // Pauses the speech | ||
stop, // Stops or removes the speech from the queue | ||
} = useSpeech({ text: "This library is awesome!" }); | ||
@@ -73,5 +80,5 @@ | ||
For detailed usage of `useSpeech` hook, [refer here](https://rtts.vercel.app/docs/usage/useSpeech) | ||
For more details on using the `useSpeech` hook, [refer to the documentation](https://rtts.vercel.app/docs/usage/useSpeech). | ||
### Speech Component | ||
### `<Speech>` Component | ||
@@ -91,14 +98,18 @@ #### Basic Usage | ||
For detailed usage of `<Speech>` component, [refer here](https://rtts.vercel.app/docs/usage/speech) | ||
For more details on using the `<Speech>` component, [refer to the documentation](https://rtts.vercel.app/docs/usage/speech). | ||
## Demo | ||
[A Demo is worth a thousand words](https://rtts.vercel.app/demo) | ||
[Check out the live demo](https://rtts.vercel.app/demo) to see it in action. | ||
## Documentation | ||
Check the [documentation](https://rtts.vercel.app/docs/) to get you started! | ||
Explore the [documentation](https://rtts.vercel.app/docs/) to get started quickly. | ||
## Contribute | ||
Show your ❤️ and support by giving a ⭐. Any suggestions are welcome! Take a look at the [contributing guide](https://github.com/SahilAggarwal2004/react-text-to-speech/blob/master/CONTRIBUTING.md). | ||
Show your ❤️ and support by giving a ⭐ on [GitHub](https://github.com/SahilAggarwal2004/react-text-to-speech). You can also support the project by upvoting and sharing it on [Product Hunt](https://www.producthunt.com/posts/react-text-to-speech). Any suggestions are welcome! Take a look at the [contributing guide](CONTRIBUTING.md). | ||
## License | ||
This project is licensed under the [MIT License](LICENSE). |
Sorry, the diff of this file is not supported yet
31745
536
111