New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

react-text-to-speech

Package Overview
Dependencies
Maintainers
1
Versions
121
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-text-to-speech - npm Package Compare versions

Comparing version 0.13.5 to 0.14.0

dist/types.d.ts

30

dist/hooks.d.ts

@@ -1,25 +0,9 @@

import React, { DetailedHTMLProps, HTMLAttributes } from "react";
import { QueueChangeEventHandler } from "./queue.js";
export type SpanProps = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
export type SpeechSynthesisErrorHandler = (error: Error) => any;
export type SpeechSynthesisEventHandler = (event: SpeechSynthesisEvent) => any;
export type useSpeechProps = {
text: string | JSX.Element;
pitch?: number;
rate?: number;
volume?: number;
lang?: string;
voiceURI?: string | string[];
highlightText?: boolean;
highlightProps?: SpanProps;
preserveUtteranceQueue?: boolean;
onError?: SpeechSynthesisErrorHandler;
onStart?: SpeechSynthesisEventHandler;
onResume?: SpeechSynthesisEventHandler;
onPause?: SpeechSynthesisEventHandler;
onStop?: SpeechSynthesisEventHandler;
onBoundary?: SpeechSynthesisEventHandler;
onQueueChange?: QueueChangeEventHandler;
import React from "react";
import { dequeue, clearQueueHook } from "./queue.js";
import { SpeechStatus, useSpeechProps, SpeechUtterancesQueue } from "./types.js";
export declare function useQueue(): {
queue: SpeechUtterancesQueue;
dequeue: typeof dequeue;
clearQueue: typeof clearQueueHook;
};
export type SpeechStatus = "started" | "paused" | "stopped" | "queued";
export declare function useSpeech({ text, pitch, rate, volume, lang, voiceURI, highlightText, highlightProps, preserveUtteranceQueue, onError, onStart, onResume, onPause, onStop, onBoundary, onQueueChange, }: useSpeechProps): {

@@ -26,0 +10,0 @@ Text: () => React.ReactNode;

import React, { cloneElement, isValidElement, useEffect, useMemo, useRef, useState } from "react";
import { ArrayToText, JSXToArray, findCharIndex, getIndex, isParent, sanitize } from "./utils.js";
import { addToQueue, clearQueue, removeFromQueue, speakFromQueue } from "./queue.js";
function useStateRef(init) {
const [state, setState] = useState(init);
const ref = useRef(init);
function setStateRef(value) {
ref.current = value;
setState(value);
}
return [state, ref, setStateRef];
import { addToQueue, removeFromQueue, speakFromQueue, subscribe, dequeue, clearQueueHook, clearQueueUnload, clearQueue } from "./queue.js";
import { ArrayToText, JSXToArray, cancel, findCharIndex, getIndex, isParent, sanitize } from "./utils.js";
export function useQueue() {
const [queue, setQueue] = useState([]);
useEffect(() => subscribe((queue) => setQueue([...queue])), []);
return { queue, dequeue, clearQueue: clearQueueHook };
}

@@ -17,3 +13,2 @@ export function useSpeech({ text, pitch = 1, rate = 1, volume = 1, lang, voiceURI, highlightText = false, highlightProps = { style: { backgroundColor: "yellow" } }, preserveUtteranceQueue = false, onError = console.error, onStart, onResume, onPause, onStop, onBoundary, onQueueChange, }) {

const utteranceRef = useRef();
const cancel = () => { var _a; return (_a = window.speechSynthesis) === null || _a === void 0 ? void 0 : _a.cancel(); };
const [words, stringifiedWords] = useMemo(() => {

@@ -51,3 +46,3 @@ const words = JSXToArray(text);

const stopEventHandler = (event) => {
window.removeEventListener("beforeunload", cancel);
window.removeEventListener("beforeunload", clearQueueUnload);
setSpeechStatus("stopped");

@@ -66,3 +61,3 @@ setSpeakingWord(null);

utterance.onstart = (event) => {
window.addEventListener("beforeunload", cancel);
window.addEventListener("beforeunload", clearQueueUnload);
setSpeechStatus("started");

@@ -88,3 +83,3 @@ onStart === null || onStart === void 0 ? void 0 : onStart(event);

clearQueue();
addToQueue(utterance, onQueueChange);
addToQueue({ utterance, setSpeechStatus }, onQueueChange);
if (synth.speaking) {

@@ -148,1 +143,10 @@ if (preserveUtteranceQueue && speechStatus !== "started") {

}
function useStateRef(init) {
const [state, setState] = useState(init);
const ref = useRef(init);
function setStateRef(value) {
ref.current = value;
setState(value);
}
return [state, ref, setStateRef];
}
import React from "react";
export type IconProps = React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>;
import { IconProps } from "./types.js";
export declare function HiMiniStop(props: IconProps): React.JSX.Element;
export declare function HiVolumeOff(props: IconProps): React.JSX.Element;
export declare function HiVolumeUp(props: IconProps): React.JSX.Element;
export declare function HiVolumeOff(props: IconProps): React.JSX.Element;
export declare function HiMiniStop(props: IconProps): React.JSX.Element;
import React from "react";
export function HiVolumeUp(props) {
export function HiMiniStop(props) {
return (React.createElement("span", Object.assign({}, props),
React.createElement("svg", { viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": true, width: "1.25rem", height: "1.25rem" },
React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" }))));
React.createElement("path", { d: "M5.25 3A2.25 2.25 0 003 5.25v9.5A2.25 2.25 0 005.25 17h9.5A2.25 2.25 0 0017 14.75v-9.5A2.25 2.25 0 0014.75 3h-9.5z" }))));
}

@@ -12,6 +12,6 @@ export function HiVolumeOff(props) {

}
export function HiMiniStop(props) {
export function HiVolumeUp(props) {
return (React.createElement("span", Object.assign({}, props),
React.createElement("svg", { viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": true, width: "1.25rem", height: "1.25rem" },
React.createElement("path", { d: "M5.25 3A2.25 2.25 0 003 5.25v9.5A2.25 2.25 0 005.25 17h9.5A2.25 2.25 0 0017 14.75v-9.5A2.25 2.25 0 0014.75 3h-9.5z" }))));
React.createElement("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" }))));
}

@@ -1,24 +0,6 @@

import React, { DetailedHTMLProps, HTMLAttributes, ReactNode } from "react";
import { SpeechStatus, useSpeech, useSpeechProps } from "./hooks.js";
export type Button = JSX.Element | string | null;
export type DivProps = DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
export type ChildrenOptions = {
speechStatus?: SpeechStatus;
isInQueue?: boolean;
start?: Function;
pause?: Function;
stop?: Function;
};
export type Children = (childrenOptions: ChildrenOptions) => ReactNode;
export type SpeechProps = useSpeechProps & {
id?: string;
startBtn?: Button;
pauseBtn?: Button;
stopBtn?: Button;
useStopOverPause?: boolean;
props?: DivProps;
children?: Children;
};
export { useSpeech };
import React from "react";
import { useSpeech, useQueue } from "./hooks.js";
import { DivProps, SpeechProps } from "./types.js";
export declare function HighlightedText({ id, children, ...props }: DivProps): React.JSX.Element;
export default function Speech({ id, startBtn, pauseBtn, stopBtn, useStopOverPause, props, children, ...hookProps }: SpeechProps): React.JSX.Element;
export declare function HighlightedText({ id, children, ...props }: DivProps): React.JSX.Element;
export { useSpeech, useQueue };

@@ -14,5 +14,12 @@ var __rest = (this && this.__rest) || function (s, e) {

import { createPortal } from "react-dom";
import { useSpeech } from "./hooks.js";
import { useSpeech, useQueue } from "./hooks.js";
import { HiMiniStop, HiVolumeOff, HiVolumeUp } from "./icons.js";
export { useSpeech };
export function HighlightedText(_a) {
var { id, children } = _a, props = __rest(_a, ["id", "children"]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (React.createElement("div", Object.assign({ id: `rtts-${id}` }, props), loading && (typeof children === "string" ? React.createElement("span", null, children) : children)));
}
export default function Speech(_a) {

@@ -35,9 +42,2 @@ 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"]);

}
export function HighlightedText(_a) {
var { id, children } = _a, props = __rest(_a, ["id", "children"]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(false);
}, []);
return (React.createElement("div", Object.assign({ id: `rtts-${id}` }, props), loading && (typeof children === "string" ? React.createElement("span", null, children) : children)));
}
export { useSpeech, useQueue };

@@ -1,6 +0,11 @@

export type SpeechUtterancesQueue = SpeechSynthesisUtterance[];
export type QueueChangeEventHandler = (queue: SpeechUtterancesQueue) => any;
export declare function addToQueue(utterance: SpeechSynthesisUtterance, callback?: QueueChangeEventHandler): void;
import { QueueChangeEventHandler, SpeechQueueItem } from "./types.js";
export declare function clearQueue(start?: number, emitEvent?: boolean): void;
export declare function addToQueue(item: SpeechQueueItem, callback?: QueueChangeEventHandler): void;
export declare function clearQueueHook(): void;
export declare function clearQueueUnload(): void;
export declare function dequeue(index?: number): void;
export declare function emit(callback?: QueueChangeEventHandler): void;
export declare function removeFromQueue(utterance: SpeechSynthesisUtterance, callback?: QueueChangeEventHandler): void;
export declare function clearQueue(): void;
export declare function removeFromQueue(utterance: number): void;
export declare function speakFromQueue(): void;
export declare function subscribe(callback: QueueChangeEventHandler): () => void;

@@ -1,20 +0,55 @@

let queue = [];
export function addToQueue(utterance, callback) {
queue.push(utterance);
callback === null || callback === void 0 ? void 0 : callback(queue);
import { cancel } from "./utils.js";
const queue = [];
const queueListeners = [];
export function clearQueue(start = 0, emitEvent = false) {
queue.slice(start).forEach(({ setSpeechStatus }) => setSpeechStatus("stopped"));
queue.length = 0;
if (emitEvent)
emit();
}
export function addToQueue(item, callback) {
queue.push(item);
emit(callback);
}
export function clearQueueHook() {
cancel();
clearQueue(1, true);
}
export function clearQueueUnload() {
cancel();
clearQueue(1);
}
export function dequeue(index = 0) {
if (index === 0)
cancel();
else
removeFromQueue(index);
}
export function emit(callback) {
const utteranceQueue = queue.map(({ utterance }) => utterance);
queueListeners.forEach((listener) => listener(utteranceQueue));
callback === null || callback === void 0 ? void 0 : callback(utteranceQueue);
}
export function removeFromQueue(utterance, callback) {
const index = queue.indexOf(utterance);
const index = typeof utterance === "number" ? utterance : queue.findIndex((item) => item.utterance === utterance);
if (index === -1)
return;
queue.splice(index, 1);
callback === null || callback === void 0 ? void 0 : callback(queue);
const [item] = queue.splice(index, 1);
if (item) {
item.setSpeechStatus("stopped");
emit(callback);
}
}
export function clearQueue() {
queue = [];
}
export function speakFromQueue() {
const utterance = queue[0];
if (utterance)
speechSynthesis.speak(utterance);
const item = queue[0];
if (item)
speechSynthesis.speak(item.utterance);
}
export function subscribe(callback) {
queueListeners.push(callback);
return () => {
const index = queueListeners.indexOf(callback);
if (index !== -1)
queueListeners.splice(index, 1);
};
}
import { ReactNode } from "react";
export type Index = string | number;
export type StringArray = string | StringArray[];
export declare const getIndex: (parentIndex: Index, index: Index) => string;
export declare const sanitize: (text: string) => string;
import { Index, StringArray } from "./types.js";
export declare function ArrayToText(element: StringArray): string;
export declare function JSXToArray(element: ReactNode): StringArray;
export declare function ArrayToText(element: StringArray): string;
export declare function cancel(): void;
export declare function findCharIndex(words: StringArray, index: number): string;
export declare function getIndex(parentIndex: Index, index: Index): string;
export declare function isParent(parentIndex: string, index?: string): boolean;
export declare const sanitize: (text: string) => string;
import { isValidElement } from "react";
export const getIndex = (parentIndex, index) => `${parentIndex === "" ? "" : parentIndex + "-"}${index}`;
export const sanitize = (text) => text.replace(/[;<>]/g, (match) => (match === ">" ? ")" : "("));
export function ArrayToText(element) {
if (typeof element === "string")
return element;
return element.map(ArrayToText).join(" ") + " ";
}
export function JSXToArray(element) {

@@ -13,6 +16,6 @@ if (isValidElement(element)) {

}
export function ArrayToText(element) {
if (typeof element === "string")
return element;
return element.map(ArrayToText).join(" ") + " ";
export function cancel() {
var _a;
if (typeof window !== "undefined")
(_a = window.speechSynthesis) === null || _a === void 0 ? void 0 : _a.cancel();
}

@@ -37,2 +40,5 @@ export function findCharIndex(words, index) {

}
export function getIndex(parentIndex, index) {
return `${parentIndex === "" ? "" : parentIndex + "-"}${index}`;
}
export function isParent(parentIndex, index) {

@@ -51,1 +57,2 @@ if (!(index === null || index === void 0 ? void 0 : index.startsWith(parentIndex)))

}
export const sanitize = (text) => text.replace(/[;<>]/g, (match) => (match === ">" ? ")" : "("));
{
"name": "react-text-to-speech",
"version": "0.13.5",
"version": "0.14.0",
"description": "An easy to use react component for the Web Speech API.",

@@ -41,4 +41,4 @@ "type": "module",

"@types/react": "^18.2.74",
"@types/react-dom": "^18.2.23"
"@types/react-dom": "^18.2.24"
}
}

@@ -167,13 +167,11 @@ # react-text-to-speech

The `preserveUtteranceQueue` prop, available in both `useSpeech` hook and `<Speech>` component, facilitates handling multiple speech instances simultaneously.
If set to `false`, any currently speaking speech utterance will be stopped immediately upon initiating a new utterance. The new utterance will be spoken without waiting for the previous one to finish.
The `preserveUtteranceQueue` prop, available in both `useSpeech` hook and `<Speech>` component, facilitates handling multiple speech instances simultaneously.\
If set to `false`, any currently speaking speech utterance will be stopped immediately upon initiating a new utterance. The new utterance will be spoken without waiting for the previous one to finish.\
If set to `true`, new speech utterances will be added to a queue. They will be spoken once the previous speech instances are completed. This allows for sequential delivery of speech content, maintaining order and avoiding overlapping utterances.
`TIP`: The `onQueueChange` event handler used [above](#handling-errors-and-events) runs whenever queue updates.
The `useQueue` hook can be used to keep track of the queue as well as change the queue as shown below. The `onQueueChange` event handler used [above](#handling-errors-and-events) can also be used to keep track of queue updates.
```jsx
import React, { useMemo } from "react";
import { useSpeech } from "react-text-to-speech";
import { useQueue, useSpeech } from "../components/dist";

@@ -207,8 +205,28 @@ function NewsItem({ title, desc }) {

];
const {
queue, // Queue that stores all the speech utterances
clearQueue, // Function to clear the queue
dequeue, // Function to remove a speech utterance from the queue at a specific index
} = useQueue();
return (
<div style={{ display: "flex", flexDirection: "column", rowGap: "1rem" }}>
{news.map(({ id, title, desc }) => (
<NewsItem key={id} title={title} desc={desc} />
))}
<div>
<div style={{ display: "flex", flexDirection: "column", rowGap: "1rem" }}>
{news.map(({ id, title, desc }) => (
<NewsItem key={id} title={title} desc={desc} />
))}
</div>
<div style={{ display: "flex", flexDirection: "column", rowGap: "1rem", marginBlock: "2rem" }}>
{queue.length ? (
queue.map(({ text }, i) => (
<div key={i}>
<button onClick={() => dequeue(i)}>Dequeue</button>
<span style={{ marginLeft: "1rem" }}>{text}</span>
</div>
))
) : (
<div>Queue is Empty</div>
)}
</div>
<button onClick={clearQueue}>Clear Queue</button>
</div>

@@ -215,0 +233,0 @@ );

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc