@untemps/react-vocal 2.0.0-beta.13 → 2.0.0-beta.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +16 -1
- package/dist/index.cjs +2 -2
- package/dist/index.d.ts +76 -0
- package/dist/index.es.js +22 -14
- package/package.json +30 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# [2.0.0-beta.15](https://github.com/untemps/react-vocal/compare/v2.0.0-beta.14...v2.0.0-beta.15) (2026-05-24)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### chore
|
|
5
|
+
|
|
6
|
+
* Migrate codebase to TypeScript ([#156](https://github.com/untemps/react-vocal/issues/156)) ([86c6e49](https://github.com/untemps/react-vocal/commit/86c6e49a82f599b60356afb91f34b59f63710a44))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* minimum supported Node.js version bumped from `^20.19.0 || >=22.12.0` to `>=22`, aligning with the underlying @untemps/vocal 2.x direct dependency
|
|
12
|
+
|
|
13
|
+
# [2.0.0-beta.14](https://github.com/untemps/react-vocal/compare/v2.0.0-beta.13...v2.0.0-beta.14) (2026-05-24)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Performance Improvements
|
|
17
|
+
|
|
18
|
+
* Wrap _onFocus and _onBlur in useCallback ([#155](https://github.com/untemps/react-vocal/issues/155)) ([9a26840](https://github.com/untemps/react-vocal/commit/9a2684091252b784ea79f328536006f00ed9862b))
|
|
19
|
+
|
|
1
20
|
# [2.0.0-beta.13](https://github.com/untemps/react-vocal/compare/v2.0.0-beta.12...v2.0.0-beta.13) (2026-05-24)
|
|
2
21
|
|
|
3
22
|
# [2.0.0-beta.12](https://github.com/untemps/react-vocal/compare/v2.0.0-beta.11...v2.0.0-beta.12) (2026-05-24)
|
package/README.md
CHANGED
|
@@ -54,6 +54,21 @@ yarn add fuse.js
|
|
|
54
54
|
|
|
55
55
|
Without fuse.js, phrase commands fall back to case-insensitive exact matching. Single-word commands always use exact matching and never require fuse.js.
|
|
56
56
|
|
|
57
|
+
## TypeScript
|
|
58
|
+
|
|
59
|
+
`@untemps/react-vocal` is written in TypeScript and ships full type declarations. The public surface is typed end-to-end:
|
|
60
|
+
|
|
61
|
+
- `Vocal` component props (`VocalProps`, `OnResultCallback`)
|
|
62
|
+
- `useVocal` hook signature, action tuple (`UseVocalActions`, `UseVocalReturn`)
|
|
63
|
+
- `useCommands` shapes (`CommandCallback`, `CommandsMap`, `TriggerCommand`)
|
|
64
|
+
- `isSupported` function (re-exported from `@untemps/vocal`)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import Vocal, { useVocal, isSupported, type VocalProps, type CommandsMap } from '@untemps/react-vocal'
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
TypeScript is listed as an optional peer dependency (`>=6.0.0`) — install it only if your project uses TS.
|
|
71
|
+
|
|
57
72
|
## Usage
|
|
58
73
|
|
|
59
74
|
### `Vocal` component
|
|
@@ -327,7 +342,7 @@ const [ref, { start, stop, abort, subscribe, unsubscribe, clean, isRecording }]
|
|
|
327
342
|
| abort | func | Function to abort the recognition |
|
|
328
343
|
| subscribe | func | Function to subscribe to recognition events |
|
|
329
344
|
| unsubscribe | func | Function to unsubscribe to recognition events |
|
|
330
|
-
| clean | func | Function to clean
|
|
345
|
+
| clean | func | Function to remove all event listeners and clean up the recognition instance |
|
|
331
346
|
| isRecording | bool | Reactive flag mirroring whether a session is active. `true` between `start()` and the next `end`/`error` event. Updated optimistically on `start()` so the UI re-renders at click time. |
|
|
332
347
|
|
|
333
348
|
#### Cancelling a start in flight
|
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let l=require(`react`);l=c(l,1);var u=()=>!!navigator.permissions,d=()=>!!navigator.mediaDevices,f=async(e,t,{signal:n}={})=>{if(!u()||!d())throw new DOMException(`Navigator API: permissions or Navigator API: mediaDevices not supported`,`NOT_SUPPORTED_ERR`);if(n?.throwIfAborted(),(await navigator.permissions.query({name:e})).state===`denied`)throw new DOMException(`Permission denied`,`NOT_ALLOWED_ERR`);n?.throwIfAborted();let r=navigator.mediaDevices.getUserMedia(t);if(!n)return r;let i,a=new Promise((e,t)=>{i=()=>t(n.reason),n.addEventListener(`abort`,i,{once:!0})});return Promise.race([r,a]).finally(()=>{n.removeEventListener(`abort`,i)})},p={AUDIO_END:`audioend`,AUDIO_START:`audiostart`,END:`end`,ERROR:`error`,NO_MATCH:`nomatch`,RESULT:`result`,SOUND_END:`soundend`,SOUND_START:`soundstart`,SPEECH_END:`speechend`,SPEECH_START:`speechstart`,START:`start`},m=1e3,h=new Set([`not-allowed`,`service-not-allowed`,`audio-capture`]),g={grammars:null,lang:`en-US`,continuous:!1,interimResults:!1,maxAlternatives:1},_=()=>{if(!(typeof window>`u`))return window.SpeechRecognition??window.webkitSpeechRecognition??window.mozSpeechRecognition??window.msSpeechRecognition},v=()=>window.SpeechGrammarList??window.webkitSpeechGrammarList??window.mozSpeechGrammarList??window.msSpeechGrammarList,y=e=>e.reduce((e,t)=>(t.confidence??0)>(e.confidence??0)?t:e),b=e=>{let t=e.slice();return Object.defineProperty(t,`isFinal`,{value:!0}),Object.defineProperty(t,`item`,{value:e=>t[e]}),t},x=e=>{let t=e.slice();return Object.defineProperty(t,`item`,{value:e=>t[e]}),t},S=e=>Object.values(p).includes(e),C=e=>`Unknown event type "${e}". Valid types are: ${Object.values(p).join(`, `)}.`,w=()=>!!_()&&!!u()&&!!d(),T=e=>{let t=_();if(!t)throw new DOMException(`SpeechRecognition not supported`,`NOT_SUPPORTED_ERR`);let n=new t,r={},i=!1,a=!1,o=0,s=null,c=!1,l=[],u={...g,...e??{}};if(n.lang=u.lang,n.continuous=u.continuous,n.interimResults=u.interimResults,n.maxAlternatives=u.maxAlternatives,u.grammars)n.grammars=u.grammars;else{let e=v();n.grammars=e?new e:null}let d=()=>{s!==null&&(clearTimeout(s),s=null),c=!1},w=()=>!!n&&!a&&n.continuous,T=()=>{s=null;try{n.start(),o=Date.now()}catch{c=!1,i=!1}},E=()=>{let e=l;if(l=[],e.length===0||!r[p.RESULT]?.length)return;let t=e.map(e=>y(Array.from(e)).transcript).join(` `).trim(),n=Object.assign(new Event(p.RESULT),{resultIndex:0,results:x(e)});[...r[p.RESULT]].forEach(({callback:e})=>{e(n,t,[t])})},D=[[p.END,e=>{if(w()){let t=Math.max(0,m-(Date.now()-o));c=!0,s=setTimeout(T,t),e.stopImmediatePropagation();return}E(),i=!1}],[p.START,e=>{c&&(e.stopImmediatePropagation(),queueMicrotask(()=>{c=!1}))}],[p.ERROR,e=>{h.has(e.error)&&(a=!0,d(),i=!1)}],[p.RESULT,e=>{if(!u.continuous)return;let t=e,n=t.results?.[t.resultIndex];n?.isFinal&&l.push(b(Array.from(n)))}]];D.forEach(([e,t])=>n.addEventListener(e,t));let O=async({signal:e}={})=>{if(n)try{let t=await f(`microphone`,{audio:!0},{signal:e});if(e?.aborted||!n)return;if(!t)throw Error(`Unable to retrieve the stream from media device`);a=!1,l=[],n.start(),i=!0,o=Date.now()}catch(e){if(e instanceof Error&&e.name===`AbortError`)return;throw e}},k=()=>{n&&(a=!0,d(),n.stop(),i=!1)},A=()=>{n&&(a=!0,d(),l=[],n.abort(),i=!1)},j=(e,t)=>{if(!S(e))throw Error(C(e));if(!n)return;let i=n=>{if(c&&(e===p.END||e===p.START))return;if(e!==p.RESULT){t(n);return}let r=n;if(!(r.results?.length>0)||r.resultIndex>=r.results.length){t(n);return}let i=r.results[r.resultIndex];if(u.continuous&&i.isFinal)return;let a=Array.from(i);t(n,y(a).transcript,a.map(e=>e.transcript))};n.addEventListener(e,i),r[e]||(r[e]=[]),r[e].push({callback:t,handler:i})},M=(e,t)=>{if(!S(e))throw Error(C(e));if(!(!n||!r[e]))if(t!==void 0){let i=r[e].findIndex(e=>e.callback===t);i!==-1&&(n.removeEventListener(e,r[e][i].handler),r[e].splice(i,1),r[e].length===0&&delete r[e])}else r[e].forEach(({handler:t})=>n.removeEventListener(e,t)),delete r[e]};return{get isRecording(){return i},start:O,stop:k,abort:A,on:j,off:M,cleanup:()=>{k(),Object.keys(r).forEach(e=>M(e)),D.forEach(([e,t])=>n?.removeEventListener(e,t)),n=null}}},E=e=>typeof e==`function`,D=(e=`en-US`,t=null,n=1,r=!1,i=null)=>{let a=(0,l.useRef)(null),[o,s]=(0,l.useState)(!1),c=(0,l.useMemo)(()=>w(),[]);return(0,l.useEffect)(()=>{if(c){let o=i||T({lang:e,grammars:t,maxAlternatives:n,continuous:r});a.current=o;let c=()=>s(!0),l=()=>s(!1);return o.on(`start`,c),o.on(`end`,l),o.on(`error`,l),()=>{o.off(`start`,c),o.off(`end`,l),o.off(`error`,l),o.abort(),o.cleanup(),s(!1)}}},[e,t,n,r,i,c]),[a,{start:(0,l.useCallback)(e=>{if(a.current)return s(!0),a.current.start(e)},[]),stop:(0,l.useCallback)(()=>{a.current&&a.current.stop()},[]),abort:(0,l.useCallback)(()=>{a.current&&a.current.abort()},[]),subscribe:(0,l.useCallback)((e,t)=>{a.current&&a.current.on(e,t)},[]),unsubscribe:(0,l.useCallback)((e,t)=>{a.current&&a.current.off(e,t)},[]),clean:(0,l.useCallback)(()=>{a.current&&a.current.cleanup()},[]),isRecording:o}]},O=(e,t=0)=>{let n=(0,l.useRef)(-1),r=(0,l.useCallback)(()=>{clearTimeout(n.current),n.current=-1},[]),i=(0,l.useCallback)(()=>{r(),n.current=setTimeout(e,t)},[e,t,r]);return(0,l.useEffect)(()=>r,[r]),[i,r]},k=(e,t=.4)=>{let n=(0,l.useMemo)(()=>e?Object.entries(e).reduce((e,[t,n])=>({...e,[t.toLowerCase()]:n}),{}):{},[e]),r=(0,l.useMemo)(()=>Object.keys(n),[n]),i=(0,l.useMemo)(()=>r.some(e=>e.includes(` `)),[r]),a=(0,l.useRef)(null);return(0,l.useEffect)(()=>{if(!i){a.current=null;return}let e=!1;return import(`fuse.js`).then(t=>{e||(a.current=new(t.default??t)(r,{includeScore:!0,ignoreLocation:!0}))}).catch(()=>{e||process.env.NODE_ENV!==`production`&&console.warn(`[react-vocal] fuse.js is not installed. Phrase command keys will fall back to exact matching. Install fuse.js to enable fuzzy matching: npm install fuse.js`)}),()=>{e=!0}},[i,r]),e=>{if(!r.length)return null;if(!i){let t=e.trim().split(/\s+/),r=t.length>1?t:[e.trim()];for(let e of r){let t=e.toLowerCase();if(t in n)return n[t]?.(e,t)}return null}let o=a.current;if(o){let r=o.search(e).filter(e=>e.score<t);if(r?.length){let t=r[0].item.toLowerCase();return n[t]?.(e,t)}}else{let t=e.toLowerCase(),i=r.find(e=>t.includes(e)||e.includes(t));if(i)return n[i]?.(e,i)}return null}},A=o((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),j=o((e=>{process.env.NODE_ENV!==`production`&&(function(){function t(e){if(e==null)return null;if(typeof e==`function`)return e.$$typeof===O?null:e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case _:return`Fragment`;case y:return`Profiler`;case v:return`StrictMode`;case C:return`Suspense`;case w:return`SuspenseList`;case D:return`Activity`}if(typeof e==`object`)switch(typeof e.tag==`number`&&console.error(`Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.`),e.$$typeof){case g:return`Portal`;case x:return e.displayName||`Context`;case b:return(e._context.displayName||`Context`)+`.Consumer`;case S:var n=e.render;return e=e.displayName,e||=(e=n.displayName||n.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case T:return n=e.displayName||null,n===null?t(e.type)||`Memo`:n;case E:n=e._payload,e=e._init;try{return t(e(n))}catch{}}return null}function n(e){return``+e}function r(e){try{n(e);var t=!1}catch{t=!0}if(t){t=console;var r=t.error,i=typeof Symbol==`function`&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||`Object`;return r.call(t,`The provided key is an unsupported type %s. This value must be coerced to a string before using it here.`,i),n(e)}}function i(e){if(e===_)return`<>`;if(typeof e==`object`&&e&&e.$$typeof===E)return`<...>`;try{var n=t(e);return n?`<`+n+`>`:`<...>`}catch{return`<...>`}}function a(){var e=k.A;return e===null?null:e.getOwner()}function o(){return Error(`react-stack-top-frame`)}function s(e){if(A.call(e,`key`)){var t=Object.getOwnPropertyDescriptor(e,`key`).get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function c(e,t){function n(){N||(N=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}n.isReactWarning=!0,Object.defineProperty(e,`key`,{get:n,configurable:!0})}function l(){var e=t(this.type);return P[e]||(P[e]=!0,console.error(`Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.`)),e=this.props.ref,e===void 0?null:e}function u(e,t,n,r,i,a){var o=n.ref;return e={$$typeof:h,type:e,key:t,props:n,_owner:r},(o===void 0?null:o)===null?Object.defineProperty(e,`ref`,{enumerable:!1,value:null}):Object.defineProperty(e,`ref`,{enumerable:!1,get:l}),e._store={},Object.defineProperty(e._store,`validated`,{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,`_debugInfo`,{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,`_debugStack`,{configurable:!1,enumerable:!1,writable:!0,value:i}),Object.defineProperty(e,`_debugTask`,{configurable:!1,enumerable:!1,writable:!0,value:a}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function d(e,n,i,o,l,d){var p=n.children;if(p!==void 0)if(o)if(j(p)){for(o=0;o<p.length;o++)f(p[o]);Object.freeze&&Object.freeze(p)}else console.error(`React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.`);else f(p);if(A.call(n,`key`)){p=t(e);var m=Object.keys(n).filter(function(e){return e!==`key`});o=0<m.length?`{key: someKey, `+m.join(`: ..., `)+`: ...}`:`{key: someKey}`,L[p+o]||(m=0<m.length?`{`+m.join(`: ..., `)+`: ...}`:`{}`,console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports);let t=require(`react`);var n=()=>!!navigator.permissions,r=()=>!!navigator.mediaDevices,i=async(e,t,{signal:i}={})=>{if(!n()||!r())throw new DOMException(`Navigator API: permissions or Navigator API: mediaDevices not supported`,`NOT_SUPPORTED_ERR`);if(i?.throwIfAborted(),(await navigator.permissions.query({name:e})).state===`denied`)throw new DOMException(`Permission denied`,`NOT_ALLOWED_ERR`);i?.throwIfAborted();let a=navigator.mediaDevices.getUserMedia(t);if(!i)return a;let o,s=new Promise((e,t)=>{o=()=>t(i.reason),i.addEventListener(`abort`,o,{once:!0})});return Promise.race([a,s]).finally(()=>{i.removeEventListener(`abort`,o)})},a={AUDIO_END:`audioend`,AUDIO_START:`audiostart`,END:`end`,ERROR:`error`,NO_MATCH:`nomatch`,RESULT:`result`,SOUND_END:`soundend`,SOUND_START:`soundstart`,SPEECH_END:`speechend`,SPEECH_START:`speechstart`,START:`start`},o=1e3,s=new Set([`not-allowed`,`service-not-allowed`,`audio-capture`]),c={grammars:null,lang:`en-US`,continuous:!1,interimResults:!1,maxAlternatives:1},l=()=>{if(!(typeof window>`u`))return window.SpeechRecognition??window.webkitSpeechRecognition??window.mozSpeechRecognition??window.msSpeechRecognition},u=()=>window.SpeechGrammarList??window.webkitSpeechGrammarList??window.mozSpeechGrammarList??window.msSpeechGrammarList,d=e=>e.reduce((e,t)=>(t.confidence??0)>(e.confidence??0)?t:e),f=e=>{let t=e.slice();return Object.defineProperty(t,`isFinal`,{value:!0}),Object.defineProperty(t,`item`,{value:e=>t[e]}),t},p=e=>{let t=e.slice();return Object.defineProperty(t,`item`,{value:e=>t[e]}),t},m=e=>Object.values(a).includes(e),h=e=>`Unknown event type "${e}". Valid types are: ${Object.values(a).join(`, `)}.`,g=()=>!!l()&&!!n()&&!!r(),_=e=>{let t=l();if(!t)throw new DOMException(`SpeechRecognition not supported`,`NOT_SUPPORTED_ERR`);let n=new t,r={},g=!1,_=!1,v=0,y=null,b=!1,x=[],S={...c,...e??{}};if(n.lang=S.lang,n.continuous=S.continuous,n.interimResults=S.interimResults,n.maxAlternatives=S.maxAlternatives,S.grammars)n.grammars=S.grammars;else{let e=u();n.grammars=e?new e:null}let C=()=>{y!==null&&(clearTimeout(y),y=null),b=!1},w=()=>!!n&&!_&&n.continuous,T=()=>{y=null;try{n.start(),v=Date.now()}catch{b=!1,g=!1}},E=()=>{let e=x;if(x=[],e.length===0||!r[a.RESULT]?.length)return;let t=e.map(e=>d(Array.from(e)).transcript).join(` `).trim(),n=Object.assign(new Event(a.RESULT),{resultIndex:0,results:p(e)});[...r[a.RESULT]].forEach(({callback:e})=>{e(n,t,[t])})},D=[[a.END,e=>{if(w()){let t=Math.max(0,o-(Date.now()-v));b=!0,y=setTimeout(T,t),e.stopImmediatePropagation();return}E(),g=!1}],[a.START,e=>{b&&(e.stopImmediatePropagation(),queueMicrotask(()=>{b=!1}))}],[a.ERROR,e=>{s.has(e.error)&&(_=!0,C(),g=!1)}],[a.RESULT,e=>{if(!S.continuous)return;let t=e,n=t.results?.[t.resultIndex];n?.isFinal&&x.push(f(Array.from(n)))}]];D.forEach(([e,t])=>n.addEventListener(e,t));let O=async({signal:e}={})=>{if(n)try{let t=await i(`microphone`,{audio:!0},{signal:e});if(e?.aborted||!n)return;if(!t)throw Error(`Unable to retrieve the stream from media device`);_=!1,x=[],n.start(),g=!0,v=Date.now()}catch(e){if(e instanceof Error&&e.name===`AbortError`)return;throw e}},k=()=>{n&&(_=!0,C(),n.stop(),g=!1)},A=()=>{n&&(_=!0,C(),x=[],n.abort(),g=!1)},j=(e,t)=>{if(!m(e))throw Error(h(e));if(!n)return;let i=n=>{if(b&&(e===a.END||e===a.START))return;if(e!==a.RESULT){t(n);return}let r=n;if(!(r.results?.length>0)||r.resultIndex>=r.results.length){t(n);return}let i=r.results[r.resultIndex];if(S.continuous&&i.isFinal)return;let o=Array.from(i);t(n,d(o).transcript,o.map(e=>e.transcript))};n.addEventListener(e,i),r[e]||(r[e]=[]),r[e].push({callback:t,handler:i})},M=(e,t)=>{if(!m(e))throw Error(h(e));if(!(!n||!r[e]))if(t!==void 0){let i=r[e].findIndex(e=>e.callback===t);i!==-1&&(n.removeEventListener(e,r[e][i].handler),r[e].splice(i,1),r[e].length===0&&delete r[e])}else r[e].forEach(({handler:t})=>n.removeEventListener(e,t)),delete r[e]};return{get isRecording(){return g},start:O,stop:k,abort:A,on:j,off:M,cleanup:()=>{k(),Object.keys(r).forEach(e=>M(e)),D.forEach(([e,t])=>n?.removeEventListener(e,t)),n=null}}},v=e=>typeof e==`function`,y=(e=`en-US`,n=null,r=1,i=!1,a=null)=>{let o=(0,t.useRef)(null),[s,c]=(0,t.useState)(!1),l=(0,t.useMemo)(()=>g(),[]);return(0,t.useEffect)(()=>{if(l){let t=a||_({lang:e,grammars:n,maxAlternatives:r,continuous:i});o.current=t;let s=()=>c(!0),l=()=>c(!1);return t.on(`start`,s),t.on(`end`,l),t.on(`error`,l),()=>{t.off(`start`,s),t.off(`end`,l),t.off(`error`,l),t.abort(),t.cleanup(),c(!1)}}},[e,n,r,i,a,l]),[o,{start:(0,t.useCallback)(e=>{if(o.current)return c(!0),o.current.start(e)},[]),stop:(0,t.useCallback)(()=>{o.current&&o.current.stop()},[]),abort:(0,t.useCallback)(()=>{o.current&&o.current.abort()},[]),subscribe:(0,t.useCallback)((e,t)=>{o.current&&o.current.on(e,t)},[]),unsubscribe:(0,t.useCallback)((e,t)=>{o.current&&o.current.off(e,t)},[]),clean:(0,t.useCallback)(()=>{o.current&&o.current.cleanup()},[]),isRecording:s}]},b=(e,n=0)=>{let r=(0,t.useRef)(-1),i=(0,t.useCallback)(()=>{clearTimeout(r.current),r.current=-1},[]),a=(0,t.useCallback)(()=>{i(),r.current=setTimeout(e,n)},[e,n,i]);return(0,t.useEffect)(()=>i,[i]),[a,i]},x=(e,n=.4)=>{let r=(0,t.useMemo)(()=>e?Object.entries(e).reduce((e,[t,n])=>({...e,[t.toLowerCase()]:n}),{}):{},[e]),i=(0,t.useMemo)(()=>Object.keys(r),[r]),a=(0,t.useMemo)(()=>i.some(e=>e.includes(` `)),[i]),o=(0,t.useRef)(null);return(0,t.useEffect)(()=>{if(!a){o.current=null;return}let e=!1;return import(`fuse.js`).then(t=>{e||(o.current=new(t.default??t)(i,{includeScore:!0,ignoreLocation:!0}))}).catch(()=>{e||process.env.NODE_ENV!==`production`&&console.warn(`[react-vocal] fuse.js is not installed. Phrase command keys will fall back to exact matching. Install fuse.js to enable fuzzy matching: npm install fuse.js`)}),()=>{e=!0}},[a,i]),e=>{if(!i.length)return null;if(!a){let t=e.trim().split(/\s+/),n=t.length>1?t:[e.trim()];for(let e of n){let t=e.toLowerCase();if(t in r)return r[t]?.(e,t)}return null}let t=o.current;if(t){let i=t.search(e).filter(e=>(e.score??1)<n);if(i?.length){let t=i[0].item.toLowerCase();return r[t]?.(e,t)}}else{let t=e.toLowerCase(),n=i.find(e=>t.includes(e)||e.includes(t));if(n)return r[n]?.(e,n)}return null}},S=e((e=>{var t=Symbol.for(`react.transitional.element`),n=Symbol.for(`react.fragment`);function r(e,n,r){var i=null;if(r!==void 0&&(i=``+r),n.key!==void 0&&(i=``+n.key),`key`in n)for(var a in r={},n)a!==`key`&&(r[a]=n[a]);else r=n;return n=r.ref,{$$typeof:t,type:e,key:i,ref:n===void 0?null:n,props:r}}e.Fragment=n,e.jsx=r,e.jsxs=r})),C=e((e=>{process.env.NODE_ENV!==`production`&&(function(){function t(e){if(e==null)return null;if(typeof e==`function`)return e.$$typeof===O?null:e.displayName||e.name||null;if(typeof e==`string`)return e;switch(e){case _:return`Fragment`;case y:return`Profiler`;case v:return`StrictMode`;case C:return`Suspense`;case w:return`SuspenseList`;case D:return`Activity`}if(typeof e==`object`)switch(typeof e.tag==`number`&&console.error(`Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue.`),e.$$typeof){case g:return`Portal`;case x:return e.displayName||`Context`;case b:return(e._context.displayName||`Context`)+`.Consumer`;case S:var n=e.render;return e=e.displayName,e||=(e=n.displayName||n.name||``,e===``?`ForwardRef`:`ForwardRef(`+e+`)`),e;case T:return n=e.displayName||null,n===null?t(e.type)||`Memo`:n;case E:n=e._payload,e=e._init;try{return t(e(n))}catch{}}return null}function n(e){return``+e}function r(e){try{n(e);var t=!1}catch{t=!0}if(t){t=console;var r=t.error,i=typeof Symbol==`function`&&Symbol.toStringTag&&e[Symbol.toStringTag]||e.constructor.name||`Object`;return r.call(t,`The provided key is an unsupported type %s. This value must be coerced to a string before using it here.`,i),n(e)}}function i(e){if(e===_)return`<>`;if(typeof e==`object`&&e&&e.$$typeof===E)return`<...>`;try{var n=t(e);return n?`<`+n+`>`:`<...>`}catch{return`<...>`}}function a(){var e=k.A;return e===null?null:e.getOwner()}function o(){return Error(`react-stack-top-frame`)}function s(e){if(A.call(e,`key`)){var t=Object.getOwnPropertyDescriptor(e,`key`).get;if(t&&t.isReactWarning)return!1}return e.key!==void 0}function c(e,t){function n(){N||(N=!0,console.error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)",t))}n.isReactWarning=!0,Object.defineProperty(e,`key`,{get:n,configurable:!0})}function l(){var e=t(this.type);return P[e]||(P[e]=!0,console.error(`Accessing element.ref was removed in React 19. ref is now a regular prop. It will be removed from the JSX Element type in a future release.`)),e=this.props.ref,e===void 0?null:e}function u(e,t,n,r,i,a){var o=n.ref;return e={$$typeof:h,type:e,key:t,props:n,_owner:r},(o===void 0?null:o)===null?Object.defineProperty(e,`ref`,{enumerable:!1,value:null}):Object.defineProperty(e,`ref`,{enumerable:!1,get:l}),e._store={},Object.defineProperty(e._store,`validated`,{configurable:!1,enumerable:!1,writable:!0,value:0}),Object.defineProperty(e,`_debugInfo`,{configurable:!1,enumerable:!1,writable:!0,value:null}),Object.defineProperty(e,`_debugStack`,{configurable:!1,enumerable:!1,writable:!0,value:i}),Object.defineProperty(e,`_debugTask`,{configurable:!1,enumerable:!1,writable:!0,value:a}),Object.freeze&&(Object.freeze(e.props),Object.freeze(e)),e}function d(e,n,i,o,l,d){var p=n.children;if(p!==void 0)if(o)if(j(p)){for(o=0;o<p.length;o++)f(p[o]);Object.freeze&&Object.freeze(p)}else console.error(`React.jsx: Static children should always be an array. You are likely explicitly calling React.jsxs or React.jsxDEV. Use the Babel transform instead.`);else f(p);if(A.call(n,`key`)){p=t(e);var m=Object.keys(n).filter(function(e){return e!==`key`});o=0<m.length?`{key: someKey, `+m.join(`: ..., `)+`: ...}`:`{key: someKey}`,L[p+o]||(m=0<m.length?`{`+m.join(`: ..., `)+`: ...}`:`{}`,console.error(`A props object containing a "key" prop is being spread into JSX:
|
|
2
2
|
let props = %s;
|
|
3
3
|
<%s {...props} />
|
|
4
4
|
React keys must be passed directly to JSX without using spread:
|
|
5
5
|
let props = %s;
|
|
6
|
-
<%s key={someKey} {...props} />`,o,p,m,p),L[p+o]=!0)}if(p=null,i!==void 0&&(r(i),p=``+i),s(n)&&(r(n.key),p=``+n.key),`key`in n)for(var h in i={},n)h!==`key`&&(i[h]=n[h]);else i=n;return p&&c(i,typeof e==`function`?e.displayName||e.name||`Unknown`:e),u(e,p,i,a(),l,d)}function f(e){p(e)?e._store&&(e._store.validated=1):typeof e==`object`&&e&&e.$$typeof===E&&(e._payload.status===`fulfilled`?p(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function p(e){return typeof e==`object`&&!!e&&e.$$typeof===h}var m=require(`react`),h=Symbol.for(`react.transitional.element`),g=Symbol.for(`react.portal`),_=Symbol.for(`react.fragment`),v=Symbol.for(`react.strict_mode`),y=Symbol.for(`react.profiler`),b=Symbol.for(`react.consumer`),x=Symbol.for(`react.context`),S=Symbol.for(`react.forward_ref`),C=Symbol.for(`react.suspense`),w=Symbol.for(`react.suspense_list`),T=Symbol.for(`react.memo`),E=Symbol.for(`react.lazy`),D=Symbol.for(`react.activity`),O=Symbol.for(`react.client.reference`),k=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,A=Object.prototype.hasOwnProperty,j=Array.isArray,M=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(e){return e()}};var N,P={},F=m.react_stack_bottom_frame.bind(m,o)(),I=M(i(o)),L={};e.Fragment=_,e.jsx=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!1,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)},e.jsxs=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!0,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)}})()})),
|
|
6
|
+
<%s key={someKey} {...props} />`,o,p,m,p),L[p+o]=!0)}if(p=null,i!==void 0&&(r(i),p=``+i),s(n)&&(r(n.key),p=``+n.key),`key`in n)for(var h in i={},n)h!==`key`&&(i[h]=n[h]);else i=n;return p&&c(i,typeof e==`function`?e.displayName||e.name||`Unknown`:e),u(e,p,i,a(),l,d)}function f(e){p(e)?e._store&&(e._store.validated=1):typeof e==`object`&&e&&e.$$typeof===E&&(e._payload.status===`fulfilled`?p(e._payload.value)&&e._payload.value._store&&(e._payload.value._store.validated=1):e._store&&(e._store.validated=1))}function p(e){return typeof e==`object`&&!!e&&e.$$typeof===h}var m=require(`react`),h=Symbol.for(`react.transitional.element`),g=Symbol.for(`react.portal`),_=Symbol.for(`react.fragment`),v=Symbol.for(`react.strict_mode`),y=Symbol.for(`react.profiler`),b=Symbol.for(`react.consumer`),x=Symbol.for(`react.context`),S=Symbol.for(`react.forward_ref`),C=Symbol.for(`react.suspense`),w=Symbol.for(`react.suspense_list`),T=Symbol.for(`react.memo`),E=Symbol.for(`react.lazy`),D=Symbol.for(`react.activity`),O=Symbol.for(`react.client.reference`),k=m.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE,A=Object.prototype.hasOwnProperty,j=Array.isArray,M=console.createTask?console.createTask:function(){return null};m={react_stack_bottom_frame:function(e){return e()}};var N,P={},F=m.react_stack_bottom_frame.bind(m,o)(),I=M(i(o)),L={};e.Fragment=_,e.jsx=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!1,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)},e.jsxs=function(e,t,n){var r=1e4>k.recentlyCreatedOwnerStacks++;return d(e,t,n,!0,r?Error(`react-stack-top-frame`):F,r?M(i(e)):I)}})()})),w=e(((e,t)=>{process.env.NODE_ENV===`production`?t.exports=S():t.exports=C()}))(),T=({color:e=`black`,activeColor:t=`red`,isActive:n=!1})=>(0,w.jsx)(`svg`,{"data-testid":`__icon-root__`,xmlns:`http://www.w3.org/2000/svg`,width:`100%`,height:`100%`,viewBox:`0 0 24 24`,"aria-hidden":`true`,children:(0,w.jsxs)(`g`,{children:[(0,w.jsx)(`path`,{"data-testid":`__icon-path__`,fill:e,d:`M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z`}),n&&(0,w.jsx)(`circle`,{"data-testid":`__icon-active__`,fill:t,cx:`16`,cy:`4`,r:`4`})]})}),E=(e,t)=>{for(let n of e)for(let e of n)if(t(e.transcript??``)!==null)return},D=({children:e,commands:n=null,lang:r=`en-US`,grammars:i=null,timeout:a=3e3,silenceTimeout:o=null,precision:s=.4,maxAlternatives:c=1,continuous:l=!1,ariaLabel:u=`start recognition`,style:d=null,className:f=null,outlineStyle:p=`2px solid`,onStart:m=null,onEnd:h=null,onSpeechStart:_=null,onSpeechEnd:S=null,onResult:C=null,onError:D=null,onNoMatch:O=null,signal:k=null,__rsInstance:A=null})=>{let j=(0,t.useRef)(null),M=(0,t.useMemo)(()=>g(),[]),[,{start:N,stop:P,subscribe:F,unsubscribe:I,isRecording:L}]=y(r,i,c,l,A),ee=x(n,s),R=(0,t.useRef)({onStart:null,onEnd:null,onSpeechStart:null,onSpeechEnd:null,onResult:null,onError:null,onNoMatch:null});R.current={onStart:m,onEnd:h,onSpeechStart:_,onSpeechEnd:S,onResult:C,onError:D,onNoMatch:O};let z=(0,t.useRef)(l);z.current=l;let B=(0,t.useRef)(ee);B.current=ee;let V=(0,t.useRef)(null),H=(0,t.useRef)(null),U=(0,t.useRef)(!1),W=(0,t.useRef)(o);W.current=o;let G=(0,t.useCallback)(()=>H.current?.(),[]),[K,q]=b(G,a),[te,J]=b(G,o??0),Y=(0,t.useCallback)(()=>{try{P()}catch(e){R.current.onError?.(e),V.current?.()}},[P]),ne=(0,t.useCallback)(e=>{K(),R.current.onStart?.(e)},[K]),re=(0,t.useCallback)(e=>{q(),R.current.onSpeechStart?.(e)},[q]),ie=(0,t.useCallback)(e=>{K(),z.current&&(W.current??0)>0&&te(),R.current.onSpeechEnd?.(e)},[K,te]),ae=(0,t.useCallback)((e,t)=>{q(),z.current||(E(e.results===void 0?[]:Array.from(e.results,e=>Array.from(e)),B.current),Y()),R.current.onResult?.(t,e)},[q,Y]),X=(0,t.useCallback)(e=>{Y(),R.current.onError?.(e)},[Y]),oe=(0,t.useCallback)(e=>{q(),Y(),R.current.onNoMatch?.(e)},[q,Y]),Z=(0,t.useCallback)(e=>{if(!U.current){U.current=!0,q(),J();try{Y(),V.current?.()}finally{U.current=!1,R.current.onEnd?.(e)}}},[q,J,Y]);H.current=Z;let Q=(0,t.useMemo)(()=>({start:ne,end:Z,speechstart:re,speechend:ie,result:ae,error:X,nomatch:oe}),[ne,Z,re,ie,ae,X,oe]);V.current=()=>Object.entries(Q).forEach(([e,t])=>I?.(e,t));let $=(0,t.useCallback)(()=>{try{J(),Object.entries(Q).forEach(([e,t])=>F(e,t)),N({signal:k??void 0})?.catch?.(X)}catch(e){X(e)}},[Q,F,N,J,X,k]),se=(0,t.useCallback)(()=>{!f&&p&&j.current&&(j.current.style.outline=p)},[f,p]),ce=(0,t.useCallback)(()=>{!f&&p&&j.current&&(j.current.style.outline=`none`)},[f,p]);return M?v(e)?e($,Y,L):(0,t.isValidElement)(e)?(0,t.cloneElement)(e,{...!L&&{onClick:$}}):(0,w.jsx)(`button`,{"data-testid":`__vocal-root__`,ref:j,"aria-label":u,"aria-pressed":L,style:f?void 0:{width:24,height:24,backgroundColor:`transparent`,border:`none`,padding:0,cursor:!l&&L?`default`:`pointer`,...d??{}},className:f??void 0,onFocus:se,onBlur:ce,onClick:L?Y:$,children:(0,w.jsx)(T,{isActive:L,color:`#aaa`})}):null};exports.default=D,exports.isSupported=g,exports.useVocal=y;
|
|
7
7
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { CSSProperties } from 'react';
|
|
2
|
+
import { EventHandlerFor } from '@untemps/vocal';
|
|
3
|
+
import { EventType } from '@untemps/vocal';
|
|
4
|
+
import { GenericEventHandler } from '@untemps/vocal';
|
|
5
|
+
import { isSupported } from '@untemps/vocal';
|
|
6
|
+
import { JSX } from 'react/jsx-runtime';
|
|
7
|
+
import { ReactElement } from 'react';
|
|
8
|
+
import { ReactNode } from 'react';
|
|
9
|
+
import { RefObject } from 'react';
|
|
10
|
+
import { VocalInstance } from '@untemps/vocal';
|
|
11
|
+
|
|
12
|
+
export declare type CommandCallback = (rawInput: string, commandKey: string) => unknown;
|
|
13
|
+
|
|
14
|
+
export declare type CommandsMap = Record<string, CommandCallback>;
|
|
15
|
+
|
|
16
|
+
export { isSupported }
|
|
17
|
+
|
|
18
|
+
export declare type OnResultCallback = (bestAlternative: string, event: SpeechRecognitionEvent | Event) => void;
|
|
19
|
+
|
|
20
|
+
export declare type TriggerCommand = (rawInput: string) => unknown;
|
|
21
|
+
|
|
22
|
+
export declare const useVocal: (lang?: string, grammars?: SpeechGrammarList | null, maxAlternatives?: number, continuous?: boolean, __rsInstance?: VocalInstance | null) => UseVocalReturn;
|
|
23
|
+
|
|
24
|
+
export declare interface UseVocalActions {
|
|
25
|
+
start: (options?: {
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
}) => Promise<void> | undefined;
|
|
28
|
+
stop: () => void;
|
|
29
|
+
abort: () => void;
|
|
30
|
+
subscribe: {
|
|
31
|
+
<T extends EventType>(eventType: T, handler: EventHandlerFor<T>): void;
|
|
32
|
+
(eventType: string, handler: GenericEventHandler): void;
|
|
33
|
+
};
|
|
34
|
+
unsubscribe: {
|
|
35
|
+
<T extends EventType>(eventType: T, handler?: EventHandlerFor<T>): void;
|
|
36
|
+
(eventType: string, handler?: GenericEventHandler): void;
|
|
37
|
+
};
|
|
38
|
+
clean: () => void;
|
|
39
|
+
isRecording: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export declare type UseVocalReturn = [RefObject<VocalInstance | null>, UseVocalActions];
|
|
43
|
+
|
|
44
|
+
declare const Vocal: ({ children, commands, lang, grammars, timeout, silenceTimeout, precision, maxAlternatives, continuous, ariaLabel, style, className, outlineStyle, onStart, onEnd, onSpeechStart, onSpeechEnd, onResult, onError, onNoMatch, signal, __rsInstance, }: VocalProps) => JSX.Element | null;
|
|
45
|
+
export default Vocal;
|
|
46
|
+
|
|
47
|
+
export declare interface VocalProps {
|
|
48
|
+
children?: ReactNode | ((start: () => void, stop: () => void, isStarted: boolean) => ReactElement | null);
|
|
49
|
+
commands?: CommandsMap | null;
|
|
50
|
+
lang?: string;
|
|
51
|
+
grammars?: SpeechGrammarList | null;
|
|
52
|
+
timeout?: number;
|
|
53
|
+
silenceTimeout?: number | null;
|
|
54
|
+
precision?: number;
|
|
55
|
+
maxAlternatives?: number;
|
|
56
|
+
continuous?: boolean;
|
|
57
|
+
ariaLabel?: string;
|
|
58
|
+
style?: CSSProperties | null;
|
|
59
|
+
className?: string | null;
|
|
60
|
+
outlineStyle?: string | null;
|
|
61
|
+
onStart?: ((event: Event) => void) | null;
|
|
62
|
+
onEnd?: ((event?: Event) => void) | null;
|
|
63
|
+
onSpeechStart?: ((event: Event) => void) | null;
|
|
64
|
+
onSpeechEnd?: ((event: Event) => void) | null;
|
|
65
|
+
onResult?: OnResultCallback | null;
|
|
66
|
+
onError?: ((error: unknown) => void) | null;
|
|
67
|
+
onNoMatch?: ((event: Event) => void) | null;
|
|
68
|
+
signal?: AbortSignal | null;
|
|
69
|
+
/**
|
|
70
|
+
* Internal/testing escape hatch. Injects a custom vocal instance. Not part of the
|
|
71
|
+
* stable public API — see issue #136 for the redesign of this surface.
|
|
72
|
+
*/
|
|
73
|
+
__rsInstance?: VocalInstance | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export { }
|
package/dist/index.es.js
CHANGED
|
@@ -245,7 +245,7 @@ var s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
245
245
|
}
|
|
246
246
|
let r = c.current;
|
|
247
247
|
if (r) {
|
|
248
|
-
let i = r.search(e).filter((e) => e.score < t);
|
|
248
|
+
let i = r.search(e).filter((e) => (e.score ?? 1) < t);
|
|
249
249
|
if (i?.length) {
|
|
250
250
|
let t = i[0].item.toLowerCase();
|
|
251
251
|
return n[t]?.(e, t);
|
|
@@ -451,8 +451,16 @@ var s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
451
451
|
})] })
|
|
452
452
|
}), N = (e, t) => {
|
|
453
453
|
for (let n of e) for (let e of n) if (t(e.transcript ?? "") !== null) return;
|
|
454
|
-
}, P = ({ children: r, commands: o = null, lang: s = "en-US", grammars: c = null, timeout: l = 3e3, silenceTimeout: u = null, precision: d = .4, maxAlternatives: f = 1, continuous: p = !1, ariaLabel: m = "start recognition", style: h = null, className: g = null, outlineStyle: _ = "2px solid", onStart: v = null, onEnd: y = null, onSpeechStart: b = null, onSpeechEnd: x = null, onResult: S = null, onError: w = null, onNoMatch: k = null, signal: A = null, __rsInstance: P }) => {
|
|
455
|
-
let F = a(null), I = i(() => C(), []), [, { start: L, stop: R, subscribe: ee, unsubscribe: te, isRecording: z }] = E(s, c, f, p, P), B = O(o, d), V = a({
|
|
454
|
+
}, P = ({ children: r, commands: o = null, lang: s = "en-US", grammars: c = null, timeout: l = 3e3, silenceTimeout: u = null, precision: d = .4, maxAlternatives: f = 1, continuous: p = !1, ariaLabel: m = "start recognition", style: h = null, className: g = null, outlineStyle: _ = "2px solid", onStart: v = null, onEnd: y = null, onSpeechStart: b = null, onSpeechEnd: x = null, onResult: S = null, onError: w = null, onNoMatch: k = null, signal: A = null, __rsInstance: P = null }) => {
|
|
455
|
+
let F = a(null), I = i(() => C(), []), [, { start: L, stop: R, subscribe: ee, unsubscribe: te, isRecording: z }] = E(s, c, f, p, P), B = O(o, d), V = a({
|
|
456
|
+
onStart: null,
|
|
457
|
+
onEnd: null,
|
|
458
|
+
onSpeechStart: null,
|
|
459
|
+
onSpeechEnd: null,
|
|
460
|
+
onResult: null,
|
|
461
|
+
onError: null,
|
|
462
|
+
onNoMatch: null
|
|
463
|
+
});
|
|
456
464
|
V.current = {
|
|
457
465
|
onStart: v,
|
|
458
466
|
onEnd: y,
|
|
@@ -479,9 +487,9 @@ var s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
479
487
|
}, [K]), se = n((e) => {
|
|
480
488
|
q(), V.current.onSpeechStart?.(e);
|
|
481
489
|
}, [q]), ce = n((e) => {
|
|
482
|
-
K(), H.current && re.current > 0 && ae(), V.current.onSpeechEnd?.(e);
|
|
490
|
+
K(), H.current && (re.current ?? 0) > 0 && ae(), V.current.onSpeechEnd?.(e);
|
|
483
491
|
}, [K, ae]), le = n((e, t) => {
|
|
484
|
-
q(), H.current || (N(e
|
|
492
|
+
q(), H.current || (N(e.results === void 0 ? [] : Array.from(e.results, (e) => Array.from(e)), U.current), Y()), V.current.onResult?.(t, e);
|
|
485
493
|
}, [q, Y]), X = n((e) => {
|
|
486
494
|
Y(), V.current.onError?.(e);
|
|
487
495
|
}, [Y]), ue = n((e) => {
|
|
@@ -521,7 +529,7 @@ var s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
521
529
|
W.current = () => Object.entries(Q).forEach(([e, t]) => te?.(e, t));
|
|
522
530
|
let $ = n(() => {
|
|
523
531
|
try {
|
|
524
|
-
J(), Object.entries(Q).forEach(([e, t]) => ee(e, t)), L({ signal: A })?.catch?.(X);
|
|
532
|
+
J(), Object.entries(Q).forEach(([e, t]) => ee(e, t)), L({ signal: A ?? void 0 })?.catch?.(X);
|
|
525
533
|
} catch (e) {
|
|
526
534
|
X(e);
|
|
527
535
|
}
|
|
@@ -532,26 +540,26 @@ var s = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
532
540
|
J,
|
|
533
541
|
X,
|
|
534
542
|
A
|
|
535
|
-
]), de = () => {
|
|
536
|
-
!g && _ && (F.current.style.outline = _);
|
|
537
|
-
}, fe = () => {
|
|
538
|
-
!g && _ && (F.current.style.outline = "none");
|
|
539
|
-
};
|
|
543
|
+
]), de = n(() => {
|
|
544
|
+
!g && _ && F.current && (F.current.style.outline = _);
|
|
545
|
+
}, [g, _]), fe = n(() => {
|
|
546
|
+
!g && _ && F.current && (F.current.style.outline = "none");
|
|
547
|
+
}, [g, _]);
|
|
540
548
|
return I ? T(r) ? r($, Y, z) : t(r) ? e(r, { ...!z && { onClick: $ } }) : /* @__PURE__ */ (0, j.jsx)("button", {
|
|
541
549
|
"data-testid": "__vocal-root__",
|
|
542
550
|
ref: F,
|
|
543
551
|
"aria-label": m,
|
|
544
552
|
"aria-pressed": z,
|
|
545
|
-
style: g ?
|
|
553
|
+
style: g ? void 0 : {
|
|
546
554
|
width: 24,
|
|
547
555
|
height: 24,
|
|
548
556
|
backgroundColor: "transparent",
|
|
549
557
|
border: "none",
|
|
550
558
|
padding: 0,
|
|
551
559
|
cursor: !p && z ? "default" : "pointer",
|
|
552
|
-
...h
|
|
560
|
+
...h ?? {}
|
|
553
561
|
},
|
|
554
|
-
className: g,
|
|
562
|
+
className: g ?? void 0,
|
|
555
563
|
onFocus: de,
|
|
556
564
|
onBlur: fe,
|
|
557
565
|
onClick: z ? Y : $,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@untemps/react-vocal",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.15",
|
|
4
4
|
"author": "Vincent Le Badezet <v.lebadezet@untemps.net>",
|
|
5
5
|
"repository": "git@github.com:untemps/react-vocal.git",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,54 +21,71 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
|
24
|
-
"dist
|
|
25
|
-
"dist
|
|
24
|
+
"dist/*.cjs",
|
|
25
|
+
"dist/*.es.js",
|
|
26
|
+
"dist/*.d.ts",
|
|
26
27
|
"CHANGELOG.md"
|
|
27
28
|
],
|
|
28
29
|
"type": "module",
|
|
29
30
|
"main": "dist/index.cjs",
|
|
30
31
|
"module": "dist/index.es.js",
|
|
32
|
+
"types": "dist/index.d.ts",
|
|
31
33
|
"sideEffects": false,
|
|
32
34
|
"exports": {
|
|
33
35
|
".": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
34
37
|
"import": "./dist/index.es.js",
|
|
35
38
|
"require": "./dist/index.cjs",
|
|
36
39
|
"default": "./dist/index.es.js"
|
|
37
40
|
}
|
|
38
41
|
},
|
|
39
42
|
"engines": {
|
|
40
|
-
"node": "
|
|
43
|
+
"node": ">=22"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies": {
|
|
43
46
|
"@commitlint/cli": "^20.5.3",
|
|
44
|
-
"fuse.js": "^7.3.0",
|
|
45
47
|
"@commitlint/config-conventional": "^20.5.3",
|
|
48
|
+
"@eslint/js": "^10.0.1",
|
|
49
|
+
"@microsoft/api-extractor": "^7.58.7",
|
|
46
50
|
"@semantic-release/changelog": "^6.0.3",
|
|
47
51
|
"@semantic-release/git": "^10.0.1",
|
|
48
52
|
"@semantic-release/github": "^12.0.6",
|
|
49
53
|
"@testing-library/dom": "^10.4.1",
|
|
50
54
|
"@testing-library/jest-dom": "^6.9.1",
|
|
51
55
|
"@testing-library/react": "^16.3.2",
|
|
56
|
+
"@types/react": "^19.2.15",
|
|
57
|
+
"@types/react-dom": "^19.2.3",
|
|
52
58
|
"@untemps/utils": "^3.2.0",
|
|
53
59
|
"@vitejs/plugin-react": "^6.0.1",
|
|
54
60
|
"@vitest/coverage-v8": "^4.1.5",
|
|
61
|
+
"eslint": "^10.4.0",
|
|
62
|
+
"eslint-config-prettier": "^10.1.8",
|
|
63
|
+
"fuse.js": "^7.3.0",
|
|
64
|
+
"globals": "^17.6.0",
|
|
55
65
|
"husky": "^9.1.7",
|
|
56
66
|
"jsdom": "^29.1.1",
|
|
57
67
|
"prettier": "^3.8.3",
|
|
58
68
|
"react": "^19.2.5",
|
|
59
69
|
"react-dom": "^19.2.5",
|
|
60
70
|
"semantic-release": "^25.0.3",
|
|
71
|
+
"typescript": "^6.0.3",
|
|
72
|
+
"typescript-eslint": "^8.59.4",
|
|
61
73
|
"vite": "^8.0.10",
|
|
74
|
+
"vite-plugin-dts": "^5.0.1",
|
|
62
75
|
"vitest": "^4.1.5"
|
|
63
76
|
},
|
|
64
77
|
"peerDependencies": {
|
|
65
78
|
"fuse.js": ">=6.0.0",
|
|
66
79
|
"react": ">=16.13.1",
|
|
67
|
-
"react-dom": ">=16.13.1"
|
|
80
|
+
"react-dom": ">=16.13.1",
|
|
81
|
+
"typescript": ">=6.0.0"
|
|
68
82
|
},
|
|
69
83
|
"peerDependenciesMeta": {
|
|
70
84
|
"fuse.js": {
|
|
71
85
|
"optional": true
|
|
86
|
+
},
|
|
87
|
+
"typescript": {
|
|
88
|
+
"optional": true
|
|
72
89
|
}
|
|
73
90
|
},
|
|
74
91
|
"dependencies": {
|
|
@@ -109,6 +126,10 @@
|
|
|
109
126
|
{
|
|
110
127
|
"path": "dist/index.es.js",
|
|
111
128
|
"label": "ES distribution"
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"path": "dist/index.d.ts",
|
|
132
|
+
"label": "TypeScript declarations"
|
|
112
133
|
}
|
|
113
134
|
]
|
|
114
135
|
}
|
|
@@ -119,8 +140,10 @@
|
|
|
119
140
|
"dev": "cd dev && yarn && yarn dev",
|
|
120
141
|
"test": "vitest",
|
|
121
142
|
"test:ci": "vitest run --coverage",
|
|
143
|
+
"typecheck": "tsc --noEmit",
|
|
144
|
+
"lint": "eslint src vitest.setup.ts",
|
|
122
145
|
"build": "vite build",
|
|
123
146
|
"prepare": "husky",
|
|
124
|
-
"prettier": "prettier \"*/**/*.js\" --ignore-path ./.prettierignore --write && git add -u && git status"
|
|
147
|
+
"prettier": "prettier \"*/**/*.{js,ts,tsx}\" --ignore-path ./.prettierignore --write && git add -u && git status"
|
|
125
148
|
}
|
|
126
149
|
}
|