@untemps/react-vocal 1.7.30 → 1.7.31
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/.github/workflows/publish.yml +30 -0
- package/CHANGELOG.md +2 -0
- package/CLAUDE.md +55 -0
- package/jest/jest.setup.js +15 -5
- package/package.json +11 -7
- package/.github/workflows/index.yml +0 -23
- package/src/components/__tests__/__snapshots__/Icon.test.js.snap +0 -21
- package/src/components/__tests__/__snapshots__/Vocal.test.js.snap +0 -28
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: "Publish package"
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- main
|
|
6
|
+
- beta
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
id-token: write
|
|
10
|
+
pull-requests: write
|
|
11
|
+
issues: write
|
|
12
|
+
jobs:
|
|
13
|
+
release:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v6
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
- uses: actions/setup-node@v6
|
|
20
|
+
with:
|
|
21
|
+
node-version: '24'
|
|
22
|
+
- run: yarn install --frozen-lockfile
|
|
23
|
+
- run: yarn test:ci
|
|
24
|
+
- run: yarn build
|
|
25
|
+
- run: npx semantic-release
|
|
26
|
+
env:
|
|
27
|
+
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
28
|
+
- uses: codecov/codecov-action@v5
|
|
29
|
+
with:
|
|
30
|
+
files: coverage/lcov.info
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
## [1.7.31](https://github.com/untemps/react-vocal/compare/v1.7.30...v1.7.31) (2026-05-03)
|
|
2
|
+
|
|
1
3
|
## [1.7.30](https://github.com/untemps/react-vocal/compare/v1.7.29...v1.7.30) (2025-12-08)
|
|
2
4
|
|
|
3
5
|
## [1.7.29](https://github.com/untemps/react-vocal/compare/v1.7.28...v1.7.29) (2025-12-08)
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
yarn test # watch mode
|
|
9
|
+
yarn test:ci # CI mode with coverage (also runs in pre-commit hook)
|
|
10
|
+
yarn build # build CJS + ES + UMD to dist/
|
|
11
|
+
yarn dev # dev server at http://localhost:10001/ (separate dev/ package)
|
|
12
|
+
yarn prettier # format all JS files and stage changes
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Run a single test file:
|
|
16
|
+
```bash
|
|
17
|
+
yarn jest src/hooks/__tests__/useVocal.test.js
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Build formats are driven by `BABEL_ENV`: `cjs` → `dist/index.js`, `es` → `dist/index.es.js`, `umd` → `dist/index.umd.js`.
|
|
21
|
+
|
|
22
|
+
## Architecture
|
|
23
|
+
|
|
24
|
+
This is a React library wrapping the [Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API) via `@untemps/vocal` (the `SpeechRecognitionWrapper` class).
|
|
25
|
+
|
|
26
|
+
### Public API (`src/index.js`)
|
|
27
|
+
|
|
28
|
+
- **`Vocal`** (default export) — the component
|
|
29
|
+
- **`useVocal`** — named export, the hook
|
|
30
|
+
- **`isSupported`** — boolean re-exported from `@untemps/vocal`
|
|
31
|
+
|
|
32
|
+
### Hook layer (`src/hooks/`)
|
|
33
|
+
|
|
34
|
+
| Hook | Role |
|
|
35
|
+
|------|------|
|
|
36
|
+
| `useVocal` | Creates/manages a `SpeechRecognitionWrapper` instance in a ref. Returns `[ref, { start, stop, abort, subscribe, unsubscribe, clean }]`. Instance is re-created when `lang` or `grammars` change. |
|
|
37
|
+
| `useCommands` | Fuzzy-matches a speech result string against a `commands` map using **fuse.js** (default score threshold `0.4` — lower = stricter). Keys are lowercased. |
|
|
38
|
+
| `useTimeout` | Manages the recognition timeout: starts on `start` event, pauses on `speechstart`, restarts on `speechend`, fires `_onEnd` on expiry. |
|
|
39
|
+
|
|
40
|
+
### Component (`src/components/Vocal.js`)
|
|
41
|
+
|
|
42
|
+
Composes the three hooks above. Three render modes depending on `children`:
|
|
43
|
+
- **function** `(start, stop, isStarted) => element` — full control
|
|
44
|
+
- **React element** — receives `onClick` injected via `cloneElement`
|
|
45
|
+
- **no children** — renders the default `<Icon>` button
|
|
46
|
+
|
|
47
|
+
The `__rsInstance` prop (undocumented) injects a custom `SpeechRecognitionWrapper` instance, used exclusively in tests.
|
|
48
|
+
|
|
49
|
+
### Testing
|
|
50
|
+
|
|
51
|
+
`jest/jest.setup.js` globally mocks `SpeechRecognition`, `Permissions`, `MediaDevices`, and `SpeechGrammarList`. The mock exposes a custom `say(sentence)` method that fires the full `speechstart → result/nomatch → speechend` event sequence synchronously — use it to simulate recognition in tests.
|
|
52
|
+
|
|
53
|
+
## Commit convention
|
|
54
|
+
|
|
55
|
+
Angular Conventional Commits (`feat`, `fix`, `chore`, `docs`, etc.). Enforced by commitlint on `commit-msg` hook.
|
package/jest/jest.setup.js
CHANGED
|
@@ -3,9 +3,11 @@ import { toBeInTheDocument, toHaveAttribute, toHaveStyle } from '@testing-librar
|
|
|
3
3
|
|
|
4
4
|
expect.extend({ toBeInTheDocument, toHaveAttribute, toHaveStyle })
|
|
5
5
|
|
|
6
|
-
global
|
|
7
|
-
userAgent: 'node.js',
|
|
8
|
-
|
|
6
|
+
Object.defineProperty(global, 'navigator', {
|
|
7
|
+
value: { userAgent: 'node.js' },
|
|
8
|
+
writable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
})
|
|
9
11
|
global.PermissionStatus = jest.fn(() => ({
|
|
10
12
|
state: 'granted',
|
|
11
13
|
addEventListener: jest.fn(),
|
|
@@ -14,11 +16,19 @@ const status = new PermissionStatus()
|
|
|
14
16
|
global.Permissions = jest.fn(() => ({
|
|
15
17
|
query: jest.fn().mockResolvedValue(status),
|
|
16
18
|
}))
|
|
17
|
-
global.navigator
|
|
19
|
+
Object.defineProperty(global.navigator, 'permissions', {
|
|
20
|
+
value: new Permissions(),
|
|
21
|
+
writable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
})
|
|
18
24
|
global.MediaDevices = jest.fn(() => ({
|
|
19
25
|
getUserMedia: jest.fn().mockResolvedValue('foo'),
|
|
20
26
|
}))
|
|
21
|
-
global.navigator
|
|
27
|
+
Object.defineProperty(global.navigator, 'mediaDevices', {
|
|
28
|
+
value: new MediaDevices(),
|
|
29
|
+
writable: true,
|
|
30
|
+
configurable: true,
|
|
31
|
+
})
|
|
22
32
|
global.SpeechGrammarList = jest.fn(() => ({
|
|
23
33
|
length: 0,
|
|
24
34
|
}))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@untemps/react-vocal",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.31",
|
|
4
4
|
"author": "Vincent Le Badezet <v.lebadezet@untemps.net>",
|
|
5
5
|
"repository": "git@github.com:untemps/react-vocal.git",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"main": "dist/index.js",
|
|
24
24
|
"module": "dist/index.es.js",
|
|
25
25
|
"engines": {
|
|
26
|
-
"node": ">=
|
|
26
|
+
"node": ">=18.0.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@babel/cli": "^7.12.10",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"@rollup/plugin-babel": "^5.2.2",
|
|
39
39
|
"@rollup/plugin-commonjs": "^17.0.0",
|
|
40
40
|
"@rollup/plugin-node-resolve": "^11.0.1",
|
|
41
|
-
"@semantic-release/changelog": "^6.0.
|
|
41
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
42
42
|
"@semantic-release/git": "^10.0.1",
|
|
43
|
-
"@semantic-release/github": "^
|
|
43
|
+
"@semantic-release/github": "^12.0.6",
|
|
44
44
|
"@testing-library/dom": "^7.29.0",
|
|
45
45
|
"@testing-library/jest-dom": "^5.11.6",
|
|
46
46
|
"@testing-library/react": "^11.2.2",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"rollup": "^2.35.1",
|
|
61
61
|
"rollup-plugin-sizes": "^1.0.4",
|
|
62
62
|
"rollup-plugin-terser": "^7.0.2",
|
|
63
|
-
"rollup-plugin-visualizer": "^
|
|
64
|
-
"semantic-release": "^
|
|
63
|
+
"rollup-plugin-visualizer": "^5.14.0",
|
|
64
|
+
"semantic-release": "^25.0.3"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
67
|
"react": "^16.13.1",
|
|
@@ -87,7 +87,11 @@
|
|
|
87
87
|
},
|
|
88
88
|
"release": {
|
|
89
89
|
"branches": [
|
|
90
|
-
"main"
|
|
90
|
+
"main",
|
|
91
|
+
{
|
|
92
|
+
"name": "beta",
|
|
93
|
+
"prerelease": true
|
|
94
|
+
}
|
|
91
95
|
],
|
|
92
96
|
"plugins": [
|
|
93
97
|
[
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
name: "deploy"
|
|
2
|
-
on:
|
|
3
|
-
push:
|
|
4
|
-
branches:
|
|
5
|
-
- main
|
|
6
|
-
jobs:
|
|
7
|
-
release:
|
|
8
|
-
runs-on: ubuntu-latest
|
|
9
|
-
steps:
|
|
10
|
-
- uses: actions/checkout@v2
|
|
11
|
-
- uses: actions/setup-node@v1
|
|
12
|
-
with:
|
|
13
|
-
node-version: '14'
|
|
14
|
-
- run: yarn install
|
|
15
|
-
- run: yarn test:ci
|
|
16
|
-
- run: yarn build
|
|
17
|
-
- run: npx semantic-release
|
|
18
|
-
env:
|
|
19
|
-
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
|
|
20
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
21
|
-
- uses: codecov/codecov-action@v1
|
|
22
|
-
with:
|
|
23
|
-
file: coverage/lcov.info
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`Icon matches snapshot 1`] = `
|
|
4
|
-
<DocumentFragment>
|
|
5
|
-
<svg
|
|
6
|
-
data-testid="__icon-root__"
|
|
7
|
-
height="100%"
|
|
8
|
-
viewBox="0 0 24 24"
|
|
9
|
-
width="100%"
|
|
10
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
11
|
-
>
|
|
12
|
-
<g>
|
|
13
|
-
<path
|
|
14
|
-
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"
|
|
15
|
-
data-testid="__icon-path__"
|
|
16
|
-
fill="black"
|
|
17
|
-
/>
|
|
18
|
-
</g>
|
|
19
|
-
</svg>
|
|
20
|
-
</DocumentFragment>
|
|
21
|
-
`;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`Vocal matches snapshot 1`] = `
|
|
4
|
-
<DocumentFragment>
|
|
5
|
-
<button
|
|
6
|
-
aria-label="start recognition"
|
|
7
|
-
data-testid="__vocal-root__"
|
|
8
|
-
role="button"
|
|
9
|
-
style="width: 24px; height: 24px; background: none; padding: 0px; cursor: pointer;"
|
|
10
|
-
>
|
|
11
|
-
<svg
|
|
12
|
-
data-testid="__icon-root__"
|
|
13
|
-
height="100%"
|
|
14
|
-
viewBox="0 0 24 24"
|
|
15
|
-
width="100%"
|
|
16
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
17
|
-
>
|
|
18
|
-
<g>
|
|
19
|
-
<path
|
|
20
|
-
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"
|
|
21
|
-
data-testid="__icon-path__"
|
|
22
|
-
fill="black"
|
|
23
|
-
/>
|
|
24
|
-
</g>
|
|
25
|
-
</svg>
|
|
26
|
-
</button>
|
|
27
|
-
</DocumentFragment>
|
|
28
|
-
`;
|