@untemps/react-vocal 2.0.0-beta.4 → 2.0.0-beta.6

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 CHANGED
@@ -1,3 +1,22 @@
1
+ # [2.0.0-beta.6](https://github.com/untemps/react-vocal/compare/v2.0.0-beta.5...v2.0.0-beta.6) (2026-05-12)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add continuous session support ([#118](https://github.com/untemps/react-vocal/issues/118)) ([690ba61](https://github.com/untemps/react-vocal/commit/690ba617746aa28499d7ea2d48751453a652ff5e))
7
+
8
+ # [2.0.0-beta.5](https://github.com/untemps/react-vocal/compare/v2.0.0-beta.4...v2.0.0-beta.5) (2026-05-11)
9
+
10
+
11
+ ### Features
12
+
13
+ * Make fuse.js an optional peer dependency ([#117](https://github.com/untemps/react-vocal/issues/117)) ([a1c2a33](https://github.com/untemps/react-vocal/commit/a1c2a337f8d4ba4729c81f0a9b8664bcf914755f))
14
+
15
+
16
+ ### BREAKING CHANGES
17
+
18
+ * fuse.js must now be installed separately to enable fuzzy matching for phrase commands.
19
+
1
20
  # [2.0.0-beta.4](https://github.com/untemps/react-vocal/compare/v2.0.0-beta.3...v2.0.0-beta.4) (2026-05-10)
2
21
 
3
22
 
package/README.md CHANGED
@@ -46,6 +46,14 @@ Although the lack of `SpeechGrammar` and `SpeechGrammarList` is handled by the u
46
46
  yarn add @untemps/react-vocal
47
47
  ```
48
48
 
49
+ Fuzzy matching for phrase commands requires [fuse.js](https://fusejs.io/) as an optional peer dependency:
50
+
51
+ ```bash
52
+ yarn add fuse.js
53
+ ```
54
+
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
+
49
57
  ## Usage
50
58
 
51
59
  ### `Vocal` component
@@ -190,7 +198,11 @@ const commands = {
190
198
  }
191
199
  ```
192
200
 
193
- The component utilizes a special hook called `useCommands` to respond to the commands.
201
+ The component utilizes a special hook called `useCommands` to respond to the commands.
202
+ The hook performs a fuzzy search to match approximate commands if needed. This allows to fix accidental typos or approximate recognition results.
203
+ To do so the hook uses [fuse.js](https://fusejs.io/) which implements an algorithm to find strings that are approximately equal to a given input. The score precision that distinguishes acceptable command-to-callback mapping from negative matching can be customized in the hook instantiation.
204
+
205
+ fuse.js is an optional peer dependency — install it separately to enable fuzzy matching (see [Installation](#installation)). Without it, phrase commands fall back to case-insensitive exact matching.
194
206
 
195
207
  **Single-word command keys** (e.g. `rouge`, `submit`) use exact case-insensitive lookup. When the recognition returns a multi-word transcript, each word is tried individually so a command fires even when embedded in a phrase (e.g. _"je veux du rouge"_ triggers `rouge`).
196
208
 
@@ -212,6 +224,8 @@ The component utilizes a special hook called `useCommands` to respond to the com
212
224
  | timeout | number | 3000 | Time in ms to wait before discarding the recognition |
213
225
  | precision | number | 0.4 | Fuse.js score threshold for **phrase** command keys only (lower = stricter). Single-word commands always use exact lookup. |
214
226
  | maxAlternatives | number | 1 | Maximum number of recognition alternatives per segment. Setting this to 3–5 lets the engine surface the correct word as a secondary transcript, which is useful for handling homophones (e.g. _vert_ / _verre_ in French). |
227
+ | continuous | boolean | false | Keep the recognition session open after each result. The session accumulates transcript across segments and stops when the button is clicked again or `silenceTimeout` expires. Commands are not evaluated in continuous mode. |
228
+ | silenceTimeout | number | null | When `continuous` is true, automatically stop the session after this many ms of inactivity following the last recognized result. `null` or `0` disables auto-stop (button click required). |
215
229
  | style | object | null | Styles of the root element if className is not specified |
216
230
  | className | string | null | Class of the root element |
217
231
  | ariaLabel | string | 'start recognition' | Accessible label for the default button |
@@ -286,7 +300,7 @@ const App = () => {
286
300
  #### Signature
287
301
 
288
302
  ```
289
- useVocal(lang, grammars, maxAlternatives)
303
+ useVocal(lang, grammars, maxAlternatives, continuous)
290
304
  ```
291
305
 
292
306
  | Args | Type | Default | Description |
@@ -294,6 +308,7 @@ useVocal(lang, grammars, maxAlternatives)
294
308
  | lang | string | 'en-US' | Language understood by the recognition [BCP 47 language tag](https://tools.ietf.org/html/bcp47) |
295
309
  | grammars | SpeechGrammarList | null | Grammars understood by the recognition [JSpeech Grammar Format](https://www.w3.org/TR/jsgf/) |
296
310
  | maxAlternatives | number | 1 | Maximum number of recognition alternatives per segment |
311
+ | continuous | boolean | false | Keep the recognition session open after each result |
297
312
 
298
313
  ---
299
314
 
package/dev/src/index.jsx CHANGED
@@ -13,6 +13,7 @@ const COMMANDS = {
13
13
  const App = () => {
14
14
  const [logs, setLogs] = useState('')
15
15
  const [borderColor, setBorderColor] = useState()
16
+ const [continuous, setContinuous] = useState(false)
16
17
 
17
18
  const _log = (value) => setLogs((prev) => `${prev}${prev.length > 0 ? '\n' : ''} ----- ${value}`)
18
19
 
@@ -22,8 +23,8 @@ const App = () => {
22
23
  Object.fromEntries(
23
24
  Object.entries(COMMANDS).map(([key, color]) => [
24
25
  key,
25
- (input) => {
26
- _log(`command matched: "${input}" → ${color}`)
26
+ (rawInput, commandKey) => {
27
+ _log(`command matched: "${commandKey}" → ${color}`)
27
28
  setBorderColor(color)
28
29
  },
29
30
  ])
@@ -37,12 +38,19 @@ const App = () => {
37
38
  <Vocal
38
39
  lang="fr"
39
40
  commands={commands}
41
+ continuous={continuous}
40
42
  onStart={() => _log('start')}
41
43
  onEnd={() => _log('end')}
42
- onResult={(result) => _log(`result: "${result}"`)}
44
+ onResult={(result) => _log(`transcript: "${result}"`)}
43
45
  onError={(e) => _log(`error: ${e.message}`)}
44
46
  maxAlternatives={3}
45
47
  />
48
+ <p style={{ fontSize: 12, color: '#666', margin: '8px 0' }}>
49
+ <label style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
50
+ <input type="checkbox" checked={continuous} onChange={(e) => setContinuous(e.target.checked)} />
51
+ Mode continu
52
+ </label>
53
+ </p>
46
54
  <p style={{ fontSize: 12, color: '#666', margin: '8px 0' }}>
47
55
  Commandes :{' '}
48
56
  {Object.keys(COMMANDS).map((k, i) => (