Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tts-react

Package Overview
Dependencies
Maintainers
1
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tts-react - npm Package Compare versions

Comparing version 3.0.2 to 3.0.3

4

dist/component.d.ts

@@ -1,2 +0,2 @@

import React from 'react';
/// <reference types="react" />
import type { TTSHookProps } from './hook.js';

@@ -46,5 +46,5 @@ import type { SvgProps } from './icons.js';

*/
declare const TextToSpeech: ({ size, lang, rate, voice, volume, children, position, onStart, onPause, onBoundary, onEnd, onError, onMuteToggled, onVolumeChange, onPitchChange, onRateChange, fetchAudioData, markColor, markBackgroundColor, autoPlay, allowMuting, align, markTextAsSpoken, useStopOverPause }: TTSProps) => React.JSX.Element;
declare const TextToSpeech: ({ size, lang, rate, voice, volume, children, position, onStart, onPause, onBoundary, onEnd, onError, onMuteToggled, onVolumeChange, onPitchChange, onRateChange, fetchAudioData, markColor, markBackgroundColor, autoPlay, allowMuting, align, markTextAsSpoken, useStopOverPause }: TTSProps) => JSX.Element;
export { Sizes } from './icons.js';
export { TextToSpeech, Positions };
export type { TTSProps };

@@ -1,2 +0,1 @@

import React from 'react';
import type { MouseEventHandler } from 'react';

@@ -16,4 +15,4 @@ import { Sizes } from './icons.js';

};
declare const Control: ({ title, type, onClick, size, align, ...rest }: ControlProps) => React.JSX.Element;
declare const Control: ({ title, type, onClick, size, align, ...rest }: ControlProps) => JSX.Element;
export { Control, padding };
export type { ControlProps };

@@ -1,10 +0,1 @@

function _classPrivateMethodInitSpec(obj, privateSet) { _checkPrivateRedeclaration(obj, privateSet); privateSet.add(obj); }
function _classPrivateFieldInitSpec(obj, privateMap, value) { _checkPrivateRedeclaration(obj, privateMap); privateMap.set(obj, value); }
function _checkPrivateRedeclaration(obj, privateCollection) { if (privateCollection.has(obj)) { throw new TypeError("Cannot initialize the same private elements twice on an object"); } }
function _classPrivateMethodGet(receiver, privateSet, fn) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return fn; }
function _classPrivateFieldGet(receiver, privateMap) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "get"); return _classApplyDescriptorGet(receiver, descriptor); }
function _classApplyDescriptorGet(receiver, descriptor) { if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }
function _classPrivateFieldSet(receiver, privateMap, value) { var descriptor = _classExtractFieldDescriptor(receiver, privateMap, "set"); _classApplyDescriptorSet(receiver, descriptor, value); return value; }
function _classExtractFieldDescriptor(receiver, privateMap, action) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to " + action + " private field on non-instance"); } return privateMap.get(receiver); }
function _classApplyDescriptorSet(receiver, descriptor, value) { if (descriptor.set) { descriptor.set.call(receiver, value); } else { if (!descriptor.writable) { throw new TypeError("attempted to set read only private field"); } descriptor.value = value; } }
import { isPunctuation } from './utils.js';

@@ -23,107 +14,29 @@ var Events = /*#__PURE__*/function (Events) {

}(Events || {});
var _target = /*#__PURE__*/new WeakMap();
var _synthesizer = /*#__PURE__*/new WeakMap();
var _dispatchBoundaries = /*#__PURE__*/new WeakMap();
var _fetchAudioData = /*#__PURE__*/new WeakMap();
var _marks = /*#__PURE__*/new WeakMap();
var _text = /*#__PURE__*/new WeakMap();
var _lang = /*#__PURE__*/new WeakMap();
var _aborter = /*#__PURE__*/new WeakMap();
var _initialized = /*#__PURE__*/new WeakMap();
var _initWebSpeechVoice = /*#__PURE__*/new WeakSet();
var _attachAudioSource = /*#__PURE__*/new WeakSet();
var _dispatchEnd = /*#__PURE__*/new WeakSet();
var _dispatchError = /*#__PURE__*/new WeakSet();
var _dispatchReady = /*#__PURE__*/new WeakSet();
var _dispatchPlaying = /*#__PURE__*/new WeakSet();
var _dispatchPaused = /*#__PURE__*/new WeakSet();
var _dispatchBoundary = /*#__PURE__*/new WeakSet();
var _dispatchVolume = /*#__PURE__*/new WeakSet();
var _dispatchRate = /*#__PURE__*/new WeakSet();
var _dispatchPitch = /*#__PURE__*/new WeakSet();
var _playHtmlAudio = /*#__PURE__*/new WeakSet();
var _getPollySpeechMarkForAudioTime = /*#__PURE__*/new WeakSet();
var _getBoundaryWordCharLength = /*#__PURE__*/new WeakSet();
var _clamp = /*#__PURE__*/new WeakSet();
var _recycle = /*#__PURE__*/new WeakSet();
var _utteranceInit = /*#__PURE__*/new WeakSet();
var _htmlAudioInit = /*#__PURE__*/new WeakSet();
class Controller extends EventTarget {
#target;
#synthesizer;
#dispatchBoundaries = true;
#fetchAudioData = async () => ({
audio: '',
marks: []
});
#marks = [];
#text = '';
#lang = '';
#aborter = new AbortController();
#initialized = false;
constructor(options) {
super();
_classPrivateMethodInitSpec(this, _htmlAudioInit);
_classPrivateMethodInitSpec(this, _utteranceInit);
/**
* Removes registered listeners and creates new abort controller.
*/
_classPrivateMethodInitSpec(this, _recycle);
_classPrivateMethodInitSpec(this, _clamp);
/**
* Not all browsers return `evt.charLength` on SpeechSynthesisUtterance `boundary` events.
*/
_classPrivateMethodInitSpec(this, _getBoundaryWordCharLength);
_classPrivateMethodInitSpec(this, _getPollySpeechMarkForAudioTime);
_classPrivateMethodInitSpec(this, _playHtmlAudio);
_classPrivateMethodInitSpec(this, _dispatchPitch);
_classPrivateMethodInitSpec(this, _dispatchRate);
_classPrivateMethodInitSpec(this, _dispatchVolume);
_classPrivateMethodInitSpec(this, _dispatchBoundary);
_classPrivateMethodInitSpec(this, _dispatchPaused);
_classPrivateMethodInitSpec(this, _dispatchPlaying);
_classPrivateMethodInitSpec(this, _dispatchReady);
_classPrivateMethodInitSpec(this, _dispatchError);
_classPrivateMethodInitSpec(this, _dispatchEnd);
_classPrivateMethodInitSpec(this, _attachAudioSource);
_classPrivateMethodInitSpec(this, _initWebSpeechVoice);
_classPrivateFieldInitSpec(this, _target, {
writable: true,
value: void 0
});
_classPrivateFieldInitSpec(this, _synthesizer, {
writable: true,
value: void 0
});
_classPrivateFieldInitSpec(this, _dispatchBoundaries, {
writable: true,
value: true
});
_classPrivateFieldInitSpec(this, _fetchAudioData, {
writable: true,
value: async () => ({
audio: '',
marks: []
})
});
_classPrivateFieldInitSpec(this, _marks, {
writable: true,
value: []
});
_classPrivateFieldInitSpec(this, _text, {
writable: true,
value: ''
});
_classPrivateFieldInitSpec(this, _lang, {
writable: true,
value: ''
});
_classPrivateFieldInitSpec(this, _aborter, {
writable: true,
value: new AbortController()
});
_classPrivateFieldInitSpec(this, _initialized, {
writable: true,
value: false
});
_classPrivateFieldSet(this, _lang, options?.lang ?? _classPrivateFieldGet(this, _lang));
_classPrivateFieldSet(this, _synthesizer, window.speechSynthesis);
_classPrivateFieldSet(this, _target, new SpeechSynthesisUtterance(_classPrivateFieldGet(this, _text)));
_classPrivateFieldSet(this, _dispatchBoundaries, options?.dispatchBoundaries ?? _classPrivateFieldGet(this, _dispatchBoundaries));
this.#lang = options?.lang ?? this.#lang;
this.#synthesizer = window.speechSynthesis;
this.#target = new SpeechSynthesisUtterance(this.#text);
this.#dispatchBoundaries = options?.dispatchBoundaries ?? this.#dispatchBoundaries;
if (options?.fetchAudioData) {
_classPrivateFieldSet(this, _target, _classPrivateFieldSet(this, _synthesizer, new Audio()));
_classPrivateFieldSet(this, _fetchAudioData, options.fetchAudioData);
this.#target = this.#synthesizer = new Audio();
this.#fetchAudioData = options.fetchAudioData;
} else {
_classPrivateMethodGet(this, _initWebSpeechVoice, _initWebSpeechVoice2).call(this, options?.voice);
this.#initWebSpeechVoice(options?.voice);
if (window.speechSynthesis) {
window.speechSynthesis.onvoiceschanged = () => {
_classPrivateMethodGet(this, _initWebSpeechVoice, _initWebSpeechVoice2).call(this, options?.voice);
this.#initWebSpeechVoice(options?.voice);
};

@@ -133,33 +46,233 @@ }

}
#initWebSpeechVoice(voice) {
if (this.#target instanceof SpeechSynthesisUtterance) {
let voices = window.speechSynthesis.getVoices();
if (voice) {
this.#target.voice = voice;
}
if (this.#lang) {
voices = voices.filter(voice => voice.lang === this.#lang);
this.#target.voice = voices[0] ?? null;
if (voice && voice.lang === this.#lang) {
this.#target.voice = voice;
}
}
}
}
async #attachAudioSource() {
if (this.#synthesizer instanceof HTMLAudioElement) {
let data = null;
try {
data = await this.#fetchAudioData(this.#text);
} catch (err) {
if (err instanceof Error) {
this.#dispatchError(err.message);
}
} finally {
if (data?.audio) {
this.#synthesizer.src = data.audio;
this.#marks = data.marks ?? this.#marks;
}
}
}
}
#dispatchEnd(evt) {
this.dispatchEvent(new CustomEvent(Events.END, {
detail: evt
}));
}
#dispatchError(msg) {
this.dispatchEvent(new CustomEvent(Events.ERROR, {
detail: msg
}));
}
#dispatchReady() {
this.dispatchEvent(new Event(Events.READY));
}
#dispatchPlaying(evt) {
this.dispatchEvent(new CustomEvent(Events.PLAYING, {
detail: evt
}));
}
#dispatchPaused(evt) {
this.dispatchEvent(new CustomEvent(Events.PAUSED, {
detail: evt
}));
}
#dispatchBoundary(evt, boundary) {
this.dispatchEvent(new CustomEvent(Events.BOUNDARY, {
detail: {
evt,
boundary
}
}));
}
#dispatchVolume(volume) {
this.dispatchEvent(new CustomEvent(Events.VOLUME, {
detail: volume
}));
}
#dispatchRate(rate) {
this.dispatchEvent(new CustomEvent(Events.RATE, {
detail: rate
}));
}
#dispatchPitch(pitch) {
this.dispatchEvent(new CustomEvent(Events.PITCH, {
detail: pitch
}));
}
async #playHtmlAudio() {
const audio = this.#synthesizer;
try {
await audio.play();
} catch (err) {
if (err instanceof Error) {
this.#dispatchError(err.message);
}
}
}
#getPollySpeechMarkForAudioTime(time) {
const length = this.#marks.length;
let bestMatch = this.#marks[0];
let found = false;
let i = 1;
while (i < length && !found) {
if (this.#marks[i].time <= time) {
bestMatch = this.#marks[i];
} else {
found = true;
}
i++;
}
return bestMatch;
}
/**
* Not all browsers return `evt.charLength` on SpeechSynthesisUtterance `boundary` events.
*/
#getBoundaryWordCharLength(startIndex) {
const match = this.#text.substring(startIndex).match(/.+?\b/);
return match ? match[0].length : 0;
}
#clamp(value) {
let min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
let max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
return Math.max(min, Math.min(value, max));
}
/**
* Removes registered listeners and creates new abort controller.
*/
#recycle() {
this.#aborter.abort();
this.#aborter = new AbortController();
return this.#aborter.signal;
}
#utteranceInit() {
if (this.#target instanceof SpeechSynthesisUtterance) {
const signal = this.#recycle();
this.#target.addEventListener('end', this.#dispatchEnd.bind(this), {
signal
});
this.#target.addEventListener('start', this.#dispatchPlaying.bind(this), {
signal
});
this.#target.addEventListener('resume', this.#dispatchPlaying.bind(this), {
signal
});
this.#target.addEventListener('pause', this.#dispatchPaused.bind(this), {
signal
});
this.#target.addEventListener('error', evt => {
this.#dispatchError(evt.error);
}, {
signal
});
if (this.#lang) {
this.#target.lang = this.#lang;
}
if (this.#dispatchBoundaries) {
this.#target.addEventListener('boundary', evt => {
const {
charIndex: startChar
} = evt;
const charLength = evt.charLength ?? this.#getBoundaryWordCharLength(startChar);
const endChar = startChar + charLength;
const word = this.#text.substring(startChar, endChar);
if (word && !isPunctuation(word)) {
this.#dispatchBoundary(evt, {
word,
startChar,
endChar
});
}
}, {
signal
});
}
this.#dispatchReady();
}
}
async #htmlAudioInit() {
if (this.#target instanceof HTMLAudioElement) {
const target = this.#target;
this.#target.addEventListener('canplay', this.#dispatchReady.bind(this), {
once: true
});
this.#target.addEventListener('playing', this.#dispatchPlaying.bind(this));
this.#target.addEventListener('pause', this.#dispatchPaused.bind(this));
this.#target.addEventListener('ended', this.#dispatchEnd.bind(this));
this.#target.addEventListener('error', () => {
const error = target.error;
this.#dispatchError(error?.message);
});
if (this.#dispatchBoundaries) {
this.#target.addEventListener('timeupdate', evt => {
// Polly Speech Marks use milliseconds
const currentTime = target.currentTime * 1000;
const mark = this.#getPollySpeechMarkForAudioTime(currentTime);
if (mark && !this.paused) {
this.#dispatchBoundary(evt, {
word: mark.value,
startChar: mark.start,
endChar: mark.end
});
}
});
}
await this.#attachAudioSource();
}
}
get synthesizer() {
return _classPrivateFieldGet(this, _synthesizer);
return this.#synthesizer;
}
get target() {
return _classPrivateFieldGet(this, _target);
return this.#target;
}
set text(value) {
_classPrivateFieldSet(this, _text, value);
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
_classPrivateFieldGet(this, _target).text = value;
this.#text = value;
if (this.#target instanceof SpeechSynthesisUtterance) {
this.#target.text = value;
}
}
get paused() {
return _classPrivateFieldGet(this, _synthesizer).paused;
return this.#synthesizer.paused;
}
get rate() {
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
return _classPrivateFieldGet(this, _synthesizer).playbackRate;
if (this.#synthesizer instanceof HTMLAudioElement) {
return this.#synthesizer.playbackRate;
}
return _classPrivateFieldGet(this, _target).rate;
return this.#target.rate;
}
set rate(value) {
const clamped = _classPrivateMethodGet(this, _clamp, _clamp2).call(this, parseFloat(value.toPrecision(3)), 0.1, 10);
const clamped = this.#clamp(parseFloat(value.toPrecision(3)), 0.1, 10);
if (!Number.isNaN(clamped)) {
_classPrivateMethodGet(this, _dispatchRate, _dispatchRate2).call(this, clamped);
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
_classPrivateFieldGet(this, _synthesizer).defaultPlaybackRate = clamped;
_classPrivateFieldGet(this, _synthesizer).playbackRate = clamped;
this.#dispatchRate(clamped);
if (this.#synthesizer instanceof HTMLAudioElement) {
this.#synthesizer.defaultPlaybackRate = clamped;
this.#synthesizer.playbackRate = clamped;
}
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
_classPrivateFieldGet(this, _target).rate = clamped;
if (this.#target instanceof SpeechSynthesisUtterance) {
this.#target.rate = clamped;
}

@@ -169,4 +282,4 @@ }

get pitch() {
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
return _classPrivateFieldGet(this, _target).pitch;
if (this.#target instanceof SpeechSynthesisUtterance) {
return this.#target.pitch;
}

@@ -178,7 +291,7 @@

set pitch(value) {
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
const clamped = _classPrivateMethodGet(this, _clamp, _clamp2).call(this, parseFloat(value.toPrecision(2)), 0, 2);
if (this.#target instanceof SpeechSynthesisUtterance) {
const clamped = this.#clamp(parseFloat(value.toPrecision(2)), 0, 2);
if (!Number.isNaN(clamped)) {
_classPrivateMethodGet(this, _dispatchPitch, _dispatchPitch2).call(this, clamped);
_classPrivateFieldGet(this, _target).pitch = clamped;
this.#dispatchPitch(clamped);
this.#target.pitch = clamped;
}

@@ -194,14 +307,14 @@ }

get volume() {
return _classPrivateFieldGet(this, _target).volume;
return this.#target.volume;
}
set volume(value) {
const clamped = _classPrivateMethodGet(this, _clamp, _clamp2).call(this, parseFloat(value.toPrecision(2)), this.volumeMin, this.volumeMax);
const clamped = this.#clamp(parseFloat(value.toPrecision(2)), this.volumeMin, this.volumeMax);
if (!Number.isNaN(clamped)) {
_classPrivateMethodGet(this, _dispatchVolume, _dispatchVolume2).call(this, clamped);
_classPrivateFieldGet(this, _target).volume = clamped;
this.#dispatchVolume(clamped);
this.#target.volume = clamped;
}
}
get preservesPitch() {
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
return _classPrivateFieldGet(this, _synthesizer).preservesPitch;
if (this.#synthesizer instanceof HTMLAudioElement) {
return this.#synthesizer.preservesPitch;
}

@@ -215,17 +328,17 @@ return false;

*/
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
if (this.#synthesizer instanceof HTMLAudioElement) {
// eslint-disable-next-line @typescript-eslint/no-extra-semi
;
_classPrivateFieldGet(this, _synthesizer).preservesPitch = value;
this.#synthesizer.preservesPitch = value;
}
}
get lang() {
return _classPrivateFieldGet(this, _lang);
return this.#lang;
}
set lang(value) {
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
_classPrivateFieldSet(this, _lang, value);
_classPrivateFieldGet(this, _target).lang = value;
_classPrivateFieldGet(this, _target).voice = null;
_classPrivateMethodGet(this, _initWebSpeechVoice, _initWebSpeechVoice2).call(this);
if (this.#target instanceof SpeechSynthesisUtterance) {
this.#lang = value;
this.#target.lang = value;
this.#target.voice = null;
this.#initWebSpeechVoice();
}

@@ -242,47 +355,47 @@ }

async init() {
if (!_classPrivateFieldGet(this, _initialized)) {
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
_classPrivateMethodGet(this, _utteranceInit, _utteranceInit2).call(this);
if (!this.#initialized) {
if (this.#target instanceof SpeechSynthesisUtterance) {
this.#utteranceInit();
}
if (_classPrivateFieldGet(this, _target) instanceof HTMLAudioElement) {
await _classPrivateMethodGet(this, _htmlAudioInit, _htmlAudioInit2).call(this);
if (this.#target instanceof HTMLAudioElement) {
await this.#htmlAudioInit();
}
_classPrivateFieldSet(this, _initialized, true);
this.#initialized = true;
}
}
async play() {
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
await _classPrivateMethodGet(this, _playHtmlAudio, _playHtmlAudio2).call(this);
if (this.#synthesizer instanceof HTMLAudioElement) {
await this.#playHtmlAudio();
} else {
_classPrivateFieldGet(this, _synthesizer).speak(_classPrivateFieldGet(this, _target));
this.#synthesizer.speak(this.#target);
}
}
pause() {
_classPrivateFieldGet(this, _synthesizer).pause();
this.#synthesizer.pause();
}
async resume() {
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
await _classPrivateMethodGet(this, _playHtmlAudio, _playHtmlAudio2).call(this);
if (this.#synthesizer instanceof HTMLAudioElement) {
await this.#playHtmlAudio();
} else {
_classPrivateFieldGet(this, _synthesizer).resume();
this.#synthesizer.resume();
}
}
async replay() {
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
_classPrivateFieldGet(this, _synthesizer).load();
await _classPrivateMethodGet(this, _playHtmlAudio, _playHtmlAudio2).call(this);
if (this.#synthesizer instanceof HTMLAudioElement) {
this.#synthesizer.load();
await this.#playHtmlAudio();
} else {
// Take out of any paused state
_classPrivateFieldGet(this, _synthesizer).resume();
this.#synthesizer.resume();
// Drop all utterances in the queue
_classPrivateFieldGet(this, _synthesizer).cancel();
this.#synthesizer.cancel();
// Start speaking from the beginning
_classPrivateFieldGet(this, _synthesizer).speak(_classPrivateFieldGet(this, _target));
this.#synthesizer.speak(this.#target);
}
}
cancel() {
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
_classPrivateFieldGet(this, _synthesizer).load();
if (this.#synthesizer instanceof HTMLAudioElement) {
this.#synthesizer.load();
} else {
_classPrivateFieldGet(this, _synthesizer).cancel();
this.#synthesizer.cancel();
}

@@ -297,3 +410,3 @@ }

*/
if (!(_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) && !this.paused && _classPrivateFieldGet(this, _synthesizer).speaking) {
if (!(this.#synthesizer instanceof HTMLAudioElement) && !this.paused && this.#synthesizer.speaking) {
this.replay();

@@ -308,3 +421,3 @@ }

*/
if (!(_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) && !this.paused && _classPrivateFieldGet(this, _synthesizer).speaking) {
if (!(this.#synthesizer instanceof HTMLAudioElement) && !this.paused && this.#synthesizer.speaking) {
this.replay();

@@ -314,194 +427,2 @@ }

}
function _initWebSpeechVoice2(voice) {
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
let voices = window.speechSynthesis.getVoices();
if (voice) {
_classPrivateFieldGet(this, _target).voice = voice;
}
if (_classPrivateFieldGet(this, _lang)) {
voices = voices.filter(voice => voice.lang === _classPrivateFieldGet(this, _lang));
_classPrivateFieldGet(this, _target).voice = voices[0] ?? null;
if (voice && voice.lang === _classPrivateFieldGet(this, _lang)) {
_classPrivateFieldGet(this, _target).voice = voice;
}
}
}
}
async function _attachAudioSource2() {
if (_classPrivateFieldGet(this, _synthesizer) instanceof HTMLAudioElement) {
let data = null;
try {
data = await _classPrivateFieldGet(this, _fetchAudioData).call(this, _classPrivateFieldGet(this, _text));
} catch (err) {
if (err instanceof Error) {
_classPrivateMethodGet(this, _dispatchError, _dispatchError2).call(this, err.message);
}
} finally {
if (data?.audio) {
_classPrivateFieldGet(this, _synthesizer).src = data.audio;
_classPrivateFieldSet(this, _marks, data.marks ?? _classPrivateFieldGet(this, _marks));
}
}
}
}
function _dispatchEnd2(evt) {
this.dispatchEvent(new CustomEvent(Events.END, {
detail: evt
}));
}
function _dispatchError2(msg) {
this.dispatchEvent(new CustomEvent(Events.ERROR, {
detail: msg
}));
}
function _dispatchReady2() {
this.dispatchEvent(new Event(Events.READY));
}
function _dispatchPlaying2(evt) {
this.dispatchEvent(new CustomEvent(Events.PLAYING, {
detail: evt
}));
}
function _dispatchPaused2(evt) {
this.dispatchEvent(new CustomEvent(Events.PAUSED, {
detail: evt
}));
}
function _dispatchBoundary2(evt, boundary) {
this.dispatchEvent(new CustomEvent(Events.BOUNDARY, {
detail: {
evt,
boundary
}
}));
}
function _dispatchVolume2(volume) {
this.dispatchEvent(new CustomEvent(Events.VOLUME, {
detail: volume
}));
}
function _dispatchRate2(rate) {
this.dispatchEvent(new CustomEvent(Events.RATE, {
detail: rate
}));
}
function _dispatchPitch2(pitch) {
this.dispatchEvent(new CustomEvent(Events.PITCH, {
detail: pitch
}));
}
async function _playHtmlAudio2() {
const audio = _classPrivateFieldGet(this, _synthesizer);
try {
await audio.play();
} catch (err) {
if (err instanceof Error) {
_classPrivateMethodGet(this, _dispatchError, _dispatchError2).call(this, err.message);
}
}
}
function _getPollySpeechMarkForAudioTime2(time) {
const length = _classPrivateFieldGet(this, _marks).length;
let bestMatch = _classPrivateFieldGet(this, _marks)[0];
let found = false;
let i = 1;
while (i < length && !found) {
if (_classPrivateFieldGet(this, _marks)[i].time <= time) {
bestMatch = _classPrivateFieldGet(this, _marks)[i];
} else {
found = true;
}
i++;
}
return bestMatch;
}
function _getBoundaryWordCharLength2(startIndex) {
const match = _classPrivateFieldGet(this, _text).substring(startIndex).match(/.+?\b/);
return match ? match[0].length : 0;
}
function _clamp2(value) {
let min = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
let max = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
return Math.max(min, Math.min(value, max));
}
function _recycle2() {
_classPrivateFieldGet(this, _aborter).abort();
_classPrivateFieldSet(this, _aborter, new AbortController());
return _classPrivateFieldGet(this, _aborter).signal;
}
function _utteranceInit2() {
if (_classPrivateFieldGet(this, _target) instanceof SpeechSynthesisUtterance) {
const signal = _classPrivateMethodGet(this, _recycle, _recycle2).call(this);
_classPrivateFieldGet(this, _target).addEventListener('end', _classPrivateMethodGet(this, _dispatchEnd, _dispatchEnd2).bind(this), {
signal
});
_classPrivateFieldGet(this, _target).addEventListener('start', _classPrivateMethodGet(this, _dispatchPlaying, _dispatchPlaying2).bind(this), {
signal
});
_classPrivateFieldGet(this, _target).addEventListener('resume', _classPrivateMethodGet(this, _dispatchPlaying, _dispatchPlaying2).bind(this), {
signal
});
_classPrivateFieldGet(this, _target).addEventListener('pause', _classPrivateMethodGet(this, _dispatchPaused, _dispatchPaused2).bind(this), {
signal
});
_classPrivateFieldGet(this, _target).addEventListener('error', evt => {
_classPrivateMethodGet(this, _dispatchError, _dispatchError2).call(this, evt.error);
}, {
signal
});
if (_classPrivateFieldGet(this, _lang)) {
_classPrivateFieldGet(this, _target).lang = _classPrivateFieldGet(this, _lang);
}
if (_classPrivateFieldGet(this, _dispatchBoundaries)) {
_classPrivateFieldGet(this, _target).addEventListener('boundary', evt => {
const {
charIndex: startChar
} = evt;
const charLength = evt.charLength ?? _classPrivateMethodGet(this, _getBoundaryWordCharLength, _getBoundaryWordCharLength2).call(this, startChar);
const endChar = startChar + charLength;
const word = _classPrivateFieldGet(this, _text).substring(startChar, endChar);
if (word && !isPunctuation(word)) {
_classPrivateMethodGet(this, _dispatchBoundary, _dispatchBoundary2).call(this, evt, {
word,
startChar,
endChar
});
}
}, {
signal
});
}
_classPrivateMethodGet(this, _dispatchReady, _dispatchReady2).call(this);
}
}
async function _htmlAudioInit2() {
if (_classPrivateFieldGet(this, _target) instanceof HTMLAudioElement) {
const target = _classPrivateFieldGet(this, _target);
_classPrivateFieldGet(this, _target).addEventListener('canplay', _classPrivateMethodGet(this, _dispatchReady, _dispatchReady2).bind(this), {
once: true
});
_classPrivateFieldGet(this, _target).addEventListener('playing', _classPrivateMethodGet(this, _dispatchPlaying, _dispatchPlaying2).bind(this));
_classPrivateFieldGet(this, _target).addEventListener('pause', _classPrivateMethodGet(this, _dispatchPaused, _dispatchPaused2).bind(this));
_classPrivateFieldGet(this, _target).addEventListener('ended', _classPrivateMethodGet(this, _dispatchEnd, _dispatchEnd2).bind(this));
_classPrivateFieldGet(this, _target).addEventListener('error', () => {
const error = target.error;
_classPrivateMethodGet(this, _dispatchError, _dispatchError2).call(this, error?.message);
});
if (_classPrivateFieldGet(this, _dispatchBoundaries)) {
_classPrivateFieldGet(this, _target).addEventListener('timeupdate', evt => {
// Polly Speech Marks use milliseconds
const currentTime = target.currentTime * 1000;
const mark = _classPrivateMethodGet(this, _getPollySpeechMarkForAudioTime, _getPollySpeechMarkForAudioTime2).call(this, currentTime);
if (mark && !this.paused) {
_classPrivateMethodGet(this, _dispatchBoundary, _dispatchBoundary2).call(this, evt, {
word: mark.value,
startChar: mark.start,
endChar: mark.end
});
}
});
}
await _classPrivateMethodGet(this, _attachAudioSource, _attachAudioSource2).call(this);
}
}
export { Controller, Events };

@@ -1,2 +0,2 @@

import React from 'react';
/// <reference types="react" />
interface HighliterProps {

@@ -8,3 +8,3 @@ text: string;

}
declare const Highlighter: ({ text, mark, color, backgroundColor }: HighliterProps) => React.JSX.Element;
declare const Highlighter: ({ text, mark, color, backgroundColor }: HighliterProps) => JSX.Element;
export { Highlighter };

@@ -1,2 +0,116 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e||self).TTSReact={},e.React)}(this,function(e,t){function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var i=/*#__PURE__*/n(t),r=0;function s(e){return"__private_"+r+++"_"+e}function o(e,t){if(!Object.prototype.hasOwnProperty.call(e,t))throw new TypeError("attempted to use private field on non-instance");return e}const a=/[^\P{P}'/-]+/gu,l=e=>e.replace(a,"");function c(e,t){try{var n=e()}catch(e){return t(e)}return n&&n.then?n.then(void 0,t):n}const u=function(){try{const e=this,t=function(){if(o(e,v)[v]instanceof HTMLAudioElement){const t=o(e,v)[v];return o(e,v)[v].addEventListener("canplay",o(e,R)[R].bind(e),{once:!0}),o(e,v)[v].addEventListener("playing",o(e,M)[M].bind(e)),o(e,v)[v].addEventListener("pause",o(e,N)[N].bind(e)),o(e,v)[v].addEventListener("ended",o(e,S)[S].bind(e)),o(e,v)[v].addEventListener("error",()=>{const n=t.error;o(e,w)[w](n?.message)}),o(e,m)[m]&&o(e,v)[v].addEventListener("timeupdate",n=>{const i=1e3*t.currentTime,r=o(e,H)[H](i);r&&!e.paused&&o(e,k)[k](n,{word:r.value,startChar:r.start,endChar:r.end})}),Promise.resolve(o(e,L)[L]()).then(function(){})}}();return Promise.resolve(t&&t.then?t.then(function(){}):void 0)}catch(e){return Promise.reject(e)}},h=function(){try{const e=this,t=o(e,f)[f],n=c(function(){return Promise.resolve(t.play()).then(function(){})},function(t){t instanceof Error&&o(e,w)[w](t.message)});return Promise.resolve(n&&n.then?n.then(function(){}):void 0)}catch(e){return Promise.reject(e)}},d=function(){try{const e=this,t=function(){if(o(e,f)[f]instanceof HTMLAudioElement){let t=null;const n=function(n,i){try{var r=c(function(){return Promise.resolve(o(e,y)[y](o(e,E)[E])).then(function(e){t=e})},function(t){t instanceof Error&&o(e,w)[w](t.message)})}catch(e){return i(!0,e)}return r&&r.then?r.then(i.bind(null,!1),i.bind(null,!0)):i(!1,r)}(0,function(n,i){if(t?.audio&&(o(e,f)[f].src=t.audio,o(e,g)[g]=t.marks??o(e,g)[g]),n)throw i;return i});if(n&&n.then)return n.then(function(){})}}();return Promise.resolve(t&&t.then?t.then(function(){}):void 0)}catch(e){return Promise.reject(e)}};var p;!function(e){e.BOUNDARY="boundary",e.END="end",e.ERROR="error",e.PAUSED="paused",e.PITCH="pitch",e.PLAYING="playing",e.RATE="rate",e.READY="ready",e.VOLUME="volume"}(p||(p={}));var v=/*#__PURE__*/s("target"),f=/*#__PURE__*/s("synthesizer"),m=/*#__PURE__*/s("dispatchBoundaries"),y=/*#__PURE__*/s("fetchAudioData"),g=/*#__PURE__*/s("marks"),E=/*#__PURE__*/s("text"),P=/*#__PURE__*/s("lang"),b=/*#__PURE__*/s("aborter"),A=/*#__PURE__*/s("initialized"),C=/*#__PURE__*/s("initWebSpeechVoice"),L=/*#__PURE__*/s("attachAudioSource"),S=/*#__PURE__*/s("dispatchEnd"),w=/*#__PURE__*/s("dispatchError"),R=/*#__PURE__*/s("dispatchReady"),M=/*#__PURE__*/s("dispatchPlaying"),N=/*#__PURE__*/s("dispatchPaused"),k=/*#__PURE__*/s("dispatchBoundary"),I=/*#__PURE__*/s("dispatchVolume"),T=/*#__PURE__*/s("dispatchRate"),O=/*#__PURE__*/s("dispatchPitch"),x=/*#__PURE__*/s("playHtmlAudio"),H=/*#__PURE__*/s("getPollySpeechMarkForAudioTime"),D=/*#__PURE__*/s("getBoundaryWordCharLength"),U=/*#__PURE__*/s("clamp"),_=/*#__PURE__*/s("recycle"),z=/*#__PURE__*/s("utteranceInit"),j=/*#__PURE__*/s("htmlAudioInit");class B extends EventTarget{constructor(e){super(),Object.defineProperty(this,j,{value:u}),Object.defineProperty(this,z,{value:ne}),Object.defineProperty(this,_,{value:te}),Object.defineProperty(this,U,{value:ee}),Object.defineProperty(this,D,{value:Q}),Object.defineProperty(this,H,{value:X}),Object.defineProperty(this,x,{value:h}),Object.defineProperty(this,O,{value:q}),Object.defineProperty(this,T,{value:J}),Object.defineProperty(this,I,{value:Z}),Object.defineProperty(this,k,{value:W}),Object.defineProperty(this,N,{value:K}),Object.defineProperty(this,M,{value:Y}),Object.defineProperty(this,R,{value:F}),Object.defineProperty(this,w,{value:V}),Object.defineProperty(this,S,{value:$}),Object.defineProperty(this,L,{value:d}),Object.defineProperty(this,C,{value:G}),Object.defineProperty(this,v,{writable:!0,value:void 0}),Object.defineProperty(this,f,{writable:!0,value:void 0}),Object.defineProperty(this,m,{writable:!0,value:!0}),Object.defineProperty(this,y,{writable:!0,value:function(){try{return Promise.resolve({audio:"",marks:[]})}catch(e){return Promise.reject(e)}}}),Object.defineProperty(this,g,{writable:!0,value:[]}),Object.defineProperty(this,E,{writable:!0,value:""}),Object.defineProperty(this,P,{writable:!0,value:""}),Object.defineProperty(this,b,{writable:!0,value:new AbortController}),Object.defineProperty(this,A,{writable:!0,value:!1}),o(this,P)[P]=e?.lang??o(this,P)[P],o(this,f)[f]=window.speechSynthesis,o(this,v)[v]=new SpeechSynthesisUtterance(o(this,E)[E]),o(this,m)[m]=e?.dispatchBoundaries??o(this,m)[m],e?.fetchAudioData?(o(this,v)[v]=o(this,f)[f]=new Audio,o(this,y)[y]=e.fetchAudioData):(o(this,C)[C](e?.voice),window.speechSynthesis&&(window.speechSynthesis.onvoiceschanged=()=>{o(this,C)[C](e?.voice)}))}get synthesizer(){return o(this,f)[f]}get target(){return o(this,v)[v]}set text(e){o(this,E)[E]=e,o(this,v)[v]instanceof SpeechSynthesisUtterance&&(o(this,v)[v].text=e)}get paused(){return o(this,f)[f].paused}get rate(){return o(this,f)[f]instanceof HTMLAudioElement?o(this,f)[f].playbackRate:o(this,v)[v].rate}set rate(e){const t=o(this,U)[U](parseFloat(e.toPrecision(3)),.1,10);Number.isNaN(t)||(o(this,T)[T](t),o(this,f)[f]instanceof HTMLAudioElement&&(o(this,f)[f].defaultPlaybackRate=t,o(this,f)[f].playbackRate=t),o(this,v)[v]instanceof SpeechSynthesisUtterance&&(o(this,v)[v].rate=t))}get pitch(){return o(this,v)[v]instanceof SpeechSynthesisUtterance?o(this,v)[v].pitch:-1}set pitch(e){if(o(this,v)[v]instanceof SpeechSynthesisUtterance){const t=o(this,U)[U](parseFloat(e.toPrecision(2)),0,2);Number.isNaN(t)||(o(this,O)[O](t),o(this,v)[v].pitch=t)}}get volumeMin(){return 0}get volumeMax(){return 1}get volume(){return o(this,v)[v].volume}set volume(e){const t=o(this,U)[U](parseFloat(e.toPrecision(2)),this.volumeMin,this.volumeMax);Number.isNaN(t)||(o(this,I)[I](t),o(this,v)[v].volume=t)}get preservesPitch(){return o(this,f)[f]instanceof HTMLAudioElement&&o(this,f)[f].preservesPitch}set preservesPitch(e){o(this,f)[f]instanceof HTMLAudioElement&&(o(this,f)[f].preservesPitch=e)}get lang(){return o(this,P)[P]}set lang(e){o(this,v)[v]instanceof SpeechSynthesisUtterance&&(o(this,P)[P]=e,o(this,v)[v].lang=e,o(this,v)[v].voice=null,o(this,C)[C]())}init(){try{const e=this,t=function(){if(!o(e,A)[A]){function t(){o(e,A)[A]=!0}o(e,v)[v]instanceof SpeechSynthesisUtterance&&o(e,z)[z]();const n=function(){if(o(e,v)[v]instanceof HTMLAudioElement)return Promise.resolve(o(e,j)[j]()).then(function(){})}();return n&&n.then?n.then(t):t()}}();return Promise.resolve(t&&t.then?t.then(function(){}):void 0)}catch(e){return Promise.reject(e)}}play(){try{const e=this,t=function(){if(o(e,f)[f]instanceof HTMLAudioElement)return Promise.resolve(o(e,x)[x]()).then(function(){});o(e,f)[f].speak(o(e,v)[v])}();return Promise.resolve(t&&t.then?t.then(function(){}):void 0)}catch(e){return Promise.reject(e)}}pause(){o(this,f)[f].pause()}resume(){try{const e=this,t=function(){if(o(e,f)[f]instanceof HTMLAudioElement)return Promise.resolve(o(e,x)[x]()).then(function(){});o(e,f)[f].resume()}();return Promise.resolve(t&&t.then?t.then(function(){}):void 0)}catch(e){return Promise.reject(e)}}replay(){try{const e=this,t=function(){if(o(e,f)[f]instanceof HTMLAudioElement)return o(e,f)[f].load(),Promise.resolve(o(e,x)[x]()).then(function(){});o(e,f)[f].resume(),o(e,f)[f].cancel(),o(e,f)[f].speak(o(e,v)[v])}();return Promise.resolve(t&&t.then?t.then(function(){}):void 0)}catch(e){return Promise.reject(e)}}cancel(){o(this,f)[f]instanceof HTMLAudioElement?o(this,f)[f].load():o(this,f)[f].cancel()}mute(){this.volume=0,o(this,f)[f]instanceof HTMLAudioElement||this.paused||!o(this,f)[f].speaking||this.replay()}unmute(e){this.volume=e??1,o(this,f)[f]instanceof HTMLAudioElement||this.paused||!o(this,f)[f].speaking||this.replay()}}function G(e){if(o(this,v)[v]instanceof SpeechSynthesisUtterance){let t=window.speechSynthesis.getVoices();e&&(o(this,v)[v].voice=e),o(this,P)[P]&&(t=t.filter(e=>e.lang===o(this,P)[P]),o(this,v)[v].voice=t[0]??null,e&&e.lang===o(this,P)[P]&&(o(this,v)[v].voice=e))}}function $(e){this.dispatchEvent(new CustomEvent(p.END,{detail:e}))}function V(e){this.dispatchEvent(new CustomEvent(p.ERROR,{detail:e}))}function F(){this.dispatchEvent(new Event(p.READY))}function Y(e){this.dispatchEvent(new CustomEvent(p.PLAYING,{detail:e}))}function K(e){this.dispatchEvent(new CustomEvent(p.PAUSED,{detail:e}))}function W(e,t){this.dispatchEvent(new CustomEvent(p.BOUNDARY,{detail:{evt:e,boundary:t}}))}function Z(e){this.dispatchEvent(new CustomEvent(p.VOLUME,{detail:e}))}function J(e){this.dispatchEvent(new CustomEvent(p.RATE,{detail:e}))}function q(e){this.dispatchEvent(new CustomEvent(p.PITCH,{detail:e}))}function X(e){const t=o(this,g)[g].length;let n=o(this,g)[g][0],i=!1,r=1;for(;r<t&&!i;)o(this,g)[g][r].time<=e?n=o(this,g)[g][r]:i=!0,r++;return n}function Q(e){const t=o(this,E)[E].substring(e).match(/.+?\b/);return t?t[0].length:0}function ee(e,t,n){return void 0===t&&(t=0),void 0===n&&(n=1),Math.max(t,Math.min(e,n))}function te(){return o(this,b)[b].abort(),o(this,b)[b]=new AbortController,o(this,b)[b].signal}function ne(){if(o(this,v)[v]instanceof SpeechSynthesisUtterance){const e=o(this,_)[_]();o(this,v)[v].addEventListener("end",o(this,S)[S].bind(this),{signal:e}),o(this,v)[v].addEventListener("start",o(this,M)[M].bind(this),{signal:e}),o(this,v)[v].addEventListener("resume",o(this,M)[M].bind(this),{signal:e}),o(this,v)[v].addEventListener("pause",o(this,N)[N].bind(this),{signal:e}),o(this,v)[v].addEventListener("error",e=>{o(this,w)[w](e.error)},{signal:e}),o(this,P)[P]&&(o(this,v)[v].lang=o(this,P)[P]),o(this,m)[m]&&o(this,v)[v].addEventListener("boundary",e=>{const{charIndex:t}=e,n=t+(e.charLength??o(this,D)[D](t)),i=o(this,E)[E].substring(t,n);i&&!(e=>{const t=e.trim();return a.test(t)&&1===t.length})(i)&&o(this,k)[k](e,{word:i,startChar:t,endChar:n})},{signal:e}),o(this,R)[R]()}}const ie=e=>{let{text:n,mark:r,color:s,backgroundColor:o}=e;const a=t.useMemo(()=>(e=>{let{color:t,backgroundColor:n}=e;return{color:t,backgroundColor:n}})({color:s,backgroundColor:o}),[s,o]);if(n&&r){const e=n.toString(),t=r.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),s=new RegExp(`(${t})`,"gi"),o=e.split(s);if(o.length>1)return i.default.createElement("span",null,o.map((e,t)=>{const n=`${e}-${t}`;return e?s.test(e)?i.default.createElement("mark",{key:n,style:a,"data-testid":"tts-react-mark"},e):i.default.createElement("span",{key:n},e):null}))}return i.default.createElement(i.default.Fragment,null,n)},re=e=>{let{children:n,buffer:r,boundary:s,markColor:o,markBackgroundColor:a,markTextAsSpoken:c}=e;return t.Children.map(n,e=>{let n=e;if(t.isValidElement(e)&&(n=t.cloneElement(e,{...e.props,children:re({buffer:r,boundary:s,markColor:o,markBackgroundColor:a,markTextAsSpoken:c,children:e.props.children})})),"string"==typeof(u=e)||"number"==typeof u){const t=e.toString(),{word:n,startChar:u,endChar:h}=s,d=r.text.length;if(r.text+=`${t} `,c&&n){const e=u-d,n=h-d,r=t.substring(0,e),s=t.substring(e,n),c=t.substring(n,t.length);if(s)return i.default.createElement(i.default.Fragment,null,r,i.default.createElement(ie,{text:s,mark:l(s),color:o,backgroundColor:a}),c)}}var u;return n})},se={word:"",startChar:0,endChar:0},oe=(e,t)=>{switch(t.type){case"pause":return{...e,isPlaying:!1,isPaused:!0,isError:!1};case"play":case"reset":return{...e,isPlaying:!0,isPaused:!1,isError:!1,boundary:se};case"end":return{...e,isPlaying:!1,isPaused:!1,isError:!1,boundary:se};case"error":return{...e,isPlaying:!1,isPaused:!1,isError:!0,boundary:se};case"ready":return{...e,isReady:!0};case"boundary":return{...e,boundary:{...e.boundary,...t.payload}};case"voices":return{...e,voices:t.payload};case"stop":return{...e,isPlaying:!1,isPaused:!1,isError:!1};case"muted":return{...e,isMuted:!0};case"unmuted":return{...e,isMuted:!1}}},ae=e=>{let{lang:n,rate:i,volume:r,voice:s,children:o,markColor:a,markBackgroundColor:l,onStart:c,onPause:u,onBoundary:h,onEnd:d,onError:v,onVolumeChange:f,onPitchChange:m,onRateChange:y,fetchAudioData:g,autoPlay:E=!1,markTextAsSpoken:P=!1}=e;const b=t.useRef(),[A,C]=t.useReducer(oe,{voices:window.speechSynthesis?.getVoices()??[],boundary:se,isPlaying:!1,isPaused:!1,isMuted:!1,isError:!1,isReady:void 0===g}),[L,S]=t.useMemo(()=>{if(void 0===b.current||P){const e={text:""},t=re({children:o,buffer:e,markColor:a,markBackgroundColor:l,markTextAsSpoken:P,boundary:A.boundary});return b.current=e.text.trim(),[t,b.current]}return[o,b.current]},[o,A.boundary,a,l,P]),w=t.useMemo(()=>new B({lang:n,voice:s,fetchAudioData:g}),[n,s,g]),R=t.useCallback(function(){try{return A.isPaused?w.resume():w.replay(),C({type:"play"}),Promise.resolve()}catch(e){return Promise.reject(e)}},[w,A.isPaused]),M=t.useCallback(()=>{w.pause(),C({type:"pause"})},[w]),N=t.useCallback(()=>{w.replay(),C({type:"reset"})},[w]),k=t.useCallback(()=>{w.cancel(),C({type:"stop"})},[w]),I=t.useCallback(e=>{const t=parseFloat(w.volume.toFixed(2))===w.volumeMin;t?(w.unmute(),C({type:"unmuted"})):(w.mute(),C({type:"muted"})),"function"==typeof e&&e(t)},[w]),T=t.useMemo(()=>A.isPlaying?M:R,[A.isPlaying,M,R]),O=t.useMemo(()=>A.isPlaying?k:R,[A.isPlaying,k,R]),[x,H]=t.useMemo(()=>[{lang:()=>w.lang,rate:()=>w.rate,pitch:()=>w.pitch,volume:()=>w.volume,preservesPitch:()=>w.preservesPitch},{lang(e){w.lang=e},rate(e){w.rate=e},pitch(e){w.pitch=e},volume(e){w.volume=e},preservesPitch(e){w.preservesPitch=e}}],[w]),D=t.useCallback(e=>{C({type:"play"}),"function"==typeof c&&c(e.detail)},[c]),U=t.useCallback(e=>{"function"==typeof u&&u(e.detail)},[u]),_=t.useCallback(e=>{C({type:"end"}),"function"==typeof d&&d(e.detail)},[d]),z=t.useCallback(()=>{C({type:"ready"})},[]),j=t.useCallback(e=>{C({type:"error"}),"function"==typeof v&&v(e.detail)},[v]),G=t.useCallback(e=>{C({type:"boundary",payload:e.detail.boundary}),"function"==typeof h&&h(e.detail.boundary,e.detail.evt)},[h]),$=t.useCallback(e=>{const t=e.detail,n=w.volumeMin;t===n&&w.volume!==n&&C({type:"muted"}),t!==n&&w.volume===n&&C({type:"unmuted"}),"function"==typeof f&&f(t)},[f,w]),V=t.useCallback(e=>{"function"==typeof m&&m(e.detail)},[m]),F=t.useCallback(e=>{"function"==typeof y&&y(e.detail)},[y]);return t.useEffect(()=>{w.text=S},[S,w]),t.useEffect(()=>{i&&Number.isFinite(i)&&(w.rate=i),r&&Number.isFinite(r)&&(w.volume=r)},[w,i,r]),t.useEffect(()=>{const e=()=>{w.cancel()};return function(){try{return w.addEventListener(p.PLAYING,D),w.addEventListener(p.PAUSED,U),w.addEventListener(p.END,_),w.addEventListener(p.ERROR,j),w.addEventListener(p.READY,z),w.addEventListener(p.BOUNDARY,G),w.addEventListener(p.VOLUME,$),w.addEventListener(p.PITCH,V),w.addEventListener(p.RATE,F),window.addEventListener("beforeunload",e),Promise.resolve(w.init()).then(function(){})}catch(e){return Promise.reject(e)}}(),()=>{window.removeEventListener("beforeunload",e),w.removeEventListener(p.PLAYING,D),w.removeEventListener(p.PAUSED,U),w.removeEventListener(p.END,_),w.removeEventListener(p.ERROR,j),w.removeEventListener(p.READY,z),w.removeEventListener(p.BOUNDARY,G),w.removeEventListener(p.VOLUME,$),w.removeEventListener(p.PITCH,V),w.removeEventListener(p.RATE,F)}},[D,G,U,_,z,j,h,$,V,F,w]),t.useEffect(()=>{E&&A.isReady&&(w.replay(),C({type:"play"}))},[E,w,A.isReady,S]),t.useEffect(()=>{const e=()=>{C({type:"voices",payload:window.speechSynthesis.getVoices()})};return"function"==typeof window.speechSynthesis?.addEventListener&&window.speechSynthesis.addEventListener("voiceschanged",e),()=>{"function"==typeof window.speechSynthesis?.removeEventListener&&window.speechSynthesis.removeEventListener("voiceschanged",e)}},[]),{get:x,set:H,state:A,spokenText:S,ttsChildren:L,play:R,stop:k,pause:M,replay:N,playOrStop:O,playOrPause:T,toggleMute:I}};var le;e.Sizes=void 0,(le=e.Sizes||(e.Sizes={})).SMALL="small",le.MEDIUM="medium",le.LARGE="large";const ce={small:16,medium:24,large:32},ue={play:e=>`\n <svg\n xmlns="http://www.w3.org/2000/svg"\n height="${ce[e]}px"\n viewBox="0 0 24 24"\n width="${ce[e]}px"\n fill="#000000">\n <style>\n svg {\n cursor: pointer;\n }\n </style>\n <path d="M0 0h24v24H0z" fill="none" />\n <path d="M8 5v14l11-7z" />\n </svg>\n `,pause:e=>`\n <svg\n xmlns="http://www.w3.org/2000/svg"\n height="${ce[e]}px"\n viewBox="0 0 24 24"\n width="${ce[e]}px"\n fill="#000000">\n <style>\n svg {\n cursor: pointer;\n }\n </style>\n <path d="M0 0h24v24H0z" fill="none" />\n <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />\n </svg>\n `,stop:e=>`\n <svg\n xmlns="http://www.w3.org/2000/svg"\n height="${ce[e]}px"\n viewBox="0 0 24 24"\n width="${ce[e]}px"\n fill="#000000">\n <style>\n svg {\n cursor: pointer;\n }\n </style>\n <path d="M0 0h24v24H0z" fill="none" />\n <path d="M6 6h12v12H6z" />\n </svg>\n `,replay:e=>`\n <svg\n xmlns="http://www.w3.org/2000/svg"\n height="${ce[e]}px"\n viewBox="0 0 24 24"\n width="${ce[e]}px"\n fill="#000000">\n <style>\n svg {\n cursor: pointer;\n }\n </style>\n <path d="M0 0h24v24H0z" fill="none" />\n <path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" />\n </svg>\n `,volumeDown:e=>`\n <svg\n xmlns="http://www.w3.org/2000/svg"\n height="${ce[e]}px"\n viewBox="0 0 24 24"\n width="${ce[e]}px"\n fill="#000000">\n <style>\n svg {\n cursor: pointer;\n }\n </style>\n <path d="M0 0h24v24H0z" fill="none" />\n <path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z" />\n </svg>\n `,volumeOff:e=>`\n <svg\n xmlns="http://www.w3.org/2000/svg"\n height="${ce[e]}px"\n viewBox="0 0 24 24"\n width="${ce[e]}px"\n fill="#000000">\n <style>\n svg {\n cursor: pointer;\n }\n </style>\n <path d="M0 0h24v24H0z" fill="none" />\n <path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z" />\n </svg>\n `,volumeUp:e=>`\n <svg\n xmlns="http://www.w3.org/2000/svg"\n height="${ce[e]}px"\n viewBox="0 0 24 24"\n width="${ce[e]}px"\n fill="#000000">\n <style>\n svg {\n cursor: pointer;\n }\n </style>\n <path d="M0 0h24v24H0z" fill="none" />\n <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" />\n </svg>\n `},he={[e.Sizes.SMALL]:5,[e.Sizes.MEDIUM]:5,[e.Sizes.LARGE]:5},de=n=>{let{title:r,type:s,onClick:o,size:a=e.Sizes.MEDIUM,align:l="horizontal",...c}=n;const u="tts-react-controls",h=t.useMemo(()=>ue[s](a),[s,a]),d=t.useMemo(()=>(e=>{let{size:t,align:n,type:i}=e;const r={margin:0,padding:`${he[t]}px`,border:"none",borderRadius:`${ce[t]}px`,color:"black",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"transparent"};if("replay"===i){const e=`-${ce[t]+2*he[t]+5}px`,i="horizontal"===n?"right":"bottom";return{...r,[i]:e,position:"absolute",background:"#f2f1f1a6",zIndex:9999}}return r})({size:a,align:l,type:s}),[a,l,s]);return t.useEffect(()=>{let e=document.querySelector(`style[data-id="${u}"]`);return e||(e=document.createElement("style"),e.setAttribute("data-id",u),e.innerHTML='\n button[data-tts-react-control]:hover {\n background-color: #ebeaeaa6 !important;\n }\n button[data-id="tts-react-replay"]:hover {\n filter: brightness(0.98);\n }\n ',document.head.appendChild(e)),()=>{e=null}},[l,a,s]),i.default.createElement("button",{title:r,"data-tts-react-control":!0,"data-id":`tts-react-${s}`,onClick:o,style:d,dangerouslySetInnerHTML:{__html:h},...c})};var pe,ve;e.Positions=void 0,(pe=e.Positions||(e.Positions={})).TL="topLeft",pe.TR="topRight",pe.BL="bottomLeft",pe.BR="bottomRight",pe.TC="topCenter",pe.RC="rightCenter",pe.BC="bottomCenter",pe.LC="leftCenter",e.LanguageTags=void 0,(ve=e.LanguageTags||(e.LanguageTags={})).ARABIC_SAUDI_ARABIA="ar-SA",ve.CZECH_CZECH_REPUBLIC="cs-CZ",ve.DANISH_DENMARK="da-DK",ve.GERMAN_GERMANY="de-DE",ve.MODERN_GREEK_GREECE="el-GR",ve.ENGLISH_AUSTRALIA="en-AU",ve.ENGLISH_UNITED_KINGDOM="en-GB",ve.ENGLISH_IRELAND="en-IE",ve.ENGLISH_UNITED_STATES="en-US",ve.ENGLISH_SOUTH_AFRICA="en-ZA",ve.SPANISH_SPAIN="es-ES",ve.SPANISH_MEXICO="es-MX",ve.FINNISH_FINLAND="fi-FI",ve.FRENCH_CANADA="fr-CA",ve.FRENCH_FRANCE="fr-FR",ve.HEBREW_ISRAEIL="he-IL",ve.HINDI_INDIA="hi-IN",ve.HUNGARIAN_HUNGARY="hu-HU",ve.INDONESIAN_INDONESIA="id-ID",ve.ITALIAN_ITALY="it-IT",ve.JAPANESE_JAPAN="ja-JP",ve.KOREAN_REPUBLIC_OF_KOREA="ko-KR",ve.DUTCH_BELGIUM="nl-BE",ve.DUTCH_NETHERLANDS="nl-NL",ve.NORWEGIAN_NORWAY="no-NO",ve.POLISH_POLAND="pl-PL",ve.PORTUGUESE_BRAZIL="pt-BR",ve.PORTUGUESE_PORTUGAL="pt-PT",ve.ROMANIAN_ROMANIA="ro-RO",ve.RUSSIAN_RUSSIAN_FEDERATION="ru-RU",ve.SLOVAK_SLOVAKIA="sk-SK",ve.SWEDISH_SWEDEN="sv-SE",ve.THAI_THAILAND="th-TH",ve.TURKISH_TURKEY="tr-TR",ve.CHINESE_CHINA="zh-CN",ve.CHINESE_HONG_KONG="zh-HK",ve.CHINESE_TAIWAN="zh-TW",e.TextToSpeech=n=>{let{size:r,lang:s,rate:o,voice:a,volume:l,children:c,position:u,onStart:h,onPause:d,onBoundary:p,onEnd:v,onError:f,onMuteToggled:m,onVolumeChange:y,onPitchChange:g,onRateChange:E,fetchAudioData:P,markColor:b,markBackgroundColor:A,autoPlay:C=!1,allowMuting:L=!0,align:S="horizontal",markTextAsSpoken:w=!1,useStopOverPause:R=!1}=n;const{state:M,replay:N,toggleMute:k,playOrPause:I,playOrStop:T,ttsChildren:O}=ae({lang:s,rate:o,voice:a,volume:l,children:c,onStart:h,onPause:d,onBoundary:p,onEnd:v,onError:f,onVolumeChange:y,onPitchChange:g,onRateChange:E,fetchAudioData:P,autoPlay:C,markColor:b,markBackgroundColor:A,markTextAsSpoken:w}),x=t.useMemo(()=>(t=>{let{position:n=e.Positions.LC}=t,i="'cnt ctl'",r="1fr auto",s="start";switch(n){case e.Positions.TL:i="'ctl cnt'",r="auto 1fr";break;case e.Positions.BL:i="'ctl cnt'",s="end",r="auto 1fr";break;case e.Positions.BR:i="'cnt ctl'",s="end";break;case e.Positions.TC:r="1fr",i="'ctl'\n'cnt'",s="center";break;case e.Positions.RC:s="center";break;case e.Positions.BC:r="1fr",i="'cnt'\n'ctl'",s="center";break;case e.Positions.LC:i="'ctl cnt'",r="auto 1fr",s="center"}return{alignItems:s,gridTemplateAreas:i,gridTemplateColumns:r,display:"grid",gap:"15px"}})({position:u}),[u]),H=t.useMemo(()=>(t=>{let{align:n,position:i=e.Positions.LC,size:r=e.Sizes.MEDIUM}=t;return{position:"relative",display:"inline-flex",flexDirection:"horizontal"===n?"row":"column",gap:"5px",gridArea:"ctl",padding:0,margin:i.includes("Center")?"auto":0,backgroundColor:"#f2f1f1a6",borderRadius:`${ce[r]+he[r]}px`,border:"1px solid transparent"}})({align:S,position:u,size:r}),[S,u,r]),D=t.useMemo(()=>({gridArea:"cnt"}),[]),[U,_,z]=t.useMemo(()=>M.isPlaying?R?["stop","Stop",T]:["pause","Pause",I]:["play","Play",I],[M.isPlaying,R,T,I]),j=t.useCallback(()=>{k(m)},[k,m]);return i.default.createElement("div",{style:x,className:"tts-react","data-testid":"tts-react"},M.isReady&&i.default.createElement("aside",{style:H,"data-testid":"tts-react-controls"},L&&i.default.createElement(de,{size:r,align:S,title:M.isMuted?"Unmute":"Mute","aria-label":M.isMuted?"Unmute":"Mute",onClick:j,type:M.isMuted?"volumeOff":M.isPlaying?"volumeUp":"volumeDown"}),i.default.createElement(de,{type:U,title:_,"aria-label":_,onClick:z,size:r,align:S}),M.isPaused&&i.default.createElement(de,{type:"replay",size:r,align:S,title:"Replay","aria-label":"Replay",onClick:N})),i.default.createElement("div",{style:D},O))},e.useTts=ae});
(function(f,i){typeof exports=="object"&&typeof module<"u"?i(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],i):(f=typeof globalThis<"u"?globalThis:f||self,i(f.TTSReact={},f.React))})(this,function(f,i){"use strict";var Re=(f,i,S)=>{if(!i.has(f))throw TypeError("Cannot "+S)};var s=(f,i,S)=>(Re(f,i,"read from private field"),S?S.call(f):i.get(f)),p=(f,i,S)=>{if(i.has(f))throw TypeError("Cannot add the same private member more than once");i instanceof WeakSet?i.add(f):i.set(f,S)},C=(f,i,S,ce)=>(Re(f,i,"write to private field"),ce?ce.call(f,S):i.set(f,S),S);var h=(f,i,S)=>(Re(f,i,"access private method"),S);var l,c,R,X,P,_,I,z,Q,K,Se,de,We,ee,Te,T,ae,te,Ge,Y,Me,se,$e,ie,Be,ue,Ze,pe,je,fe,Je,W,Ne,ye,qe,me,Xe,Z,Ce,Ee,Qe,ve,et,Ae,tt;const S=/[^\P{P}'/-]+/gu,ce=e=>typeof e=="string"||typeof e=="number",st=e=>e.replace(S,""),it=e=>{const o=e.trim();return S.test(o)&&o.length===1};var E=(e=>(e.BOUNDARY="boundary",e.END="end",e.ERROR="error",e.PAUSED="paused",e.PITCH="pitch",e.PLAYING="playing",e.RATE="rate",e.READY="ready",e.VOLUME="volume",e))(E||{});class nt extends EventTarget{constructor(t){super();p(this,K);p(this,de);p(this,ee);p(this,T);p(this,te);p(this,Y);p(this,se);p(this,ie);p(this,ue);p(this,pe);p(this,fe);p(this,W);p(this,ye);p(this,me);p(this,Z);p(this,Ee);p(this,ve);p(this,Ae);p(this,l,void 0);p(this,c,void 0);p(this,R,!0);p(this,X,async()=>({audio:"",marks:[]}));p(this,P,[]);p(this,_,"");p(this,I,"");p(this,z,new AbortController);p(this,Q,!1);C(this,I,(t==null?void 0:t.lang)??s(this,I)),C(this,c,window.speechSynthesis),C(this,l,new SpeechSynthesisUtterance(s(this,_))),C(this,R,(t==null?void 0:t.dispatchBoundaries)??s(this,R)),t!=null&&t.fetchAudioData?(C(this,l,C(this,c,new Audio)),C(this,X,t.fetchAudioData)):(h(this,K,Se).call(this,t==null?void 0:t.voice),window.speechSynthesis&&(window.speechSynthesis.onvoiceschanged=()=>{h(this,K,Se).call(this,t==null?void 0:t.voice)}))}get synthesizer(){return s(this,c)}get target(){return s(this,l)}set text(t){C(this,_,t),s(this,l)instanceof SpeechSynthesisUtterance&&(s(this,l).text=t)}get paused(){return s(this,c).paused}get rate(){return s(this,c)instanceof HTMLAudioElement?s(this,c).playbackRate:s(this,l).rate}set rate(t){const n=h(this,Z,Ce).call(this,parseFloat(t.toPrecision(3)),.1,10);Number.isNaN(n)||(h(this,pe,je).call(this,n),s(this,c)instanceof HTMLAudioElement&&(s(this,c).defaultPlaybackRate=n,s(this,c).playbackRate=n),s(this,l)instanceof SpeechSynthesisUtterance&&(s(this,l).rate=n))}get pitch(){return s(this,l)instanceof SpeechSynthesisUtterance?s(this,l).pitch:-1}set pitch(t){if(s(this,l)instanceof SpeechSynthesisUtterance){const n=h(this,Z,Ce).call(this,parseFloat(t.toPrecision(2)),0,2);Number.isNaN(n)||(h(this,fe,Je).call(this,n),s(this,l).pitch=n)}}get volumeMin(){return 0}get volumeMax(){return 1}get volume(){return s(this,l).volume}set volume(t){const n=h(this,Z,Ce).call(this,parseFloat(t.toPrecision(2)),this.volumeMin,this.volumeMax);Number.isNaN(n)||(h(this,ue,Ze).call(this,n),s(this,l).volume=n)}get preservesPitch(){return s(this,c)instanceof HTMLAudioElement?s(this,c).preservesPitch:!1}set preservesPitch(t){s(this,c)instanceof HTMLAudioElement&&(s(this,c).preservesPitch=t)}get lang(){return s(this,I)}set lang(t){s(this,l)instanceof SpeechSynthesisUtterance&&(C(this,I,t),s(this,l).lang=t,s(this,l).voice=null,h(this,K,Se).call(this))}async init(){s(this,Q)||(s(this,l)instanceof SpeechSynthesisUtterance&&h(this,ve,et).call(this),s(this,l)instanceof HTMLAudioElement&&await h(this,Ae,tt).call(this),C(this,Q,!0))}async play(){s(this,c)instanceof HTMLAudioElement?await h(this,W,Ne).call(this):s(this,c).speak(s(this,l))}pause(){s(this,c).pause()}async resume(){s(this,c)instanceof HTMLAudioElement?await h(this,W,Ne).call(this):s(this,c).resume()}async replay(){s(this,c)instanceof HTMLAudioElement?(s(this,c).load(),await h(this,W,Ne).call(this)):(s(this,c).resume(),s(this,c).cancel(),s(this,c).speak(s(this,l)))}cancel(){s(this,c)instanceof HTMLAudioElement?s(this,c).load():s(this,c).cancel()}mute(){this.volume=0,!(s(this,c)instanceof HTMLAudioElement)&&!this.paused&&s(this,c).speaking&&this.replay()}unmute(t){this.volume=t??1,!(s(this,c)instanceof HTMLAudioElement)&&!this.paused&&s(this,c).speaking&&this.replay()}}l=new WeakMap,c=new WeakMap,R=new WeakMap,X=new WeakMap,P=new WeakMap,_=new WeakMap,I=new WeakMap,z=new WeakMap,Q=new WeakMap,K=new WeakSet,Se=function(t){if(s(this,l)instanceof SpeechSynthesisUtterance){let n=window.speechSynthesis.getVoices();t&&(s(this,l).voice=t),s(this,I)&&(n=n.filter(d=>d.lang===s(this,I)),s(this,l).voice=n[0]??null,t&&t.lang===s(this,I)&&(s(this,l).voice=t))}},de=new WeakSet,We=async function(){if(s(this,c)instanceof HTMLAudioElement){let t=null;try{t=await s(this,X).call(this,s(this,_))}catch(n){n instanceof Error&&h(this,T,ae).call(this,n.message)}finally{t!=null&&t.audio&&(s(this,c).src=t.audio,C(this,P,t.marks??s(this,P)))}}},ee=new WeakSet,Te=function(t){this.dispatchEvent(new CustomEvent("end",{detail:t}))},T=new WeakSet,ae=function(t){this.dispatchEvent(new CustomEvent("error",{detail:t}))},te=new WeakSet,Ge=function(){this.dispatchEvent(new Event("ready"))},Y=new WeakSet,Me=function(t){this.dispatchEvent(new CustomEvent("playing",{detail:t}))},se=new WeakSet,$e=function(t){this.dispatchEvent(new CustomEvent("paused",{detail:t}))},ie=new WeakSet,Be=function(t,n){this.dispatchEvent(new CustomEvent("boundary",{detail:{evt:t,boundary:n}}))},ue=new WeakSet,Ze=function(t){this.dispatchEvent(new CustomEvent("volume",{detail:t}))},pe=new WeakSet,je=function(t){this.dispatchEvent(new CustomEvent("rate",{detail:t}))},fe=new WeakSet,Je=function(t){this.dispatchEvent(new CustomEvent("pitch",{detail:t}))},W=new WeakSet,Ne=async function(){const t=s(this,c);try{await t.play()}catch(n){n instanceof Error&&h(this,T,ae).call(this,n.message)}},ye=new WeakSet,qe=function(t){const n=s(this,P).length;let d=s(this,P)[0],y=!1,u=1;for(;u<n&&!y;)s(this,P)[u].time<=t?d=s(this,P)[u]:y=!0,u++;return d},me=new WeakSet,Xe=function(t){const n=s(this,_).substring(t).match(/.+?\b/);return n?n[0].length:0},Z=new WeakSet,Ce=function(t,n=0,d=1){return Math.max(n,Math.min(t,d))},Ee=new WeakSet,Qe=function(){return s(this,z).abort(),C(this,z,new AbortController),s(this,z).signal},ve=new WeakSet,et=function(){if(s(this,l)instanceof SpeechSynthesisUtterance){const t=h(this,Ee,Qe).call(this);s(this,l).addEventListener("end",h(this,ee,Te).bind(this),{signal:t}),s(this,l).addEventListener("start",h(this,Y,Me).bind(this),{signal:t}),s(this,l).addEventListener("resume",h(this,Y,Me).bind(this),{signal:t}),s(this,l).addEventListener("pause",h(this,se,$e).bind(this),{signal:t}),s(this,l).addEventListener("error",n=>{h(this,T,ae).call(this,n.error)},{signal:t}),s(this,I)&&(s(this,l).lang=s(this,I)),s(this,R)&&s(this,l).addEventListener("boundary",n=>{const{charIndex:d}=n,y=n.charLength??h(this,me,Xe).call(this,d),u=d+y,A=s(this,_).substring(d,u);A&&!it(A)&&h(this,ie,Be).call(this,n,{word:A,startChar:d,endChar:u})},{signal:t}),h(this,te,Ge).call(this)}},Ae=new WeakSet,tt=async function(){if(s(this,l)instanceof HTMLAudioElement){const t=s(this,l);s(this,l).addEventListener("canplay",h(this,te,Ge).bind(this),{once:!0}),s(this,l).addEventListener("playing",h(this,Y,Me).bind(this)),s(this,l).addEventListener("pause",h(this,se,$e).bind(this)),s(this,l).addEventListener("ended",h(this,ee,Te).bind(this)),s(this,l).addEventListener("error",()=>{const n=t.error;h(this,T,ae).call(this,n==null?void 0:n.message)}),s(this,R)&&s(this,l).addEventListener("timeupdate",n=>{const d=t.currentTime*1e3,y=h(this,ye,qe).call(this,d);y&&!this.paused&&h(this,ie,Be).call(this,n,{word:y.value,startChar:y.start,endChar:y.end})}),await h(this,de,We).call(this)}};const rt=({color:e,backgroundColor:o})=>({color:e,backgroundColor:o}),lt=({text:e,mark:o,color:t,backgroundColor:n})=>{const d=i.useMemo(()=>rt({color:t,backgroundColor:n}),[t,n]);if(e&&o){const y=e.toString(),u=o.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),A=new RegExp(`(${u})`,"gi"),b=y.split(A);if(b.length>1)return i.createElement("span",null,b.map((m,x)=>{const L=`${m}-${x}`;return m?A.test(m)?i.createElement("mark",{key:L,style:d,"data-testid":"tts-react-mark"},m):i.createElement("span",{key:L},m):null}))}return i.createElement(i.Fragment,null,e)},Fe=({children:e,buffer:o,boundary:t,markColor:n,markBackgroundColor:d,markTextAsSpoken:y})=>i.Children.map(e,u=>{let A=u;if(i.isValidElement(u)&&(A=i.cloneElement(u,{...u.props,children:Fe({buffer:o,boundary:t,markColor:n,markBackgroundColor:d,markTextAsSpoken:y,children:u.props.children})})),ce(u)){const b=u.toString(),{word:m,startChar:x,endChar:L}=t,U=o.text.length;if(o.text+=`${b} `,y&&m){const g=x-U,D=L-U,G=b.substring(0,g),O=b.substring(g,D),$=b.substring(D,b.length);if(O)return i.createElement(i.Fragment,null,G,i.createElement(lt,{text:O,mark:st(O),color:n,backgroundColor:d}),$)}}return A}),he={word:"",startChar:0,endChar:0},ot=(e,o)=>{switch(o.type){case"pause":return{...e,isPlaying:!1,isPaused:!0,isError:!1};case"play":case"reset":return{...e,isPlaying:!0,isPaused:!1,isError:!1,boundary:he};case"end":return{...e,isPlaying:!1,isPaused:!1,isError:!1,boundary:he};case"error":return{...e,isPlaying:!1,isPaused:!1,isError:!0,boundary:he};case"ready":return{...e,isReady:!0};case"boundary":return{...e,boundary:{...e.boundary,...o.payload}};case"voices":return{...e,voices:o.payload};case"stop":return{...e,isPlaying:!1,isPaused:!1,isError:!1};case"muted":return{...e,isMuted:!0};case"unmuted":return{...e,isMuted:!1}}},Ve=({lang:e,rate:o,volume:t,voice:n,children:d,markColor:y,markBackgroundColor:u,onStart:A,onPause:b,onBoundary:m,onEnd:x,onError:L,onVolumeChange:U,onPitchChange:g,onRateChange:D,fetchAudioData:G,autoPlay:O=!1,markTextAsSpoken:$=!1})=>{var Ye;const j=i.useRef(),[N,w]=i.useReducer(ot,{voices:((Ye=window.speechSynthesis)==null?void 0:Ye.getVoices())??[],boundary:he,isPlaying:!1,isPaused:!1,isMuted:!1,isError:!1,isReady:typeof G>"u"}),[B,J]=i.useMemo(()=>{if(typeof j.current>"u"||$){const a={text:""},H=Fe({children:d,buffer:a,markColor:y,markBackgroundColor:u,markTextAsSpoken:$,boundary:N.boundary});return j.current=a.text.trim(),[H,j.current]}return[d,j.current]},[d,N.boundary,y,u,$]),r=i.useMemo(()=>new nt({lang:e,voice:n,fetchAudioData:G}),[e,n,G]),M=i.useCallback(async()=>{N.isPaused?r.resume():r.replay(),w({type:"play"})},[r,N.isPaused]),ne=i.useCallback(()=>{r.pause(),w({type:"pause"})},[r]),we=i.useCallback(()=>{r.replay(),w({type:"reset"})},[r]),F=i.useCallback(()=>{r.cancel(),w({type:"stop"})},[r]),be=i.useCallback(a=>{const H=parseFloat(r.volume.toFixed(2))===r.volumeMin;H?(r.unmute(),w({type:"unmuted"})):(r.mute(),w({type:"muted"})),typeof a=="function"&&a(H)},[r]),Le=i.useMemo(()=>N.isPlaying?ne:M,[N.isPlaying,ne,M]),Pe=i.useMemo(()=>N.isPlaying?F:M,[N.isPlaying,F,M]),[xe,Ue]=i.useMemo(()=>[{lang(){return r.lang},rate(){return r.rate},pitch(){return r.pitch},volume(){return r.volume},preservesPitch(){return r.preservesPitch}},{lang(a){r.lang=a},rate(a){r.rate=a},pitch(a){r.pitch=a},volume(a){r.volume=a},preservesPitch(a){r.preservesPitch=a}}],[r]),re=i.useCallback(a=>{w({type:"play"}),typeof A=="function"&&A(a.detail)},[A]),q=i.useCallback(a=>{typeof b=="function"&&b(a.detail)},[b]),le=i.useCallback(a=>{w({type:"end"}),typeof x=="function"&&x(a.detail)},[x]),oe=i.useCallback(()=>{w({type:"ready"})},[]),_e=i.useCallback(a=>{w({type:"error"}),typeof L=="function"&&L(a.detail)},[L]),ge=i.useCallback(a=>{w({type:"boundary",payload:a.detail.boundary}),typeof m=="function"&&m(a.detail.boundary,a.detail.evt)},[m]),De=i.useCallback(a=>{const H=a.detail,V=r.volumeMin;H===V&&r.volume!==V&&w({type:"muted"}),H!==V&&r.volume===V&&w({type:"unmuted"}),typeof U=="function"&&U(H)},[U,r]),Oe=i.useCallback(a=>{typeof g=="function"&&g(a.detail)},[g]),ke=i.useCallback(a=>{typeof D=="function"&&D(a.detail)},[D]);return i.useEffect(()=>{r.text=J},[J,r]),i.useEffect(()=>{o&&Number.isFinite(o)&&(r.rate=o),t&&Number.isFinite(t)&&(r.volume=t)},[r,o,t]),i.useEffect(()=>{const a=()=>{r.cancel()};return(async()=>{r.addEventListener(E.PLAYING,re),r.addEventListener(E.PAUSED,q),r.addEventListener(E.END,le),r.addEventListener(E.ERROR,_e),r.addEventListener(E.READY,oe),r.addEventListener(E.BOUNDARY,ge),r.addEventListener(E.VOLUME,De),r.addEventListener(E.PITCH,Oe),r.addEventListener(E.RATE,ke),window.addEventListener("beforeunload",a),await r.init()})(),()=>{window.removeEventListener("beforeunload",a),r.removeEventListener(E.PLAYING,re),r.removeEventListener(E.PAUSED,q),r.removeEventListener(E.END,le),r.removeEventListener(E.ERROR,_e),r.removeEventListener(E.READY,oe),r.removeEventListener(E.BOUNDARY,ge),r.removeEventListener(E.VOLUME,De),r.removeEventListener(E.PITCH,Oe),r.removeEventListener(E.RATE,ke)}},[re,ge,q,le,oe,_e,m,De,Oe,ke,r]),i.useEffect(()=>{O&&N.isReady&&(r.replay(),w({type:"play"}))},[O,r,N.isReady,J]),i.useEffect(()=>{var H;const a=()=>{w({type:"voices",payload:window.speechSynthesis.getVoices()})};return typeof((H=window.speechSynthesis)==null?void 0:H.addEventListener)=="function"&&window.speechSynthesis.addEventListener("voiceschanged",a),()=>{var V;typeof((V=window.speechSynthesis)==null?void 0:V.removeEventListener)=="function"&&window.speechSynthesis.removeEventListener("voiceschanged",a)}},[]),{get:xe,set:Ue,state:N,spokenText:J,ttsChildren:B,play:M,stop:F,pause:ne,replay:we,playOrStop:Pe,playOrPause:Le,toggleMute:be}};var k=(e=>(e.SMALL="small",e.MEDIUM="medium",e.LARGE="large",e))(k||{});const v={small:16,medium:24,large:32},at={play(e){return`
<svg
xmlns="http://www.w3.org/2000/svg"
height="${v[e]}px"
viewBox="0 0 24 24"
width="${v[e]}px"
fill="#000000">
<style>
svg {
cursor: pointer;
}
</style>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M8 5v14l11-7z" />
</svg>
`},pause(e){return`
<svg
xmlns="http://www.w3.org/2000/svg"
height="${v[e]}px"
viewBox="0 0 24 24"
width="${v[e]}px"
fill="#000000">
<style>
svg {
cursor: pointer;
}
</style>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
</svg>
`},stop(e){return`
<svg
xmlns="http://www.w3.org/2000/svg"
height="${v[e]}px"
viewBox="0 0 24 24"
width="${v[e]}px"
fill="#000000">
<style>
svg {
cursor: pointer;
}
</style>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M6 6h12v12H6z" />
</svg>
`},replay(e){return`
<svg
xmlns="http://www.w3.org/2000/svg"
height="${v[e]}px"
viewBox="0 0 24 24"
width="${v[e]}px"
fill="#000000">
<style>
svg {
cursor: pointer;
}
</style>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" />
</svg>
`},volumeDown(e){return`
<svg
xmlns="http://www.w3.org/2000/svg"
height="${v[e]}px"
viewBox="0 0 24 24"
width="${v[e]}px"
fill="#000000">
<style>
svg {
cursor: pointer;
}
</style>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M18.5 12c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM5 9v6h4l5 5V4L9 9H5z" />
</svg>
`},volumeOff(e){return`
<svg
xmlns="http://www.w3.org/2000/svg"
height="${v[e]}px"
viewBox="0 0 24 24"
width="${v[e]}px"
fill="#000000">
<style>
svg {
cursor: pointer;
}
</style>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z" />
</svg>
`},volumeUp(e){return`
<svg
xmlns="http://www.w3.org/2000/svg"
height="${v[e]}px"
viewBox="0 0 24 24"
width="${v[e]}px"
fill="#000000">
<style>
svg {
cursor: pointer;
}
</style>
<path d="M0 0h24v24H0z" fill="none" />
<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z" />
</svg>
`}},Ie={[k.SMALL]:5,[k.MEDIUM]:5,[k.LARGE]:5},ct=({size:e,align:o,type:t})=>{const n={margin:0,padding:`${Ie[e]}px`,border:"none",borderRadius:`${v[e]}px`,color:"black",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"transparent"};if(t==="replay"){const d=`-${v[e]+2*Ie[e]+5}px`;return{...n,[o==="horizontal"?"right":"bottom"]:d,position:"absolute",background:"#f2f1f1a6",zIndex:9999}}return n},He=({title:e,type:o,onClick:t,size:n=k.MEDIUM,align:d="horizontal",...y})=>{const u="tts-react-controls",A=i.useMemo(()=>at[o](n),[o,n]),b=i.useMemo(()=>ct({size:n,align:d,type:o}),[n,d,o]);return i.useEffect(()=>{let m=document.querySelector(`style[data-id="${u}"]`);return m||(m=document.createElement("style"),m.setAttribute("data-id",u),m.innerHTML=`
button[data-tts-react-control]:hover {
background-color: #ebeaeaa6 !important;
}
button[data-id="tts-react-replay"]:hover {
filter: brightness(0.98);
}
`,document.head.appendChild(m)),()=>{m=null}},[d,n,o]),i.createElement("button",{title:e,"data-tts-react-control":!0,"data-id":`tts-react-${o}`,onClick:t,style:b,dangerouslySetInnerHTML:{__html:A},...y})};var ze=(e=>(e.TL="topLeft",e.TR="topRight",e.BL="bottomLeft",e.BR="bottomRight",e.TC="topCenter",e.RC="rightCenter",e.BC="bottomCenter",e.LC="leftCenter",e))(ze||{});const ht=({position:e="leftCenter"})=>{let o="'cnt ctl'",t="1fr auto",n="start";switch(e){case"topLeft":o="'ctl cnt'",t="auto 1fr";break;case"bottomLeft":o="'ctl cnt'",n="end",t="auto 1fr";break;case"bottomRight":o="'cnt ctl'",n="end";break;case"topCenter":t="1fr",o=`'ctl'
'cnt'`,n="center";break;case"rightCenter":n="center";break;case"bottomCenter":t="1fr",o=`'cnt'
'ctl'`,n="center";break;case"leftCenter":o="'ctl cnt'",t="auto 1fr",n="center"}return{alignItems:n,gridTemplateAreas:o,gridTemplateColumns:t,display:"grid",gap:"15px"}},dt=({align:e,position:o="leftCenter",size:t=k.MEDIUM})=>({position:"relative",display:"inline-flex",flexDirection:e==="horizontal"?"row":"column",gap:"5px",gridArea:"ctl",padding:0,margin:o.includes("Center")?"auto":0,backgroundColor:"#f2f1f1a6",borderRadius:`${v[t]+Ie[t]}px`,border:"1px solid transparent"}),ut=()=>({gridArea:"cnt"}),pt=({size:e,lang:o,rate:t,voice:n,volume:d,children:y,position:u,onStart:A,onPause:b,onBoundary:m,onEnd:x,onError:L,onMuteToggled:U,onVolumeChange:g,onPitchChange:D,onRateChange:G,fetchAudioData:O,markColor:$,markBackgroundColor:j,autoPlay:N=!1,allowMuting:w=!0,align:B="horizontal",markTextAsSpoken:J=!1,useStopOverPause:r=!1})=>{const{state:M,replay:ne,toggleMute:we,playOrPause:F,playOrStop:be,ttsChildren:Le}=Ve({lang:o,rate:t,voice:n,volume:d,children:y,onStart:A,onPause:b,onBoundary:m,onEnd:x,onError:L,onVolumeChange:g,onPitchChange:D,onRateChange:G,fetchAudioData:O,autoPlay:N,markColor:$,markBackgroundColor:j,markTextAsSpoken:J}),Pe=i.useMemo(()=>ht({position:u}),[u]),xe=i.useMemo(()=>dt({align:B,position:u,size:e}),[B,u,e]),Ue=i.useMemo(()=>ut(),[]),[re,q,le]=i.useMemo(()=>M.isPlaying?r?["stop","Stop",be]:["pause","Pause",F]:["play","Play",F],[M.isPlaying,r,be,F]),oe=i.useCallback(()=>{we(U)},[we,U]);return i.createElement("div",{style:Pe,className:"tts-react","data-testid":"tts-react"},M.isReady&&i.createElement("aside",{style:xe,"data-testid":"tts-react-controls"},w&&i.createElement(He,{size:e,align:B,title:M.isMuted?"Unmute":"Mute","aria-label":M.isMuted?"Unmute":"Mute",onClick:oe,type:M.isMuted?"volumeOff":M.isPlaying?"volumeUp":"volumeDown"}),i.createElement(He,{type:re,title:q,"aria-label":q,onClick:le,size:e,align:B}),M.isPaused&&i.createElement(He,{type:"replay",size:e,align:B,title:"Replay","aria-label":"Replay",onClick:ne})),i.createElement("div",{style:Ue},Le))};var Ke=(e=>(e.ARABIC_SAUDI_ARABIA="ar-SA",e.CZECH_CZECH_REPUBLIC="cs-CZ",e.DANISH_DENMARK="da-DK",e.GERMAN_GERMANY="de-DE",e.MODERN_GREEK_GREECE="el-GR",e.ENGLISH_AUSTRALIA="en-AU",e.ENGLISH_UNITED_KINGDOM="en-GB",e.ENGLISH_IRELAND="en-IE",e.ENGLISH_UNITED_STATES="en-US",e.ENGLISH_SOUTH_AFRICA="en-ZA",e.SPANISH_SPAIN="es-ES",e.SPANISH_MEXICO="es-MX",e.FINNISH_FINLAND="fi-FI",e.FRENCH_CANADA="fr-CA",e.FRENCH_FRANCE="fr-FR",e.HEBREW_ISRAEIL="he-IL",e.HINDI_INDIA="hi-IN",e.HUNGARIAN_HUNGARY="hu-HU",e.INDONESIAN_INDONESIA="id-ID",e.ITALIAN_ITALY="it-IT",e.JAPANESE_JAPAN="ja-JP",e.KOREAN_REPUBLIC_OF_KOREA="ko-KR",e.DUTCH_BELGIUM="nl-BE",e.DUTCH_NETHERLANDS="nl-NL",e.NORWEGIAN_NORWAY="no-NO",e.POLISH_POLAND="pl-PL",e.PORTUGUESE_BRAZIL="pt-BR",e.PORTUGUESE_PORTUGAL="pt-PT",e.ROMANIAN_ROMANIA="ro-RO",e.RUSSIAN_RUSSIAN_FEDERATION="ru-RU",e.SLOVAK_SLOVAKIA="sk-SK",e.SWEDISH_SWEDEN="sv-SE",e.THAI_THAILAND="th-TH",e.TURKISH_TURKEY="tr-TR",e.CHINESE_CHINA="zh-CN",e.CHINESE_HONG_KONG="zh-HK",e.CHINESE_TAIWAN="zh-TW",e))(Ke||{});f.LanguageTags=Ke,f.Positions=ze,f.Sizes=k,f.TextToSpeech=pt,f.useTts=Ve,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});
//# sourceMappingURL=tts-react.min.js.map
{
"name": "tts-react",
"version": "3.0.2",
"version": "3.0.3",
"description": "React hook and component for converting text to speech using the Web Speech API or Amazon Polly.",

@@ -31,3 +31,3 @@ "type": "module",

"build:dual": "BABEL_ENV=dual babel-dual-package --root-mode upward --out-dir dist --extensions .ts,.tsx src",
"build:umd": "BABEL_ENV=umd microbundle -i src/index.ts -o dist/umd/tts-react.min.js -f umd --no-pkg-main --name='TTSReact' --globals react='React' --jsx='' --jsxFragment='' --tsconfig='./tsconfig.umd.json'",
"build:umd": "NODE_ENV=production vite build",
"build": "npm run build:types && npm run build:dual && npm run build:umd",

@@ -34,0 +34,0 @@ "prepack": "npm run build"

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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